diff --git a/lustre/include/linux/lustre_fsfilt.h b/lustre/include/linux/lustre_fsfilt.h index 988f8e62aae208c9d07ceeaeeaa7a6dff23a154f..978fbe4a4974b0fb9bff4e64dbd11d7062a3ca61 100644 --- a/lustre/include/linux/lustre_fsfilt.h +++ b/lustre/include/linux/lustre_fsfilt.h @@ -109,8 +109,10 @@ struct fsfilt_operations { int (* fs_init_extents_ea)(struct inode *inode); int (* fs_insert_extents_ea)(struct inode *inode, unsigned long from, unsigned long num); + int (* fs_do_write_cow)(struct dentry *dentry, void *extents, int nexts); int (* fs_write_extents)(struct dentry *dentry, unsigned long offset, unsigned long blks); + int (* fs_get_fs_flags)(struct dentry *dentry); int (* fs_remove_extents_ea)(struct inode *inode, unsigned long from, unsigned long num); int (* fs_get_ino_write_extents)(struct super_block *sb, ino_t ino, @@ -493,6 +495,13 @@ static inline int fsfilt_map_inode_pages(struct obd_device *obd, return obd->obd_fsops->fs_map_inode_pages(inode, page, pages, blocks, created, create, sem); } +static inline int fsfilt_get_fs_flags(struct obd_device *obd, + struct dentry *dentry) +{ + if (obd->obd_fsops->fs_get_fs_flags) + return obd->obd_fsops->fs_get_fs_flags(dentry); + return 0; +} static inline int fsfilt_write_extents(struct obd_device *obd, struct dentry *dentry, @@ -503,7 +512,15 @@ fsfilt_write_extents(struct obd_device *obd, struct dentry *dentry, offset, blks); return 0; } - +static inline int +fsfilt_do_write_cow(struct obd_device *obd, struct dentry *dentry, + void *extents, int num_extents) +{ + if (obd->obd_fsops->fs_do_write_cow) + return obd->obd_fsops->fs_do_write_cow(dentry, extents, + num_extents); + return 0; +} static inline int fs_prep_san_write(struct obd_device *obd, struct inode *inode, long *blocks, int nblocks, loff_t newsize) diff --git a/lustre/include/linux/lustre_smfs.h b/lustre/include/linux/lustre_smfs.h index 5bdea663fbf69e3df4185f28e2c8946046d1d6d7..7bb62cb4bdae7778e2997e3488b7016b017f1c72 100644 --- a/lustre/include/linux/lustre_smfs.h +++ b/lustre/include/linux/lustre_smfs.h @@ -30,7 +30,6 @@ struct snap_inode_info { int sn_flags; /* the flags indicated inode type */ int sn_gen; /*the inode generation*/ }; - struct smfs_inode_info { struct inode *smi_inode; __u32 smi_flags; @@ -463,7 +462,6 @@ extern int smfs_rec_md(struct inode *inode, void * lmm, int lmm_size); extern int smfs_rec_unpack(struct smfs_proc_args *args, char *record, char **pbuf, int *opcode); -int smfs_cow(struct inode *dir, struct dentry *dentry, int op); extern int smfs_post_setup(struct super_block *sb, struct vfsmount *mnt); extern int smfs_post_cleanup(struct super_block *sb); diff --git a/lustre/include/linux/lustre_snap.h b/lustre/include/linux/lustre_snap.h index 38531f683538d36cf5e3898e42c76a2a1d93b768..cd8e9c64f445c07c1d070cce1017cbea5a22d5b5 100644 --- a/lustre/include/linux/lustre_snap.h +++ b/lustre/include/linux/lustre_snap.h @@ -145,6 +145,7 @@ struct snap_ea{ #define SNAPTABLE_MAGIC 0x19760218 #define SNAPTABLE_INFO "snaptable" #define SNAP_GENERATION "snap_generation" + struct snap { time_t sn_time; unsigned int sn_index; @@ -172,4 +173,13 @@ struct snap_info { extern int smfs_add_snap_item(struct super_block *sb, char *name); extern int smfs_start_cow(struct super_block *sb); extern int smfs_stop_cow(struct super_block *sb); + +struct write_extents { + size_t w_count; + loff_t w_pos; +}; +int smfs_cow(struct inode *dir, struct dentry *dentry, + void *data1, void *data2, int op); +int smfs_cow_write(struct inode *inode, struct dentry *dentry, void *data1, + void *data2); #endif /*_LUSTRE_SNAP_H*/ diff --git a/lustre/include/linux/obd.h b/lustre/include/linux/obd.h index 75bd3d44a3a21de9c8bf968dda85e8d51aafb15a..3f1bd99843c8dbff78c7dbb5301d0948369cb8f3 100644 --- a/lustre/include/linux/obd.h +++ b/lustre/include/linux/obd.h @@ -709,8 +709,11 @@ struct obd_ops { int objcount, struct obd_ioobj *obj, int niocount, struct niobuf_local *local, struct obd_trans_info *oti, int rc); + int (*o_do_cow)(struct obd_export *exp, struct obd_ioobj *obj, + int objcount, struct niobuf_remote *rnb); int (*o_write_extents)(struct obd_export *exp, struct obd_ioobj *obj, - int niocount, struct niobuf_local *local,int rc); + int objcount, int niocount, + struct niobuf_local *local,int rc); int (*o_enqueue)(struct obd_export *, struct lov_stripe_md *, __u32 type, ldlm_policy_data_t *, __u32 mode, int *flags, void *bl_cb, void *cp_cb, void *gl_cb, diff --git a/lustre/include/linux/obd_class.h b/lustre/include/linux/obd_class.h index 4af2936c9f00b8ac9ef55dcd20a65d2911bdb0f6..85edc8c23b30d1047c84cc9ce023e18c2e94b702 100644 --- a/lustre/include/linux/obd_class.h +++ b/lustre/include/linux/obd_class.h @@ -902,8 +902,28 @@ static inline int obd_commitrw(int cmd, struct obd_export *exp, struct obdo *oa, RETURN(rc); } -static inline int obd_write_extents(struct obd_export *exp, struct obd_ioobj *obj, - int niocount, struct niobuf_local *local, int rc) +static inline int obd_do_cow(struct obd_export *exp, struct obd_ioobj *obj, + int objcount,struct niobuf_remote *rnb) +{ + int rc; + ENTRY; + + /* there are cases when write_extents is not implemented. */ + if (!OBP(exp->exp_obd, do_cow)) + RETURN(0); + + OBD_COUNTER_INCREMENT(exp->exp_obd, do_cow); + + rc = OBP(exp->exp_obd, do_cow)(exp, obj, objcount, rnb); + + RETURN(rc); +} + +static inline int obd_write_extents(struct obd_export *exp, + struct obd_ioobj *obj, + int objcount, int niocount, + struct niobuf_local *local, + int rc) { ENTRY; @@ -913,7 +933,8 @@ static inline int obd_write_extents(struct obd_export *exp, struct obd_ioobj *ob OBD_COUNTER_INCREMENT(exp->exp_obd, write_extents); - rc = OBP(exp->exp_obd, write_extents)(exp, obj, niocount, local, rc); + rc = OBP(exp->exp_obd, write_extents)(exp, obj, objcount, niocount, + local, rc); RETURN(rc); } diff --git a/lustre/lvfs/fsfilt_smfs.c b/lustre/lvfs/fsfilt_smfs.c index eefd536d0750b3c64d722d26fe59008ad5405bab..2624159f77a52cdb8270af47f97b55eb832ee0d9 100644 --- a/lustre/lvfs/fsfilt_smfs.c +++ b/lustre/lvfs/fsfilt_smfs.c @@ -592,7 +592,7 @@ static int fsfilt_smfs_post_setup(struct obd_device *obd, struct vfsmount *mnt) smfs_post_setup(sb, mnt); if (SMFS_DO_REC(S2SMI(sb))) rc = smfs_start_rec(sb, mnt); -#ifdef CONFIG_SNAPFS +#if CONFIG_SNAPFS if (SMFS_DO_COW(S2SMI(sb))) rc = smfs_start_cow(sb); #endif @@ -614,12 +614,13 @@ static int fsfilt_smfs_post_cleanup(struct obd_device *obd, { struct super_block *sb = NULL; int rc = 0; - + ENTRY; + if (mnt) { sb = mnt->mnt_sb; if (SMFS_DO_REC(S2SMI(sb))) rc = smfs_stop_rec(sb); -#ifdef CONFIG_SNAPFS +#if CONFIG_SNAPFS if (SMFS_DO_COW(S2SMI(sb))) rc = smfs_stop_cow(sb); #endif @@ -631,6 +632,8 @@ static int fsfilt_smfs_post_cleanup(struct obd_device *obd, static int fsfilt_smfs_set_fs_flags(struct inode *inode, int flags) { int rc = 0; + ENTRY; + if (SMFS_DO_REC(S2SMI(inode->i_sb)) && (flags & SM_DO_REC)) SMFS_SET_INODE_REC(inode); if (SMFS_DO_COW(S2SMI(inode->i_sb)) && (flags & SM_DO_COW)) @@ -641,6 +644,8 @@ static int fsfilt_smfs_set_fs_flags(struct inode *inode, int flags) static int fsfilt_smfs_clear_fs_flags(struct inode *inode, int flags) { int rc = 0; + ENTRY; + if (SMFS_DO_REC(S2SMI(inode->i_sb)) && (flags & SM_DO_REC)) SMFS_CLEAN_INODE_REC(inode); if (SMFS_DO_COW(S2SMI(inode->i_sb)) && (flags & SM_DO_COW)) @@ -648,6 +653,21 @@ static int fsfilt_smfs_clear_fs_flags(struct inode *inode, int flags) RETURN(rc); } +static int fsfilt_smfs_get_fs_flags(struct dentry *de) +{ + struct inode *inode = de->d_inode; + int flags = 0; + ENTRY; + + LASSERT(inode); + + if (SMFS_DO_REC(S2SMI(inode->i_sb)) && SMFS_DO_INODE_REC(inode)) + flags |= SM_DO_REC; + if (SMFS_DO_COW(S2SMI(inode->i_sb)) && SMFS_DO_INODE_COW(inode)) + flags |= SM_DO_COW; + + RETURN(flags); +} static int fsfilt_smfs_set_ost_flags(struct super_block *sb) { int rc = 0; @@ -928,7 +948,25 @@ static int fsfilt_smfs_set_snap_item(struct super_block *sb, char *name) #endif RETURN(rc); } - +static int fsfilt_smfs_do_write_cow(struct dentry *de, void *extents, + int num_extents) +{ + int rc = 0; +#if CONFIG_SNAPFS + struct write_extents *w_ext = (struct write_extents *)extents; + int i = 0; + ENTRY; + for (i = 0; i < num_extents; i++) { + size_t count = w_ext->w_count; + loff_t off = w_ext->w_pos; + rc = smfs_cow_write(de->d_inode, de, &count, &off); + if (rc) + RETURN(rc); + w_ext ++; + } +#endif + RETURN(rc); +} static struct fsfilt_operations fsfilt_smfs_ops = { .fs_type = "smfs", .fs_owner = THIS_MODULE, @@ -955,6 +993,7 @@ static struct fsfilt_operations fsfilt_smfs_ops = { .fs_post_cleanup = fsfilt_smfs_post_cleanup, .fs_set_fs_flags = fsfilt_smfs_set_fs_flags, .fs_clear_fs_flags = fsfilt_smfs_clear_fs_flags, + .fs_get_fs_flags = fsfilt_smfs_get_fs_flags, .fs_set_ost_flags = fsfilt_smfs_set_ost_flags, .fs_set_mds_flags = fsfilt_smfs_set_mds_flags, .fs_precreate_rec = fsfilt_smfs_precreate_rec, @@ -969,7 +1008,7 @@ static struct fsfilt_operations fsfilt_smfs_ops = { .fs_free_write_extents = fsfilt_smfs_free_extents, .fs_write_extents = fsfilt_smfs_write_extents, .fs_set_snap_item = fsfilt_smfs_set_snap_item, - + .fs_do_write_cow = fsfilt_smfs_do_write_cow, /* FIXME-UMKA: probably fsfilt_smfs_get_op_len() should be * put here too. */ }; diff --git a/lustre/lvfs/fsfilt_snap_ext3.c b/lustre/lvfs/fsfilt_snap_ext3.c index 885bae732869a395160b1c0d815e1b75f1ad4626..c538dc486b679cbf52434fd9ef02120d585eb1cd 100644 --- a/lustre/lvfs/fsfilt_snap_ext3.c +++ b/lustre/lvfs/fsfilt_snap_ext3.c @@ -324,42 +324,74 @@ static void ext3_copy_meta(handle_t *handle, struct inode *dst, struct inode *sr } } } -/* fsfilt_ext3_copy_block - copy one data block from inode @src to @dst. - No lock here. User should do the lock. - User should check the return value to see if the result is correct. - Return value: - 1: The block has been copied successfully - 0: No block is copied, usually this is because src has no such blk - -1: Error -*/ +static int ext3_copy_reg_block(struct inode *dst, struct inode *src, int blk) +{ + struct page *src_page, *dst_page; + loff_t offset = blk << src->i_sb->s_blocksize_bits; + unsigned long index = offset >> PAGE_CACHE_SHIFT; + int rc = 0; + ENTRY; + + /*read the src page*/ + src_page = grab_cache_page(src->i_mapping, index); + if (src_page == NULL) + RETURN(-ENOMEM); + + if (!PageUptodate(src_page)) { + rc = src->i_mapping->a_ops->readpage(NULL, src_page); + if (rc < 0) { + page_cache_release(src_page); + RETURN(rc); + } + } + kmap(src_page); + /*get dst page*/ + + dst_page = grab_cache_page(dst->i_mapping, index); + if (dst_page == NULL) + GOTO(src_page_unlock, rc = -ENOMEM); + kmap(dst_page); + + /*FIXME: should use mapping ops or block_prepare_write to prepare the block*/ + rc = block_prepare_write(dst_page, 0, PAGE_CACHE_SIZE, ext3_get_block); + if (rc) { + CERROR("inode %lu, prepare write rc=%d \n", dst->i_ino, rc); + GOTO(dst_page_unlock, rc); + } -static int fsfilt_ext3_copy_block (struct inode *dst, struct inode *src, int blk) + memcpy(page_address(dst_page), page_address(src_page), PAGE_CACHE_SIZE); + + generic_commit_write(NULL, dst_page, 0, PAGE_CACHE_SIZE); + +dst_page_unlock: + kunmap(dst_page); + UnlockPage(dst_page); + page_cache_release(dst_page); +src_page_unlock: + kunmap(src_page); + page_cache_release(src_page); + + RETURN(rc); +} +static int ext3_copy_dir_block(struct inode *dst, struct inode *src, int blk) { struct buffer_head *bh_dst = NULL, *bh_src = NULL; - int err = 0; + int rc = 0; handle_t *handle = NULL; ENTRY; - CDEBUG(D_INODE, "copy blk %d from %lu to %lu \n", blk, src->i_ino, - dst->i_ino); - /* - * ext3_getblk() require handle!=NULL - */ - if (S_ISREG(src->i_mode)) - RETURN(0); - handle = ext3_journal_start(dst, SNAP_COPYBLOCK_TRANS_BLOCKS); if( !handle ) RETURN(-EINVAL); - bh_src = ext3_bread(handle, src, blk, 0, &err); + bh_src = ext3_bread(handle, src, blk, 0, &rc); if (!bh_src) { - CERROR("error for src blk %d, error %d\n", blk, err); - GOTO(exit_relese, err); + CERROR("rcor for src blk %d, rcor %d\n", blk, rc); + GOTO(exit_relese, rc); } - bh_dst = ext3_getblk(handle, dst, blk, 1, &err); + bh_dst = ext3_getblk(handle, dst, blk, 1, &rc); if (!bh_dst) { - CERROR("error for dst blk %d, error %d\n", blk, err); - GOTO(exit_relese, err); + CERROR("rcor for dst blk %d, rcor %d\n", blk, rc); + GOTO(exit_relese, rc); } CDEBUG(D_INODE, "copy block %lu to %lu (%ld bytes)\n", bh_src->b_blocknr, bh_dst->b_blocknr, src->i_sb->s_blocksize); @@ -367,14 +399,40 @@ static int fsfilt_ext3_copy_block (struct inode *dst, struct inode *src, int blk ext3_journal_get_write_access(handle, bh_dst); memcpy(bh_dst->b_data, bh_src->b_data, src->i_sb->s_blocksize); ext3_journal_dirty_metadata(handle, bh_dst); - err = 1; + rc = 1; exit_relese: if (bh_src) brelse(bh_src); if (bh_dst) brelse(bh_dst); if (handle) ext3_journal_stop(handle, dst); - RETURN(err); + RETURN(rc); +} +/* fsfilt_ext3_copy_block - copy one data block from inode @src to @dst. + No lock here. User should do the lock. + User should check the return value to see if the result is correct. + Return value: + 1: The block has been copied successfully + 0: No block is copied, usually this is because src has no such blk + -1: Error +*/ + +static int fsfilt_ext3_copy_block (struct inode *dst, struct inode *src, int blk) +{ + int rc = 0; + ENTRY; + CDEBUG(D_INODE, "copy blk %d from %lu to %lu \n", blk, src->i_ino, + dst->i_ino); + /* + * ext3_getblk() require handle!=NULL + */ + if (S_ISREG(src->i_mode)) { + rc = ext3_copy_reg_block(dst, src, blk); + } else { + rc = ext3_copy_dir_block(dst, src, blk); + } + + RETURN(rc); } static inline int ext3_has_ea(struct inode *inode) diff --git a/lustre/obdclass/lprocfs_status.c b/lustre/obdclass/lprocfs_status.c index 7879648665998b53f110ef2f52d48d51df31b4b2..6614c53008f8e1dc5b1848e00948c5fcaf12cd1d 100644 --- a/lustre/obdclass/lprocfs_status.c +++ b/lustre/obdclass/lprocfs_status.c @@ -640,6 +640,7 @@ int lprocfs_alloc_obd_stats(struct obd_device *obd, unsigned num_private_stats) LPROCFS_OBD_OP_INIT(num_private_stats, stats, iterate); LPROCFS_OBD_OP_INIT(num_private_stats, stats, preprw); LPROCFS_OBD_OP_INIT(num_private_stats, stats, commitrw); + LPROCFS_OBD_OP_INIT(num_private_stats, stats, do_cow); LPROCFS_OBD_OP_INIT(num_private_stats, stats, write_extents); LPROCFS_OBD_OP_INIT(num_private_stats, stats, enqueue); LPROCFS_OBD_OP_INIT(num_private_stats, stats, match); diff --git a/lustre/obdfilter/filter.c b/lustre/obdfilter/filter.c index 81bcd9ba5c017b6468ef29b5d9398276d3a67abe..7adb22d5897c1c2ae063141cca2358c607c669c9 100644 --- a/lustre/obdfilter/filter.c +++ b/lustre/obdfilter/filter.c @@ -2136,7 +2136,7 @@ static int filter_precreate(struct obd_device *obd, struct obdo *oa, /*only do precreate rec record. so clean kml flags here*/ fsfilt_clear_fs_flags(obd, dparent->d_inode, - SM_DO_REC | SM_DO_COW); + SM_DO_REC); dchild = filter_fid2dentry(obd, dparent, group, next_id); if (IS_ERR(dchild)) @@ -2183,7 +2183,7 @@ static int filter_precreate(struct obd_device *obd, struct obdo *oa, CERROR("unable to write lastobjid " "but file created\n"); } - fsfilt_set_fs_flags(obd, dparent->d_inode, SM_DO_REC | SM_DO_COW); + fsfilt_set_fs_flags(obd, dparent->d_inode, SM_DO_REC); cleanup: switch(cleanup_phase) { @@ -2736,6 +2736,13 @@ int filter_iocontrol(unsigned int cmd, struct obd_export *exp, RETURN(rc); } + case OBD_IOC_SNAP_ADD: { + char *name = data->ioc_inlbuf1; + if (name) { + rc = fsfilt_set_snap_item(obd, obd->u.filter.fo_sb, name); + } + RETURN(rc); + } case OBD_IOC_LLOG_CANCEL: case OBD_IOC_LLOG_REMOVE: case OBD_IOC_LLOG_INFO: @@ -2863,6 +2870,7 @@ static struct obd_ops filter_obd_ops = { .o_sync = filter_sync, .o_preprw = filter_preprw, .o_commitrw = filter_commitrw, + .o_do_cow = filter_do_cow, .o_write_extents = filter_write_extents, .o_destroy_export = filter_destroy_export, .o_llog_init = filter_llog_init, @@ -2893,6 +2901,7 @@ static struct obd_ops filter_sanobd_ops = { .o_sync = filter_sync, .o_preprw = filter_preprw, .o_commitrw = filter_commitrw, + .o_do_cow = filter_do_cow, .o_write_extents = filter_write_extents, .o_san_preprw = filter_san_preprw, .o_destroy_export = filter_destroy_export, diff --git a/lustre/obdfilter/filter_internal.h b/lustre/obdfilter/filter_internal.h index e974b3defd86683e1e5c23b2d828f0b3012abe54..0ad0e3eb536f5bec80e7f0cd69678f58593cea9f 100644 --- a/lustre/obdfilter/filter_internal.h +++ b/lustre/obdfilter/filter_internal.h @@ -118,8 +118,10 @@ int filter_commitrw(int cmd, struct obd_export *, struct obdo *, int objcount, struct obd_ioobj *, int niocount, struct niobuf_local *, struct obd_trans_info *, int rc); int filter_write_extents(struct obd_export *exp, struct obd_ioobj *obj, - int niocount, struct niobuf_local *local, + int objcount, int niocount,struct niobuf_local *local, int rc); +int filter_do_cow(struct obd_export *exp, struct obd_ioobj *obj, + int nioo, struct niobuf_remote *rnb); int filter_brw(int cmd, struct obd_export *, struct obdo *, struct lov_stripe_md *, obd_count oa_bufs, struct brw_page *, struct obd_trans_info *); diff --git a/lustre/obdfilter/filter_io.c b/lustre/obdfilter/filter_io.c index 0eac47f0df1392137e140eea36674c9189d9a2a3..10cc687fe04f1255723727cadd5550c38064d55a 100644 --- a/lustre/obdfilter/filter_io.c +++ b/lustre/obdfilter/filter_io.c @@ -33,6 +33,8 @@ #include <linux/obd_class.h> #include <linux/lustre_fsfilt.h> +#include <linux/lustre_smfs.h> +#include <linux/lustre_snap.h> #include "filter_internal.h" static int filter_start_page_read(struct obd_device *obd, struct inode *inode, @@ -832,22 +834,81 @@ void filter_grant_commit(struct obd_export *exp, int niocount, spin_unlock(&exp->exp_obd->obd_osfs_lock); } +int filter_do_cow(struct obd_export *exp, struct obd_ioobj *obj, + int nioo, struct niobuf_remote *rnb) +{ + struct dentry *dentry; + struct lvfs_run_ctxt saved; + struct write_extents *extents = NULL; + int j, rc = 0, numexts = 0, flags = 0; + + ENTRY; + + LASSERT(nioo == 1); + + push_ctxt(&saved, &exp->exp_obd->obd_lvfs_ctxt, NULL); + + dentry = filter_fid2dentry(exp->exp_obd, NULL, obj->ioo_gr, + obj->ioo_id); + if (IS_ERR(dentry)) { + pop_ctxt(&saved, &exp->exp_obd->obd_lvfs_ctxt, NULL); + RETURN (PTR_ERR(dentry)); + } -int filter_write_extents(struct obd_export *exp, struct obd_ioobj *obj, - int niocount, struct niobuf_local *local, - int rc) + if (dentry->d_inode == NULL) { + CERROR("trying to write extents to non-existent file "LPU64"\n", + obj->ioo_id); + GOTO(cleanup, rc = -ENOENT); + } + + flags = fsfilt_get_fs_flags(exp->exp_obd, dentry); + if (!(flags & SM_DO_COW)) { + GOTO(cleanup, rc); + } + OBD_ALLOC(extents, obj->ioo_bufcnt * sizeof(struct write_extents)); + if (!extents) { + CERROR("No Memory\n"); + GOTO(cleanup, rc = -ENOMEM); + } + for (j = 0; j < obj->ioo_bufcnt; j++) { + if (rnb[j].len != 0) { + extents[numexts].w_count = rnb[j].len; + extents[numexts].w_pos = rnb[j].offset; + numexts++; + } + } + rc = fsfilt_do_write_cow(exp->exp_obd, dentry, extents, numexts); + if (rc) { + CERROR("Do cow error id "LPU64" rc:%d \n", + obj->ioo_id, rc); + GOTO(cleanup, rc); + } + +cleanup: + if (extents) { + OBD_FREE(extents, obj->ioo_bufcnt * sizeof(struct write_extents)); + } + f_dput(dentry); + pop_ctxt(&saved, &exp->exp_obd->obd_lvfs_ctxt, NULL); + RETURN(rc); + +} +int filter_write_extents(struct obd_export *exp, struct obd_ioobj *obj, int nobj, + int niocount, struct niobuf_local *local, int rc) { struct lvfs_run_ctxt saved; struct dentry *dentry; struct niobuf_local *lnb; __u64 offset = 0; __u32 len = 0; - int i; + int i, flags; ENTRY; + LASSERT(nobj == 1); + push_ctxt(&saved, &exp->exp_obd->obd_lvfs_ctxt, NULL); - + dentry = filter_fid2dentry(exp->exp_obd, NULL, obj->ioo_gr, obj->ioo_id); if (IS_ERR(dentry)) { @@ -861,6 +922,11 @@ int filter_write_extents(struct obd_export *exp, struct obd_ioobj *obj, GOTO(cleanup, rc = -ENOENT); } + flags = fsfilt_get_fs_flags(exp->exp_obd, dentry); + if (!(flags & SM_DO_REC)) { + GOTO(cleanup, rc); + } + for (i = 0, lnb = local; i < obj->ioo_bufcnt; i++, lnb++) { if (len == 0) { offset = lnb->offset; @@ -891,7 +957,7 @@ int filter_write_extents(struct obd_export *exp, struct obd_ioobj *obj, cleanup: f_dput(dentry); pop_ctxt(&saved, &exp->exp_obd->obd_lvfs_ctxt, NULL); - return rc; + RETURN(rc); } int filter_commitrw(int cmd, struct obd_export *exp, struct obdo *oa, diff --git a/lustre/ost/ost_handler.c b/lustre/ost/ost_handler.c index bac04c274c4afbb9143d291952f09906df2741ab..3cbf75f548f4fb433490ffe6fdd95c66a75ad4ec 100644 --- a/lustre/ost/ost_handler.c +++ b/lustre/ost/ost_handler.c @@ -600,6 +600,11 @@ int ost_brw_write(struct ptlrpc_request *req, struct obd_trans_info *oti) GOTO(out, rc); rcs = lustre_msg_buf(req->rq_repmsg, 1, niocount * sizeof(*rcs)); + /* Do snap options here*/ + rc = obd_do_cow(req->rq_export, ioo, objcount, remote_nb); + if (rc) + GOTO(out, rc = npages); + /* FIXME all niobuf splitting should be done in obdfilter if needed */ /* CAVEAT EMPTOR this sets ioo->ioo_bufcnt to # pages */ npages = get_per_page_niobufs(ioo, objcount,remote_nb,niocount,&pp_rnb); @@ -705,11 +710,12 @@ int ost_brw_write(struct ptlrpc_request *req, struct obd_trans_info *oti) } LASSERT(j == npages); } - rc = obd_write_extents(req->rq_export, ioo, npages, local_nb, rc); + rc = obd_write_extents(req->rq_export, ioo, objcount, niocount, + local_nb, rc); if (rc) { CERROR("write extents error of id "LPU64" rc=%d\n", ioo->ioo_id, rc); - } + } out_bulk: ptlrpc_free_bulk(desc); out_local: diff --git a/lustre/smfs/dir.c b/lustre/smfs/dir.c index e3ce2ab323edb47ba210e1b03a1c280f8e10a43b..7fc58f36c72e75d0bd55fbe63102c0ae3d2cd9bf 100644 --- a/lustre/smfs/dir.c +++ b/lustre/smfs/dir.c @@ -34,6 +34,7 @@ #include <linux/lustre_lib.h> #include <linux/lustre_idl.h> #include <linux/lustre_fsfilt.h> +#include <linux/lustre_snap.h> #include <linux/lustre_smfs.h> #include "smfs_internal.h" @@ -74,10 +75,10 @@ static int smfs_create(struct inode *dir, struct dentry *dentry, if (!cache_dentry || !cache_parent) GOTO(exit, rc = -ENOMEM); - pre_smfs_inode(dir, cache_dir); - - SMFS_PRE_COW(dir, dentry, REINT_CREATE, "create", rc, exit); + SMFS_PRE_COW(dir, dentry, NULL, NULL, REINT_CREATE, "create", rc, exit); + + pre_smfs_inode(dir, cache_dir); #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) if (cache_dir && cache_dir->i_op->create) rc = cache_dir->i_op->create(cache_dir, cache_dentry, @@ -209,7 +210,7 @@ static int smfs_link(struct dentry * old_dentry, lock_kernel(); - SMFS_PRE_COW(dir, old_dentry, REINT_LINK, "link", rc, exit); + SMFS_PRE_COW(dir, old_dentry, NULL, NULL, REINT_LINK, "link", rc, exit); cache_parent = pre_smfs_dentry(NULL, cache_dir, dentry); cache_dentry = pre_smfs_dentry(cache_parent, NULL, dentry); @@ -270,7 +271,7 @@ static int smfs_unlink(struct inode * dir, SMFS_CACHE_HOOK_PRE(CACHE_HOOK_UNLINK, handle, dir, rc); - SMFS_PRE_COW(dir, dentry, REINT_UNLINK, "unlink", rc, exit); + SMFS_PRE_COW(dir, dentry, NULL, NULL, REINT_UNLINK, "unlink", rc, exit); cache_parent = pre_smfs_dentry(NULL, cache_dir, dentry); cache_dentry = pre_smfs_dentry(cache_parent, cache_inode, dentry); @@ -323,6 +324,9 @@ static int smfs_symlink(struct inode *dir, struct dentry *dentry, SMFS_CACHE_HOOK_PRE(CACHE_HOOK_SYMLINK, handle, dir, rc); + SMFS_PRE_COW(dir, dentry, NULL, NULL, REINT_CREATE, "symlink", rc, + exit); + pre_smfs_inode(dir, cache_dir); lock_kernel(); if (cache_dir->i_op->symlink) @@ -369,6 +373,8 @@ static int smfs_mkdir(struct inode *dir, struct dentry *dentry, SMFS_CACHE_HOOK_PRE(CACHE_HOOK_MKDIR, handle, dir, rc); + SMFS_PRE_COW(dir, dentry, NULL, NULL, REINT_CREATE, "mkdir", rc, + exit); cache_parent = pre_smfs_dentry(NULL, cache_dir, dentry); cache_dentry = pre_smfs_dentry(cache_parent, NULL, dentry); @@ -425,6 +431,8 @@ static int smfs_rmdir(struct inode *dir, struct dentry *dentry) SMFS_CACHE_HOOK_PRE(CACHE_HOOK_RMDIR, handle, dir, rc); + SMFS_PRE_COW(dir, dentry, NULL, NULL, REINT_UNLINK, "rmdir", rc, exit); + cache_parent = pre_smfs_dentry(NULL, cache_dir, dentry); cache_dentry = pre_smfs_dentry(cache_parent, cache_inode, dentry); @@ -478,6 +486,7 @@ static int smfs_mknod(struct inode *dir, struct dentry *dentry, } SMFS_CACHE_HOOK_PRE(CACHE_HOOK_MKNOD, handle, dir, rc); + SMFS_PRE_COW(dir, dentry, NULL, NULL, REINT_CREATE, "mknod", rc, exit); cache_parent = pre_smfs_dentry(NULL, cache_dir, dentry->d_parent); cache_dentry = pre_smfs_dentry(cache_parent, NULL, dentry); lock_kernel(); @@ -541,6 +550,8 @@ static int smfs_rename(struct inode * old_dir, struct dentry *old_dentry, } lock_kernel(); + SMFS_PRE_COW(old_dir, old_dentry, new_dir, new_dentry, REINT_RENAME, + "rename", rc, exit); SMFS_CACHE_HOOK_PRE(CACHE_HOOK_RENAME, handle, old_dir, rc); cache_old_parent = pre_smfs_dentry(NULL, cache_old_dir, old_dentry); @@ -561,7 +572,7 @@ static int smfs_rename(struct inode * old_dir, struct dentry *old_dentry, if (cache_old_dir->i_op->rename) rc = cache_old_dir->i_op->rename(cache_old_dir, cache_old_dentry, cache_new_dir, cache_new_dentry); - + post_smfs_inode(old_dir, cache_old_dir); post_smfs_inode(new_dir, cache_new_dir); diff --git a/lustre/smfs/file.c b/lustre/smfs/file.c index af1e1f5f7d50f5f2d8da722726ab3eec077886e5..d7f325ed6410e37a2fa04cfa702ba3ee99fa6bc3 100644 --- a/lustre/smfs/file.c +++ b/lustre/smfs/file.c @@ -39,6 +39,7 @@ #include <linux/lustre_idl.h> #include <linux/lustre_fsfilt.h> #include <linux/lustre_smfs.h> +#include <linux/lustre_snap.h> #include "smfs_internal.h" @@ -62,6 +63,15 @@ static ssize_t smfs_write(struct file *filp, const char *buf, size_t count, if (sfi->magic != SMFS_FILE_MAGIC) LBUG(); + if (filp->f_flags & O_APPEND) + tmp_ppos = filp->f_dentry->d_inode->i_size; + else { + tmp_ppos = *ppos; + } + + SMFS_PRE_COW(filp->f_dentry->d_inode, filp->f_dentry, &count, &tmp_ppos, + REINT_WRITE, "write", rc, exit); + if (ppos != &(filp->f_pos)) { cache_ppos = &tmp_ppos; } else { diff --git a/lustre/smfs/inode.c b/lustre/smfs/inode.c index 73b9a88f4a8fb92b6da945d4d8c46f85fb530d03..8360b18bb5756c8b58226c8f3d5ddabd52272f20 100644 --- a/lustre/smfs/inode.c +++ b/lustre/smfs/inode.c @@ -192,10 +192,10 @@ static void smfs_write_inode(struct inode *inode, int wait) return; } pre_smfs_inode(inode, cache_inode); - if (S2CSB(inode->i_sb)->s_op->write_inode) S2CSB(inode->i_sb)->s_op->write_inode(cache_inode, wait); - + + post_smfs_inode(inode, cache_inode); EXIT; } diff --git a/lustre/smfs/smfs_cow.c b/lustre/smfs/smfs_cow.c index 3e44317222a34293709fbfff28d0cd3f13aa6273..5b4f5798b8fddc92ac0ff319c485d73493a41923 100644 --- a/lustre/smfs/smfs_cow.c +++ b/lustre/smfs/smfs_cow.c @@ -24,6 +24,7 @@ #include <linux/module.h> #include <linux/kernel.h> +#include <linux/pagemap.h> #include <linux/string.h> #include <linux/slab.h> #include <linux/stat.h> @@ -443,7 +444,8 @@ int snap_do_cow(struct inode *inode, struct dentry *dparent, int del) RETURN(0); } /*Dir inode will do cow*/ -int smfs_cow_create(struct inode *dir, struct dentry *dentry) +int smfs_cow_create(struct inode *dir, struct dentry *dentry, + void *data1, void *data2) { int rc = 0; struct dentry *dparent; @@ -461,7 +463,8 @@ int smfs_cow_create(struct inode *dir, struct dentry *dentry) RETURN(rc); } -int smfs_cow_setattr(struct inode *dir, struct dentry *dentry) +int smfs_cow_setattr(struct inode *dir, struct dentry *dentry, + void *data1, void *data2) { int rc = 0; ENTRY; @@ -475,7 +478,8 @@ int smfs_cow_setattr(struct inode *dir, struct dentry *dentry) RETURN(rc); } -int smfs_cow_link(struct inode *dir, struct dentry *dentry) +int smfs_cow_link(struct inode *dir, struct dentry *dentry, + void *data1, void *data2) { int rc = 0; struct dentry *dparent; @@ -497,7 +501,8 @@ int smfs_cow_link(struct inode *dir, struct dentry *dentry) RETURN(rc); } -int smfs_cow_unlink(struct inode *dir, struct dentry *dentry) +int smfs_cow_unlink(struct inode *dir, struct dentry *dentry, + void *data1, void *data2) { struct dentry *dparent; int rc = 0; @@ -520,23 +525,123 @@ int smfs_cow_unlink(struct inode *dir, struct dentry *dentry) RETURN(rc); } -int smfs_cow_rename(struct inode *dir, struct dentry *dentry) +int smfs_cow_rename(struct inode *dir, struct dentry *dentry, + void *data1, void *data2) { + struct inode *new_dir = (struct inode *)data1; + struct dentry *new_dentry = (struct dentry *)data2; + struct dentry *dparent; int rc = 0; ENTRY; - + + LASSERT(new_dir); + LASSERT(new_dentry); + if (smfs_needs_cow(dir) != -1) { + CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n", dir->i_ino); + LASSERT(dentry->d_parent && dentry->d_parent->d_parent); + dparent = dentry->d_parent->d_parent; + if ((snap_do_cow(dir, dparent, 0))) { + CERROR("Do cow error\n"); + RETURN(-EINVAL); + } + if ((snap_do_cow(dentry->d_inode, dentry->d_parent, 0))) { + CERROR("Do cow error\n"); + RETURN(-EINVAL); + } + } + if (smfs_needs_cow(new_dir) != -1) { + CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n", new_dir->i_ino); + LASSERT(new_dentry->d_parent && new_dentry->d_parent->d_parent); + dparent = new_dentry->d_parent->d_parent; + if ((new_dir != dir) && (snap_do_cow(new_dir, dparent, 0))){ + CERROR("Do cow error\n"); + RETURN(-EINVAL); + } + if (new_dentry->d_inode && new_dentry->d_inode->i_nlink == 1) { + if ((snap_do_cow(new_dentry->d_inode, + new_dentry->d_parent, 0))) { + CERROR("Do cow error\n"); + RETURN(-EINVAL); + } + } + } RETURN(rc); } -int smfs_cow_write(struct inode *dir, struct dentry *dentry) +int smfs_cow_write(struct inode *inode, struct dentry *dentry, void *data1, + void *data2) { - int rc = 0; + struct snap_info *snap_info = S2SNAPI(inode->i_sb); + struct snap_table *table = snap_info->sntbl; + long blocks[2]={-1,-1}; + int index = 0, i, rc = 0; + size_t count = *(size_t *)data1; + loff_t pos = *(loff_t*)data2; + ENTRY; + + LASSERT(count); + LASSERT(pos); + + down(&inode->i_sem); + if (smfs_needs_cow(inode) != -1 ) { + CDEBUG(D_INFO, "snap_needs_cow for ino %lu \n",inode->i_ino); + snap_do_cow(inode, dentry->d_parent, 0); + } + + CDEBUG(D_INFO, "write offset %lld count %u \n", pos, count); + + if(pos & (PAGE_CACHE_SIZE - 1)){ + blocks[0] = pos >> inode->i_sb->s_blocksize_bits; + } + pos += count - 1; + if((pos + 1) & (PAGE_CACHE_SIZE - 1)){ + blocks[1] = pos >> inode->i_sb->s_blocksize_bits; + } + + if (blocks[0] == blocks[1]) + blocks[1] = -1; + + for (i = 0; i < 2; i++) { + int slot = 0; + if (blocks[i] == -1) + continue; + /*Find the nearest page in snaptable and copy back it*/ + for (slot = table->sntbl_count - 1; slot >= 0; slot--) { + struct fsfilt_operations *snapops = snap_info->snap_fsfilt; + struct inode *cache_inode = NULL; + int result = 0; + + index = table->sntbl_items[slot].sn_index; + cache_inode = snapops->fs_get_indirect(inode, NULL, index); + + if (!cache_inode) continue; + + CDEBUG(D_INFO, "find cache_ino %lu\n", cache_inode->i_ino); + + result = snapops->fs_copy_block(inode, cache_inode, blocks[i]); + if (result == 1) { + iput(cache_inode); + result = 0; + break; + } + if (result < 0) { + iput(cache_inode); + up(&inode->i_sem); + GOTO(exit, rc = result); + } + iput(cache_inode); + } + } +exit: + up(&inode->i_sem); RETURN(rc); } +EXPORT_SYMBOL(smfs_cow_write); -typedef int (*cow_funcs)(struct inode *dir, struct dentry *dentry); +typedef int (*cow_funcs)(struct inode *dir, struct dentry *dentry, + void *new_dir, void *new_dentry); static cow_funcs smfs_cow_funcs[REINT_MAX + 1] = { [REINT_SETATTR] smfs_cow_setattr, @@ -547,8 +652,9 @@ static cow_funcs smfs_cow_funcs[REINT_MAX + 1] = { [REINT_WRITE] smfs_cow_write, }; -int smfs_cow(struct inode *dir, struct dentry *dentry, int op) +int smfs_cow(struct inode *dir, struct dentry *dentry, void *new_dir, + void *new_dentry, int op) { - return smfs_cow_funcs[op](dir, dentry); + return smfs_cow_funcs[op](dir, dentry, new_dir, new_dentry); } diff --git a/lustre/smfs/smfs_internal.h b/lustre/smfs/smfs_internal.h index 1c72bf69b021012c6775b701e5c2f99ab874f76d..cb5862a816634962cf30cbd5a6d0bad8ed9b13e4 100644 --- a/lustre/smfs/smfs_internal.h +++ b/lustre/smfs/smfs_internal.h @@ -315,21 +315,22 @@ static inline int get_active_entry(struct inode *dir, __u64 *active_entry) } #if CONFIG_SNAPFS /*snap macros*/ -#define SMFS_PRE_COW(dir, dentry, op, name, rc, label) \ -do { \ - if (smfs_do_cow(dir) && !rc) { \ - CDEBUG(D_INODE, "Do %s snap post for dir %lu \n", \ - name, dir->i_ino); \ - rc = smfs_cow(dir, dentry, op); \ - if (rc) \ - GOTO(label, rc); \ - } \ +#define SMFS_PRE_COW(dir, dentry, new_dir, new_dentry, op, name, rc, label) \ +do { \ + if (smfs_do_cow(dir) && !rc) { \ + CDEBUG(D_INODE, "Do %s snap post for dir %lu \n", \ + name, dir->i_ino); \ + rc = smfs_cow(dir, dentry, new_dir, new_dentry, op); \ + if (rc) \ + GOTO(label, rc); \ + } \ } while(0) + extern int smfs_cow_init(struct super_block *sb); extern int smfs_cow_cleanup(struct super_block *sb); extern int smfs_init_snap_inode_info(struct inode *inode, int flags); #else -#define SMFS_PRE_COW(dir, dentry, op, name, rc, label) +#define SMFS_PRE_COW(dir, dentry, new_dir, new_dentry, op, name, rc, label) #endif #endif /*__KERNEL*/