From 1675d042a7cbc25c2b2dc8e6e790006a95114ad5 Mon Sep 17 00:00:00 2001 From: wangdi Date: Mon, 5 Jul 2004 11:04:03 +0000 Subject: [PATCH] Update snapfs 1)some fix in fsfilt_snap_ext3 and fsfilt_snap_smfs. 2)add smfs_cow.c in smfs. 3)remove snapfs in Makefile.in and configure.in --- lnet/utils/debug.c | 2 + lustre/Makefile.in | 1 - lustre/autoMakefile.am | 2 +- lustre/configure.in | 7 +- lustre/include/linux/lustre_fsfilt.h | 43 ++++- lustre/include/linux/lustre_smfs.h | 67 +++++++- lustre/include/linux/lustre_snap.h | 172 +++++++++++++++++++ lustre/lvfs/fsfilt_snap_ext3.c | 309 +++++++--------------------------- lustre/lvfs/fsfilt_snap_smfs.c | 106 +++++------- lustre/portals/utils/debug.c | 2 + lustre/smfs/Makefile.in | 4 +- lustre/smfs/dir.c | 7 +- lustre/smfs/smfs_cow.c | 318 +++++++++++++++++++++++++++++++++++ lustre/smfs/smfs_internal.h | 17 ++ lustre/smfs/super.c | 21 ++- 15 files changed, 735 insertions(+), 343 deletions(-) create mode 100644 lustre/include/linux/lustre_snap.h create mode 100644 lustre/smfs/smfs_cow.c diff --git a/lnet/utils/debug.c b/lnet/utils/debug.c index 67d8edc..9ce7528 100644 --- a/lnet/utils/debug.c +++ b/lnet/utils/debug.c @@ -545,9 +545,11 @@ static struct mod_paths { {"lov", "lustre/lov"}, {"lmv", "lustre/lmv"}, {"fsfilt_ext3", "lustre/lvfs"}, + {"fsfilt_snap_ext3", "lustre/lvfs"}, {"fsfilt_extN", "lustre/lvfs"}, {"fsfilt_reiserfs", "lustre/lvfs"}, {"fsfilt_smfs", "lustre/lvfs"}, + {"fsfilt_snap_smfs", "lustre/lvfs"}, {"ptlbd", "lustre/ptlbd"}, {"mgmt_svc", "lustre/mgmt"}, {"mgmt_cli", "lustre/mgmt"}, diff --git a/lustre/Makefile.in b/lustre/Makefile.in index 311435d..7a9e460 100644 --- a/lustre/Makefile.in +++ b/lustre/Makefile.in @@ -23,6 +23,5 @@ ifeq ($(PATCHLEVEL),4) subdir-m += ptlbd endif # PATCHLEVEL = 4 -@SNAPFS_TRUE@subdir-m += snapfs @INCLUDE_RULES@ diff --git a/lustre/autoMakefile.am b/lustre/autoMakefile.am index a664117..a706178 100644 --- a/lustre/autoMakefile.am +++ b/lustre/autoMakefile.am @@ -6,7 +6,7 @@ AUTOMAKE_OPTIONS = foreign SUBDIRS = . include portals ldiskfs lvfs obdclass lov ldlm ptlrpc \ - obdecho osc mdc lmv mds obdfilter ost llite cobd ptlbd snapfs smfs cmobd \ + obdecho osc mdc lmv mds obdfilter ost llite cobd ptlbd smfs cmobd \ liblustre doc utils tests conf scripts EXTRA_DIST = BUGS FDL Rules.in kernel_patches kernel-tests/Makefile \ diff --git a/lustre/configure.in b/lustre/configure.in index d667270..762e489 100644 --- a/lustre/configure.in +++ b/lustre/configure.in @@ -143,8 +143,12 @@ AC_ARG_ENABLE([snapfs], AC_HELP_STRING([--enable-snapfs], [build snapfs]), [],[enable_snapfs='no']) + AC_MSG_RESULT([$enable_snapfs]) AM_CONDITIONAL(SNAPFS, test x$enable_snapfs = xyes) +if test x$enable_snapfs = xyes ; then + AC_DEFINE(CONFIG_SNAPFS, 1, [enable snap support]) +fi sinclude(portals/build.m4) sinclude(portals/archdep.m4) @@ -239,9 +243,6 @@ scripts/lustre.spec scripts/version_tag.pl smfs/Makefile smfs/autoMakefile -snapfs/Makefile -snapfs/autoMakefile -snapfs/utils/Makefile cmobd/Makefile cmobd/autoMakefile tests/Makefile diff --git a/lustre/include/linux/lustre_fsfilt.h b/lustre/include/linux/lustre_fsfilt.h index 43c3123..204004e 100644 --- a/lustre/include/linux/lustre_fsfilt.h +++ b/lustre/include/linux/lustre_fsfilt.h @@ -58,8 +58,8 @@ struct fsfilt_operations { int (* fs_iocontrol)(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); int (* fs_set_md)(struct inode *inode, void *handle, void *md, - int size); - int (* fs_get_md)(struct inode *inode, void *md, int size); + int size, int flags); + int (* fs_get_md)(struct inode *inode, void *md, int size, int flags); /* this method is needed to make IO operation fsfilt nature depend. */ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) @@ -126,6 +126,32 @@ struct fsfilt_operations { char *, int, unsigned long, unsigned long, unsigned); int (* fs_del_dir_entry)(struct obd_device *, struct dentry *); + /*snap operations*/ + int (* fs_is_redirector)(struct inode *inode); + int (* fs_is_indirect)(struct inode *inode); + + struct inode * (* fs_create_indirect)(struct inode *pri, int index, + unsigned int gen, struct inode *parent, + int del); + struct inode * (* fs_get_indirect)(struct inode *pri, int *table, + int slot); + ino_t (* fs_get_indirect_ino)(struct inode *pri, int index); + int (* fs_destroy_indirect)(struct inode *pri, int index, + struct inode *next_ind); + int (* fs_restore_indirect)(struct inode *pri, int index); + int (* fs_iterate)(struct super_block *sb, + int (*repeat)(struct inode *inode, void *priv), + struct inode **start, void *priv, int flag); + int (* fs_copy_block)(struct inode *dst, struct inode *src, int blk); + int (* fs_set_indirect)(struct inode *pri, int index, + ino_t ind_ino, ino_t parent_ino); + int (* fs_snap_feature)(struct super_block *sb, int feature, int op); + int (* fs_set_snap_info)(struct super_block *sb, struct inode *inode, + void* key, __u32 keylen, void *val, + __u32 *vallen); + int (* fs_get_snap_info)(struct super_block *sb, struct inode *inode, + void* key, __u32 keylen, void *val, + __u32 *vallen); }; extern int fsfilt_register_ops(struct fsfilt_operations *fs_ops); @@ -175,6 +201,10 @@ extern void fsfilt_put_ops(struct fsfilt_operations *fs_ops); #define KML_CACHE_LINK 0x39 #define KML_CACHE_NOOP 0x3f +/*for fsfilt set md ea*/ +#define LMV_EA 1 +#define LOV_EA 0 + static inline void * fsfilt_start_ops(struct fsfilt_operations *ops, struct inode *inode, int op, struct obd_trans_info *oti, int logs) @@ -335,19 +365,18 @@ static inline int fsfilt_setup(struct obd_device *obd, return obd->obd_fsops->fs_setup(obd, fs); return 0; } - static inline int fsfilt_set_md(struct obd_device *obd, struct inode *inode, - void *handle, void *md, int size) + void *handle, void *md, int size, int flags) { - return obd->obd_fsops->fs_set_md(inode, handle, md, size); + return obd->obd_fsops->fs_set_md(inode, handle, md, size, flags); } static inline int fsfilt_get_md(struct obd_device *obd, struct inode *inode, - void *md, int size) + void *md, int size, int flags) { - return obd->obd_fsops->fs_get_md(inode, md, size); + return obd->obd_fsops->fs_get_md(inode, md, size, flags); } #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) diff --git a/lustre/include/linux/lustre_smfs.h b/lustre/include/linux/lustre_smfs.h index dfa3096..738eb6f 100644 --- a/lustre/include/linux/lustre_smfs.h +++ b/lustre/include/linux/lustre_smfs.h @@ -1,9 +1,40 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * Copyright (C) 2001-2003 Cluster File Systems, Inc. + * + * This file is part of Lustre, http://www.lustre.org. + * + * Lustre is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * Lustre is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Lustre; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * smfs data structures. + * See also lustre_idl.h for wire formats of requests. + * + */ + #ifndef __LUSTRE_SMFS_H #define __LUSTRE_SMFS_H +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; + struct snap_inode_info sm_sninfo; }; struct journal_operations { @@ -40,6 +71,7 @@ struct mds_kml_pack_info { int mpi_size[4]; int mpi_total_size; }; + struct smfs_super_info { struct super_block *smsi_sb; struct vfsmount *smsi_mnt; /* mount the cache kern */ @@ -54,9 +86,10 @@ struct smfs_super_info { char *smsi_cache_ftype; /* cache file system type */ char *smsi_ftype; /* file system type */ struct obd_export *smsi_exp; /* file system obd exp */ - smfs_pack_rec_func smsi_pack_rec[PACK_MAX]; /* sm_pack_rec type ops */ - __u32 smsi_flags; /* flags */ - __u32 smsi_ops_check; + struct snap_info *smsi_snap_info; /* snap table cow */ + smfs_pack_rec_func smsi_pack_rec[PACK_MAX]; /* sm_pack_rec type ops */ + __u32 smsi_flags; /* flags */ + __u32 smsi_ops_check; }; #define SMFS_FILE_TYPE "smfs" @@ -104,6 +137,9 @@ struct fs_extent{ (inode->i_sb->s_fs_info))->sm_cache_fsfilt) #endif +#define I2SNAPOPS(inode) ((S2SMI(inode->i_sb))->smsi_snap_info->snap_cache_fsfilt) + +#define S2SNAPI(sb) (S2SMI(sb)->smsi_snap_info) #define F2SMFI(file) ((struct smfs_file_info *)((file->private_data))) #define F2CF(file) (((struct smfs_file_info *) ((file->private_data)))->c_file) #define SIZE2BLKS(size, inode) ((size + (I2CI(inode)->i_blksize)) >> (I2CI(inode)->i_blkbits)) @@ -113,7 +149,8 @@ struct fs_extent{ #define SM_INIT_REC 0x2 #define SM_CACHE_HOOK 0x4 #define SM_OVER_WRITE 0x8 -#define SM_DIRTY_WRITE 0x10 +#define SM_DIRTY_WRITE 0x10 +#define SM_DO_COW 0x20 #define SMFS_DO_REC(smfs_info) (smfs_info->smsi_flags & SM_DO_REC) #define SMFS_SET_REC(smfs_info) (smfs_info->smsi_flags |= SM_DO_REC) @@ -143,6 +180,13 @@ struct fs_extent{ #define SMFS_SET_INODE_DIRTY_WRITE(inode) (I2SMI(inode)->smi_flags |= SM_DIRTY_WRITE) #define SMFS_CLEAN_INODE_DIRTY_WRITE(inode) (I2SMI(inode)->smi_flags &= ~SM_DIRTY_WRITE) +#define SMFS_DO_COW(smfs_info) (smfs_info->smsi_flags & SM_DO_COW) +#define SMFS_SET_COW(smfs_info) (smfs_info->smsi_flags |= SM_DO_COW) +#define SMFS_CLEAN_COW(smfs_info) (smfs_info->smsi_flags &= ~SM_DO_COW) + +#define SMFS_SET_INODE_COW(inode) (I2SMI(inode)->smi_flags |= SM_DO_COW) +#define SMFS_DO_INODE_COW(inode) (I2SMI(inode)->smi_flags & SM_DO_COW) +#define SMFS_CLEAN_INODE_COW(inode) (I2SMI(inode)->smi_flags &= ~SM_DO_COW) #define LVFS_SMFS_BACK_ATTR "lvfs_back_attr" @@ -358,7 +402,6 @@ static inline int lookup_by_path(char *path, int flags, struct nameidata *nd) } /*FIXME there should be more conditions in this check*/ - static inline int smfs_do_rec(struct inode *inode) { struct super_block *sb = inode->i_sb; @@ -369,6 +412,7 @@ static inline int smfs_do_rec(struct inode *inode) return 1; return 0; } + static inline int smfs_cache_hook(struct inode *inode) { struct smfs_super_info *smfs_info = I2CSB(inode); @@ -379,6 +423,17 @@ static inline int smfs_cache_hook(struct inode *inode) else return 0; } + +static inline int smfs_do_cow(struct inode *inode) +{ + struct super_block *sb = inode->i_sb; + struct smfs_super_info *smfs_info = S2SMI(sb); + + if (SMFS_DO_COW(smfs_info) && SMFS_DO_INODE_COW(inode)) + return 1; + return 0; +} + /* XXX BUG 3188 -- must return to one set of opcodes */ #define SMFS_TRANS_OP(inode, op) \ { \ @@ -398,5 +453,7 @@ extern int smfs_rec_precreate(struct dentry *dentry, int *num, struct obdo *oa); 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); #endif /* _LUSTRE_SMFS_H */ diff --git a/lustre/include/linux/lustre_snap.h b/lustre/include/linux/lustre_snap.h new file mode 100644 index 0000000..3962a52 --- /dev/null +++ b/lustre/include/linux/lustre_snap.h @@ -0,0 +1,172 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * Copyright (C) 2001-2003 Cluster File Systems, Inc. + * + * This file is part of Lustre, http://www.lustre.org. + * + * Lustre is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * Lustre is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Lustre; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * SNAP data structures. + * See also lustre_idl.h for wire formats of requests. + * + */ +/* maximum number of snapshots available for users */ + +#ifndef __LUSTRE_SNAP_H +#define __LUSTRE_SNAP_H + +#define MAX_SNAPS 20 +#define SNAP_ATTR "@snap" +struct snap_ea{ + int generation; + ino_t prev_ino; + ino_t next_ino; + ino_t ino[MAX_SNAPS+1]; /* including current snapshot */ + ino_t parent_ino[MAX_SNAPS+1]; +}; +#define MAX_SNAP_DATA (sizeof(struct snap_ea)) + +/* + * Check if the EA @name is Snap EA or not. + * Snap EA includes the SNAP_ATTR, SNAP_NEW_INO_ATTR and DISK_SNAP_META_ATTR + */ + +#define IS_SNAP_EA(name) ( (!strcmp((name), SNAP_ATTR)) || \ + (!strcmp((name), DISK_SNAP_META_ATTR))) + + +/* file system features */ +#define SNAP_FEATURE_COMPAT_SNAPFS 0x0010 +#define SNAP_FEATURE_COMPAT_BLOCKCOW 0x0020 + +/* constants for snap_feature operations */ +#define SNAP_CLEAR_FEATURE 0x0 +#define SNAP_SET_FEATURE 0x1 +#define SNAP_HAS_FEATURE 0x2 + +/* snap flags for inode, within 1 byte range, each occupy 1 bit */ +#define SNAP_INO_MAGIC 0x88 /* magic for snap inode */ +#define SNAP_COW_FLAG 0x01 /* snap redirected inode */ +#define SNAP_DEL_FLAG 0x02 /* snap deleted inode */ +#define SNAP_TABLE_FLAG 0x04 /* snap table inode */ +#define SNAP_PRI_FLAG 0x08 /* primary inode */ + +/* no snapfs attributes for get_indirect_ino */ +#define ENOSNAPATTR 320 + +/* constants used by iterator */ +#define SNAP_ITERATE_ALL_INODE 0x0 +#define SNAP_ITERATE_COWED_INODE 0x1 + +/* constants used by create_indirect */ +#define SNAP_CREATE_IND_NORMAL 0x0 +#define SNAP_CREATE_IND_DEL_PRI 0x1 + +/* the data structure represent in the xfs_dinode.pad + offset 0: magic (1 byte) + offset 1: flag (1 byte) + offset 2: gen (4 bytes) + offset 6: unused + */ +#define SIZEOF_MAGIC 1 +#define SIZEOF_FLAG 1 +#define SIZEOF_GENERATION 4 + +#define MAGIC_OFFSET 0 +#define FLAG_OFFSET 1 +#define GENERATION_OFFSET 2 + +#define SNAP_GET_DINODE_MAGIC(dinode) \ + (((__u8*)(dinode)->di_pad)[MAGIC_OFFSET]) +#define SNAP_SET_DINODE_MAGIC(dinode) \ + ((__u8*)(dinode)->di_pad)[MAGIC_OFFSET] = (SNAP_INO_MAGIC) +#define SNAP_GET_DINODE_FLAG(dinode) \ + (((__u8*)(dinode)->di_pad)[FLAG_OFFSET]) +#define SNAP_SET_DINODE_FLAG(dinode, flag) \ + (((__u8*)(dinode)->di_pad)[FLAG_OFFSET] |= (flag)) +#define SNAP_CLEAR_DINODE_FLAG(dinode, flag) \ + (((__u8*)(dinode)->di_pad)[FLAG_OFFSET] &= ~(flag)) +#define SNAP_GET_DINODE_GEN(dinode) \ + (le32_to_cpu(*(__u32*)(&((__u8*)(dinode)->di_pad)[GENERATION_OFFSET]))) +#define SNAP_SET_DINODE_GEN(dinode, gen) \ + *(__u32*)(&((__u8*)(dinode)->di_pad)[GENERATION_OFFSET]) = cpu_to_le32(gen) +#define SNAP_VERSION(a,b,c) \ + (((a & 0xFF) << 16) | ((b & 0xFF) << 8) | (c & 0xFF)) +#define SNAP_VERSION_MAJOR(v) \ + ((v >> 16) & 0xFF) +#define SNAP_VERSION_MINOR(v) \ + ((v >> 8) & 0xFF) +#define SNAP_VERSION_REL(v) \ + (v & 0xFF) + + +#define EXT3_EA_TRANS_BLOCKS EXT3_DATA_TRANS_BLOCKS +#define EXT3_SETMETA_TRANS_BLOCKS EXT3_DATA_TRANS_BLOCKS +#define EXT3_NEWINODE_TRANS_BLOCKS 10 +#define SNAP_INSERTLIST_TRANS_BLOCKS (2 * EXT3_EA_TRANS_BLOCKS + 1) +#define SNAP_DELETELIST_TRANS_BLOCKS (2 * EXT3_EA_TRANS_BLOCKS + 2) +#define SNAP_COPYBLOCK_TRANS_BLOCKS (EXT3_DATA_TRANS_BLOCKS) +#define SNAP_MIGRATEDATA_TRANS_BLOCKS 2 +#define SNAP_SETIND_TRANS_BLOCKS (SNAP_INSERTLIST_TRANS_BLOCKS + 1) +#define SNAP_ADDORPHAN_TRANS_BLOCKS 2 +#define SNAP_REMOVEORPHAN_TRANS_BLOCKS 1 +#define SNAP_RESTOREORPHAN_TRANS_BLOCKS (EXT3_EA_TRANS_BLOCKS + \ + SNAP_DELETELIST_TRANS_BLOCKS + \ + EXT3_NEWINODE_TRANS_BLOCKS + \ + 2 * SNAP_MIGRATEDATA_TRANS_BLOCKS) +#define SNAP_BIGCOPY_TRANS_BLOCKS (2 * EXT3_DATA_TRANS_BLOCKS) +#define SNAP_CREATEIND_TRANS_BLOCKS (EXT3_NEWINODE_TRANS_BLOCKS + \ + SNAP_MIGRATEDATA_TRANS_BLOCKS + \ + SNAP_SETIND_TRANS_BLOCKS + \ + SNAP_BIGCOPY_TRANS_BLOCKS + 3) +#define SNAP_MIGRATEBLK_TRANS_BLOCKS 2 +#define SNAP_DESTROY_TRANS_BLOCKS (SNAP_DELETELIST_TRANS_BLOCKS + \ + EXT3_EA_TRANS_BLOCKS + 2) +#define SNAP_RESTORE_TRANS_BLOCKS (EXT3_NEWINODE_TRANS_BLOCKS + \ + 2 * SNAP_MIGRATEDATA_TRANS_BLOCKS + 1) +/*Snap Table*/ +#define SNAP_MAX 32 +#define SNAP_MAX_TABLES 32 +#define SNAP_MAX_NAMELEN 64 + +#define MAX_SNAPTABLE_COUNT "MAXSnapCount" +#define SNAP_TABLE_MAGIC 0x19760218 +#define SNAPTABLE_INFO "snaptable" +#define SNAP_GENERATION "snap_generation" +struct snap { + time_t sn_time; + unsigned int sn_index; + unsigned int sn_gen; + unsigned int sn_flags; + char name[SNAP_MAX_NAMELEN]; +}; + +struct snap_table { + unsigned int sntbl_magic; + unsigned int sntbl_count; + unsigned int sntbl_max_count; + unsigned int sntbl_generation; + struct snap sntbl_items[0]; +}; + +struct snap_info { + struct fsfilt_operations *snap_fsfilt; + struct fsfilt_operations *snap_cache_fsfilt; + struct semaphore sntbl_sema; + spinlock_t sntbl_lock; + struct snap_table *sntbl; +}; + +#endif /*_LUSTRE_SNAP_H*/ diff --git a/lustre/lvfs/fsfilt_snap_ext3.c b/lustre/lvfs/fsfilt_snap_ext3.c index 0d68a45..b183bf6 100644 --- a/lustre/lvfs/fsfilt_snap_ext3.c +++ b/lustre/lvfs/fsfilt_snap_ext3.c @@ -56,7 +56,7 @@ #define EXT3_DEL_FL 0x00200000 /* inode is deleting in snapshot */ #define EXT3_SNAP_ATTR "@snap" -#define EXT3_SNAP_GENERATION_ATTR "@snap_generation" +#define EXT3_SNAP_GENERATION "@snap_generation" #define EXT3_MAX_SNAPS 20 #define EXT3_MAX_SNAP_DATA (sizeof(struct snap_ea)) #define EXT3_SNAP_INDEX EXT3_XATTR_INDEX_LUSTRE @@ -69,6 +69,8 @@ #define EXT3_FEATURE_COMPAT_SNAPFS 0x0010 #define EXT3_FEATURE_COMPAT_BLOCKCOW 0x0020 +/*snaptable info for EXT3*/ +#define EXT3_SNAPTABLE_EA "@snaptable" /* NOTE: these macros are close dependant on the structure of snap ea */ #define SNAP_CNT_FROM_SIZE(size) ((((size)-sizeof(ino_t)*2)/2)/sizeof(ino_t)) @@ -232,7 +234,7 @@ out_unlock: return err; } -static int fsfilt_ext3_set_generation(struct inode *inode, unsigned long gen) +static int ext3_set_generation(struct inode *inode, unsigned long gen) { handle_t *handle; int err = 0; @@ -243,7 +245,7 @@ static int fsfilt_ext3_set_generation(struct inode *inode, unsigned long gen) RETURN(-EINVAL); err = ext3_xattr_set(handle, inode, EXT3_SNAP_INDEX, - EXT3_SNAP_GENERATION_ATTR, + EXT3_SNAP_GENERATION, (char*)&gen, sizeof(int), 0); if (err < 0) { CERROR("ino %lu, set_ext_attr err %d\n", inode->i_ino, err); @@ -253,26 +255,6 @@ static int fsfilt_ext3_set_generation(struct inode *inode, unsigned long gen) ext3_journal_stop(handle, inode); RETURN(0); } - -static int fsfilt_ext3_get_generation(struct inode *inode) -{ - int err, gen; - ENTRY; - - err = ext3_xattr_get(inode, EXT3_SNAP_INDEX, EXT3_SNAP_GENERATION_ATTR, - (char*)&gen, sizeof(gen)); - if (err < 0) { - if (err == -ENODATA) { - RETURN(0); - } else { - CERROR("can not get generation from %lu \n", - inode->i_ino); - RETURN(err); - } - } - - RETURN(gen); -} /* * Copy inode metadata from one inode to another, excluding blocks and size. @@ -624,7 +606,7 @@ static struct inode* fsfilt_ext3_create_indirect(struct inode *pri, int index, CDEBUG(D_INODE, "got new inode %lu\n", ind->i_ino); ind->i_rdev = pri->i_rdev; ind->i_op = pri->i_op; - fsfilt_ext3_set_generation(ind, (unsigned long)gen); + ext3_set_generation(ind, (unsigned long)gen); /* If we are deleting the primary inode, we want to ensure that it is * written to disk with a non-zero link count, otherwise the next iget * and iput will mark the inode as free (which we don't want, we want @@ -1455,231 +1437,72 @@ static int fsfilt_ext3_iterate(struct super_block *sb, } } -static int find_snap_meta_index( - struct table_snap_meta_data *snap_meta, - char *name) -{ - int i; - - /* table max length is null*/ - for( i = 0; i < TABLE_ITEM_COUNT; i++){ - /*compare name Max name Length 15*/ - if (snap_meta->array[i].name[0]){ - if(!strncmp(snap_meta->array[i].name, name, strlen(name))) - return i; - } - } - return -1; /* can not find */ -} - -int set_snap_meta_index( - struct table_snap_meta_data *snap_meta, - char *name, - int size) +static int fsfilt_ext3_get_snap_info(struct super_block *sb,struct inode *inode, + void *key, __u32 keylen, void *val, + __u32 *vallen) { - int i; - - for( i = 0; i < TABLE_ITEM_COUNT; i++){ - /*compare name Max name Length 15*/ - if (! snap_meta->array[i].name[0]){ - strcpy(snap_meta->array[i].name, name); - snap_meta->count ++; - snap_meta->array[i].start = i * TABLE_ITEM_SIZE + 1; - snap_meta->array[i].len = size; - return i; - } - } - return -1; /* can not find */ -} - -static int fsfilt_ext3_get_meta_attr(struct super_block *sb, char* name, - char* buf, int *size) -{ - struct inode *inode; - struct buffer_head *bh = NULL; - struct table_snap_meta_data *s_attr; - unsigned long map_len = 0, left_size; - int i, error = 0, index = 0; - ino_t ino; - ENTRY; - - ino = SB_SNAPTABLE_INO(sb); - if (ino == 0){ - CERROR("No table file \n"); - RETURN(-ENODATA); - } - - inode = iget(sb, ino); - if(!inode || is_bad_inode(inode)){ - CERROR("unable to get table ino %lu\n", ino); - GOTO(out_iput, error = -ENOENT); - } - /*read the table from the table inode*/ - bh = ext3_bread(NULL, inode, 0, 0, &error); - if (!bh) { - CERROR("read table ino %lu, error %d\n", ino, error); - GOTO(out_iput, error = -ENODATA); - } - s_attr = (struct table_snap_meta_data *)(bh->b_data); - index = find_snap_meta_index(s_attr, name); - if (index < 0) { - CDEBUG(D_INFO, "not exit %s meta attr of table ino %lu \n", - name, inode->i_ino); - GOTO(out_iput, error = 0); - } - if (!buf || *size < s_attr->array[index].len) { - /*return the size of this meta attr */ - error = s_attr->array[index].len; - GOTO(out_iput, error); - } - map_len = (s_attr->array[index].len + sb->s_blocksize - 1) - >> sb->s_blocksize_bits; - left_size = *size; - for(i = 0; i < map_len; i++) { - struct buffer_head *array_bh = NULL; - - array_bh = ext3_bread(NULL, inode, - s_attr->array[index].start + i, - 0, &error); - if (!array_bh) { - CERROR("ino %lu read snap attr offset %d error %d \n", - inode->i_ino, (s_attr->array[index].start + i), - error); - GOTO(out_iput, error); - } - if (left_size >= sb->s_blocksize) - memcpy(buf, array_bh->b_data, sb->s_blocksize); - else - memcpy(buf, array_bh->b_data, left_size); - left_size -= sb->s_blocksize; - brelse(array_bh); - } - *size = s_attr->array[index].len; -out_iput: - brelse(bh); - iput(inode); + int rc = 0; + ENTRY; - RETURN(error); + if (!vallen || !val) { + CERROR("val and val_size is 0!\n"); + RETURN(-EFAULT); + } + if (keylen >= strlen(MAX_SNAPTABLE_COUNT) + && strcmp(key, MAX_SNAPTABLE_COUNT) == 0) { + /*FIXME should get it from the EA_size*/ + *((__u32 *)val) = EXT3_MAX_SNAPS; + *vallen = sizeof(int); + RETURN(rc); + } else if (keylen >= strlen(SNAPTABLE_INFO) + && strcmp(key, SNAPTABLE_INFO) == 0) { + rc = ext3_xattr_get(sb->s_root->d_inode, EXT3_SNAP_INDEX, + EXT3_SNAPTABLE_EA, val, *vallen); + RETURN(rc); + } else if (keylen >= strlen(SNAP_GENERATION) + && strcmp(key, SNAP_GENERATION) == 0) { + + rc = ext3_xattr_get(inode, EXT3_SNAP_INDEX,EXT3_SNAP_GENERATION, + (char *)val, *vallen); + RETURN(rc); + } + RETURN(-EINVAL); } -static int fsfilt_ext3_set_meta_attr(struct super_block *sb, char* name, - char* buf, int size) +static int fsfilt_ext3_set_snap_info(struct super_block *sb,struct inode *inode, + void *key, __u32 keylen, void *val, + __u32 *vallen) { - struct inode *inode = NULL; - handle_t *handle = NULL; - struct buffer_head *bh = NULL; - struct table_snap_meta_data *s_attr = NULL; - unsigned long ino; - int i, index = 0, error = 0; - unsigned long new_len = 0, left_size; - + int rc = 0; ENTRY; - - ino = SB_SNAPTABLE_INO(sb); - - if (ino == 0 && !buf) { - CDEBUG(D_INODE, "no table ino \n"); - RETURN(0); - } - - handle = ext3_journal_start(sb->s_root->d_inode, - 2 * EXT3_SETMETA_TRANS_BLOCKS); - if(!handle) - RETURN(-EINVAL); - - if (ino == 0) { - /*create table inode update table ino*/ - inode = ext3_new_inode(handle, sb->s_root->d_inode, (int)S_IFREG, 0); - if (!inode) - RETURN(-EINVAL); - lock_super(sb); - ext3_journal_get_write_access(handle, sb->u.ext3_sb.s_sbh); - SB_SNAPTABLE_INO(sb) = inode->i_ino; - ext3_journal_dirty_metadata(handle, sb->u.ext3_sb.s_sbh); - sb->s_dirt = 1; - unlock_super(sb); + + if (!vallen || !val) { + CERROR("val and val_size is 0!\n"); + RETURN(-EFAULT); + } - } else { - inode = iget(sb, ino); - if (!inode || !inode->i_nlink || is_bad_inode(inode)) { - CERROR("unable to get table ino %lu\n", ino); - GOTO(exit, error = -ENOENT); - } - } - /*read the table from the table inode, - * If can not find the block just create it*/ - bh = ext3_bread(handle, inode, 0, 1, &error); - if (!bh) { - CERROR("read table ino %lu, error %d\n", ino, error); - GOTO(exit, error = -ENODATA); - } - s_attr = (struct table_snap_meta_data *)(bh->b_data); - index = find_snap_meta_index(s_attr, name); - if (index < 0 && !buf) { - CDEBUG(D_INODE, "%s meta attr of table ino %lu do not exist\n", - name, inode->i_ino); - brelse(bh); - GOTO(exit, error = 0); - } - if (!buf) { - CDEBUG(D_INODE, "delete the meta attr %s in the table ino %lu", - name, inode->i_ino); - /*Here we only delete the entry of the attr - *FIXME, should we also delete the block of - * this attr - */ - ext3_journal_get_write_access(handle, bh); - memset(s_attr->array[index].name, 0, TABLE_ITEM_NAME_SIZE); - s_attr->array[index].len = 0; - s_attr->count --; - ext3_journal_dirty_metadata(handle, bh); - brelse(bh); - GOTO(exit, error); - } - new_len = (size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; - /*find the place to put this attr in that index*/ - ext3_journal_get_write_access(handle, bh); - if (index < 0){ - index = set_snap_meta_index(s_attr, name, size); - if (index < 0){ - CERROR("table full of ino %lu \n", inode->i_ino); - brelse(bh); - GOTO(exit, error = index); - } - } - s_attr->array[index].len = size; - journal_dirty_metadata(handle, bh); - brelse(bh); - /*put this attr to the snap table*/ - left_size = size; - for(i = 0; i < new_len; i++) { - struct buffer_head *array_bh = NULL; - - array_bh = ext3_bread(handle, inode, - s_attr->array[index].start + i, 1, &error); - if (!array_bh) { - CERROR("inode %lu Can not get the block of attr %s\n", - inode->i_ino, name); - brelse(array_bh); - GOTO(exit, error = -ENOSPC); - } - ext3_journal_get_write_access(handle, array_bh); - if (left_size > inode->i_sb->s_blocksize) - memcpy(array_bh->b_data, buf, inode->i_sb->s_blocksize); - else - memcpy(array_bh->b_data, buf, left_size); - ext3_journal_dirty_metadata(handle, array_bh); - left_size -= inode->i_sb->s_blocksize; - brelse(array_bh); - } -exit: - if (handle) - ext3_journal_stop(handle, sb->s_root->d_inode); - iput(inode); - RETURN(error); + if (keylen >= strlen(SNAPTABLE_INFO) + && strcmp(key, SNAPTABLE_INFO) == 0) { + struct inode *inode = sb->s_root->d_inode; + handle_t *handle; + + handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS); + if( !handle ) + RETURN(-EINVAL); + rc = ext3_xattr_set(handle, inode, EXT3_SNAP_INDEX, + EXT3_SNAPTABLE_EA, val, *vallen, 0); + ext3_journal_stop(handle,inode); + + RETURN(rc); + } else if (keylen >= strlen(SNAP_GENERATION) + && strcmp(key, SNAP_GENERATION) == 0) { + rc = ext3_set_generation(inode, *(int*)val); + + RETURN(rc); + } + RETURN(-EINVAL); } - struct fsfilt_operations fsfilt_ext3_snap_ops = { .fs_type = "ext3_snap", .fs_owner = THIS_MODULE, @@ -1690,14 +1513,12 @@ struct fsfilt_operations fsfilt_ext3_snap_ops = { .fs_is_redirector = fsfilt_ext3_is_redirector, .fs_is_indirect = fsfilt_ext3_is_indirect, .fs_get_indirect_ino = fsfilt_ext3_get_indirect_ino, - .fs_set_generation = fsfilt_ext3_set_generation, - .fs_get_generation = fsfilt_ext3_get_generation, .fs_destroy_indirect = fsfilt_ext3_destroy_indirect, .fs_restore_indirect = fsfilt_ext3_restore_indirect, .fs_iterate = fsfilt_ext3_iterate, .fs_copy_block = fsfilt_ext3_copy_block, - .fs_set_meta_attr = fsfilt_ext3_set_meta_attr, - .fs_get_meta_attr = fsfilt_ext3_get_meta_attr, + .fs_set_snap_info = fsfilt_ext3_set_snap_info, + .fs_get_snap_info = fsfilt_ext3_get_snap_info, }; static int __init fsfilt_ext3_snap_init(void) diff --git a/lustre/lvfs/fsfilt_snap_smfs.c b/lustre/lvfs/fsfilt_snap_smfs.c index 2d74ae4..bd300f4 100644 --- a/lustre/lvfs/fsfilt_snap_smfs.c +++ b/lustre/lvfs/fsfilt_snap_smfs.c @@ -137,7 +137,7 @@ static int fsfilt_smfs_set_indirect(struct inode *inode, int index, static int fsfilt_smfs_snap_feature(struct super_block *sb, int feature, int op) { - struct fsfilt_operations *snap_fsfilt = S2SMI(sb)->sm_snap_fsfilt; + struct fsfilt_operations *snap_fsfilt = S2SNAPI(sb)->snap_cache_fsfilt; struct super_block *csb = S2CSB(sb); int rc = -EIO; @@ -215,50 +215,6 @@ static ino_t fsfilt_smfs_get_indirect_ino(struct inode *inode, int index) RETURN(rc); } -static int fsfilt_smfs_set_generation(struct inode *inode, - unsigned long new_gen) -{ - struct fsfilt_operations *snap_fsfilt = I2SNAPOPS(inode); - struct inode *cache_inode = NULL; - int rc = -EIO; - ENTRY; - - if (snap_fsfilt == NULL) - RETURN(rc); - - cache_inode = I2CI(inode); - if (!cache_inode) - RETURN(rc); - - pre_smfs_inode(inode, cache_inode); - if (snap_fsfilt->fs_set_generation) - rc = snap_fsfilt->fs_set_generation(cache_inode, new_gen); - post_smfs_inode(inode, cache_inode); - - RETURN(rc); -} - -static int fsfilt_smfs_get_generation(struct inode *inode) -{ - struct fsfilt_operations *snap_fsfilt = I2SNAPOPS(inode); - struct inode *cache_inode = NULL; - int rc = -EIO; - ENTRY; - - if (snap_fsfilt == NULL) - RETURN(rc); - - cache_inode = I2CI(inode); - if (!cache_inode) - RETURN(rc); - - pre_smfs_inode(inode, cache_inode); - if (snap_fsfilt->fs_get_generation) - rc = snap_fsfilt->fs_get_generation(cache_inode); - post_smfs_inode(inode, cache_inode); - - RETURN(rc); -} static int fsfilt_smfs_destroy_indirect(struct inode *inode, int index, struct inode *next_ind) @@ -318,7 +274,7 @@ static int fsfilt_smfs_iterate(struct super_block *sb, int (*repeat)(struct inode *inode, void *priv), struct inode **start, void *priv, int flag) { - struct fsfilt_operations *snap_fsfilt = S2SMI(sb)->sm_snap_fsfilt; + struct fsfilt_operations *snap_fsfilt = S2SNAPI(sb)->snap_cache_fsfilt; struct super_block *csb = S2CSB(sb); int rc = -EIO; ENTRY; @@ -366,38 +322,56 @@ static int fsfilt_smfs_copy_block(struct inode *dst, struct inode *src, int blk) RETURN(rc); } -static int fsfilt_smfs_set_meta_attr(struct super_block *sb, char *name, - char *buf, int size) +static int fsfilt_smfs_set_snap_info(struct super_block *sb,struct inode *inode, + void* key, __u32 keylen, void *val, + __u32 *vallen) { - struct fsfilt_operations *snap_fsfilt = S2SMI(sb)->sm_snap_fsfilt; - struct super_block *csb = S2CSB(sb); + struct super_block *csb = NULL; + struct inode *cache_inode = NULL; + struct fsfilt_operations *snap_fsfilt = NULL; int rc = -EIO; + if (sb) { + csb = S2CSB(sb); + snap_fsfilt = S2SNAPI(sb)->snap_cache_fsfilt; + } else if (inode) { + cache_inode = I2CI(inode); + snap_fsfilt = I2SNAPOPS(inode); + } + if (snap_fsfilt == NULL) RETURN(rc); - if (!csb) - RETURN(rc); - if (snap_fsfilt->fs_set_meta_attr) - rc = snap_fsfilt->fs_set_meta_attr(csb, name, buf, size); + if (snap_fsfilt->fs_set_snap_info) + rc = snap_fsfilt->fs_set_snap_info(csb, cache_inode, key, + keylen, val, vallen); RETURN(rc); } -static int fsfilt_smfs_get_meta_attr(struct super_block *sb, char *name, - char *buf, int *size) +static int fsfilt_smfs_get_snap_info(struct super_block *sb, struct inode *inode, + void *key, __u32 keylen, void *val, + __u32 *vallen) { - struct fsfilt_operations *snap_fsfilt = S2SMI(sb)->sm_snap_fsfilt; - struct super_block *csb = S2CSB(sb); + struct super_block *csb = NULL; + struct inode *cache_inode = NULL; + struct fsfilt_operations *snap_fsfilt = NULL; int rc = -EIO; + if (sb) { + csb = S2CSB(sb); + snap_fsfilt = S2SNAPI(sb)->snap_cache_fsfilt; + } else if (inode) { + cache_inode = I2CI(inode); + snap_fsfilt = I2SNAPOPS(inode); + } + if (snap_fsfilt == NULL) RETURN(rc); - if (!csb) - RETURN(rc); - - if (snap_fsfilt->fs_get_meta_attr) - rc = snap_fsfilt->fs_get_meta_attr(csb, name, buf, size); + + if (snap_fsfilt->fs_get_snap_info) + rc = snap_fsfilt->fs_get_snap_info(csb, cache_inode, key, + keylen, val, vallen); RETURN(rc); } @@ -412,14 +386,12 @@ struct fsfilt_operations fsfilt_smfs_snap_ops = { .fs_is_redirector = fsfilt_smfs_is_redirector, .fs_is_indirect = fsfilt_smfs_is_indirect, .fs_get_indirect_ino = fsfilt_smfs_get_indirect_ino, - .fs_set_generation = fsfilt_smfs_set_generation, - .fs_get_generation = fsfilt_smfs_get_generation, .fs_destroy_indirect = fsfilt_smfs_destroy_indirect, .fs_restore_indirect = fsfilt_smfs_restore_indirect, .fs_iterate = fsfilt_smfs_iterate, .fs_copy_block = fsfilt_smfs_copy_block, - .fs_set_meta_attr = fsfilt_smfs_set_meta_attr, - .fs_get_meta_attr = fsfilt_smfs_get_meta_attr, + .fs_set_snap_info = fsfilt_smfs_set_snap_info, + .fs_get_snap_info = fsfilt_smfs_get_snap_info, }; diff --git a/lustre/portals/utils/debug.c b/lustre/portals/utils/debug.c index 67d8edc..9ce7528 100644 --- a/lustre/portals/utils/debug.c +++ b/lustre/portals/utils/debug.c @@ -545,9 +545,11 @@ static struct mod_paths { {"lov", "lustre/lov"}, {"lmv", "lustre/lmv"}, {"fsfilt_ext3", "lustre/lvfs"}, + {"fsfilt_snap_ext3", "lustre/lvfs"}, {"fsfilt_extN", "lustre/lvfs"}, {"fsfilt_reiserfs", "lustre/lvfs"}, {"fsfilt_smfs", "lustre/lvfs"}, + {"fsfilt_snap_smfs", "lustre/lvfs"}, {"ptlbd", "lustre/ptlbd"}, {"mgmt_svc", "lustre/mgmt"}, {"mgmt_cli", "lustre/mgmt"}, diff --git a/lustre/smfs/Makefile.in b/lustre/smfs/Makefile.in index 8dda735..8586c58 100644 --- a/lustre/smfs/Makefile.in +++ b/lustre/smfs/Makefile.in @@ -1,6 +1,6 @@ MODULES := smfs smfs-objs := super.o options.o inode.o cache.o cache_space.o dir.o ioctl.o smfs-objs += sysctl.o file.o symlink.o sm_fs.o kml.o journal.o smfs_llog.o -smfs-objs += mds_kml.o ost_kml.o - +smfs-objs += mds_kml.o ost_kml.o +@SNAPFS_TRUE@smfs-objs += smfs_cow.o @INCLUDE_RULES@ diff --git a/lustre/smfs/dir.c b/lustre/smfs/dir.c index 89acd05..4a3c943 100644 --- a/lustre/smfs/dir.c +++ b/lustre/smfs/dir.c @@ -67,7 +67,7 @@ static int smfs_create(struct inode *dir, struct dentry *dentry, SMFS_CACHE_HOOK_PRE(CACHE_HOOK_CREATE, handle, dir); - cache_parent = pre_smfs_dentry(NULL, cache_dir, dentry); + cache_parent = pre_smfs_dentry(NULL, cache_dir, dentry); cache_dentry = pre_smfs_dentry(cache_parent, NULL, dentry); lock_kernel(); @@ -76,6 +76,8 @@ static int smfs_create(struct inode *dir, struct dentry *dentry, pre_smfs_inode(dir, cache_dir); + SMFS_PRE_COW(dir, dentry, REINT_CREATE, "create", rc, exit); + #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, @@ -98,6 +100,7 @@ static int smfs_create(struct inode *dir, struct dentry *dentry, post_smfs_inode(dir, cache_dir); /*Do KML post hook*/ + SMFS_KML_POST(dir, dentry, NULL, NULL, REINT_CREATE, "create", rc, exit); SMFS_CACHE_HOOK_POST(CACHE_HOOK_CREATE, handle, dir, dentry, @@ -133,7 +136,7 @@ static struct dentry *smfs_lookup(struct inode *dir, struct dentry *dentry, handle = smfs_trans_start(dir, KML_CACHE_NOOP, NULL); if (IS_ERR(handle)) - RETURN(ERR_PTR(-ENOSPC)); + RETURN(ERR_PTR(-ENOSPC)); SMFS_CACHE_HOOK_PRE(CACHE_HOOK_LOOKUP, handle, dir); diff --git a/lustre/smfs/smfs_cow.c b/lustre/smfs/smfs_cow.c new file mode 100644 index 0000000..5b611fb --- /dev/null +++ b/lustre/smfs/smfs_cow.c @@ -0,0 +1,318 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * Copyright (C) 2004 Cluster File Systems, Inc. + * + * This file is part of Lustre, http://www.lustre.org. + * + * Lustre is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * Lustre is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Lustre; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#define DEBUG_SUBSYSTEM S_SM + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "smfs_internal.h" +#define SNAPTABLE_SIZE(size) (sizeof(struct snap_table) + size * sizeof(struct snap)) +static int smfs_init_snaptabe(struct super_block *sb) +{ + struct snap_info *snap_info = S2SNAPI(sb); + struct fsfilt_operations *snapops; + int rc = 0, size, table_size, vallen; + + ENTRY; + + init_MUTEX(&snap_info->sntbl_sema); + /*Initialized table */ + /*get the maxsize of snaptable*/ + vallen = sizeof(int); + rc = snapops->fs_get_snap_info(sb, NULL, MAX_SNAPTABLE_COUNT, + strlen(MAX_SNAPTABLE_COUNT), &size, + &vallen); + if (size == 0) { + CERROR("the Max snaptable count should not be zero\n"); + RETURN(-EINVAL); + } + + table_size = SNAPTABLE_SIZE(size); + + OBD_ALLOC(snap_info->sntbl, table_size); + + if (!snap_info->sntbl) { + CERROR("No MEM\n"); + RETURN(-ENOMEM); + } + /*get snaptable info*/ + rc = snapops->fs_get_snap_info(sb, NULL, SNAPTABLE_INFO, + strlen(SNAPTABLE_INFO), + snap_info->sntbl, &table_size); + + if (rc < 0) { + if (rc == -ENOATTR) { + snap_info->sntbl->sntbl_count = 1; + CDEBUG(D_INFO, "No snaptable here\n"); + RETURN(0); + } else { + CERROR("Can not retrive the snaptable from this filesystem\n"); + OBD_FREE(snap_info->sntbl, table_size); + RETURN(rc); + } + } + if (le32_to_cpu(snap_info->sntbl->sntbl_magic) != SNAP_TABLE_MAGIC) { + CERROR("On disk snaptable is not right \n"); + OBD_FREE(snap_info->sntbl, table_size); + RETURN(-EIO); + } + snap_info->sntbl->sntbl_max_count = size; + + return 0; +} + +int smfs_cow_init(struct super_block *sb) +{ + struct smfs_super_info *smfs_info = S2SMI(sb); + struct inode *inode = sb->s_root->d_inode; + int rc = 0; + + SMFS_SET_COW(smfs_info); + SMFS_SET_INODE_COW(inode); + + OBD_ALLOC(smfs_info->smsi_snap_info, sizeof(struct snap_info)); + + if (!smfs_info->smsi_snap_info) + RETURN(-ENOMEM); + + /*init snap fsfilt operations*/ + if (!S2SNAPI(sb)->snap_cache_fsfilt) { + char *snap_cache_ftype = NULL; + int tmp = strlen(S2SMI(sb)->smsi_cache_ftype) + strlen("_snap"); + + OBD_ALLOC(snap_cache_ftype, tmp + 1); + sprintf(snap_cache_ftype, "%s_snap", S2SMI(sb)->smsi_cache_ftype); + S2SNAPI(sb)->snap_cache_fsfilt = fsfilt_get_ops(snap_cache_ftype); + OBD_FREE(snap_cache_ftype, tmp + 1); + if (!S2SNAPI(sb)->snap_cache_fsfilt) { + CERROR("Can not get %s fsfilt ops needed by snap\n", + snap_cache_ftype); + RETURN(-EINVAL); + } + } + if (!S2SNAPI(sb)->snap_fsfilt) { + char *snap_ftype = NULL; + int tmp = strlen(S2SMI(sb)->smsi_ftype) + strlen("_snap"); + + OBD_ALLOC(snap_ftype, tmp + 1); + sprintf(snap_ftype, "%s_snap", S2SMI(sb)->smsi_ftype); + S2SNAPI(sb)->snap_fsfilt = fsfilt_get_ops(snap_ftype); + OBD_FREE(snap_ftype, tmp + 1); + if (!S2SNAPI(sb)->snap_fsfilt) { + CERROR("Can not get %s fsfilt ops needed by snap\n", + snap_ftype); + RETURN(-EINVAL); + } + } + rc = smfs_init_snaptabe(sb); + + RETURN(rc); +} + +int smfs_cow_cleanup(struct super_block *sb) +{ + struct smfs_super_info *smfs_info = S2SMI(sb); + struct snap_info *snap_info = S2SNAPI(sb); + struct inode *inode = sb->s_root->d_inode; + int rc = 0; + ENTRY; + + SMFS_CLEAN_COW(smfs_info); + SMFS_CLEAN_INODE_COW(inode); + + if (snap_info->sntbl) { + int table_size = SNAPTABLE_SIZE(snap_info->sntbl->sntbl_max_count); + OBD_FREE(snap_info->sntbl, table_size); + } + if (snap_info) + OBD_FREE(snap_info, sizeof(*snap_info)); + + RETURN(rc); +} + +/* latest snap: returns + - the index of the latest snapshot before NOW + - hence it returns 0 in case all the volume snapshots lie in the future + - this is the index where a COW will land (will be created) +*/ +void snap_last(struct super_block *sb, struct snap *snap) +{ + struct snap_info *snap_info = S2SNAPI(sb); + struct snap_table *table = snap_info->sntbl; + time_t now = CURRENT_TIME; + int i ; + + ENTRY; + /* start at the highest index in the superblock snaptime array */ + i = table->sntbl_count - 1; + + snap->sn_index = table->sntbl_items[i].sn_index; + snap->sn_time = table->sntbl_items[i].sn_time; + snap->sn_gen = table->sntbl_items[i].sn_gen; + CDEBUG(D_INFO, "index: %d, time[i]: %ld, now: %ld\n", + snap->sn_index, snap->sn_time, now); + EXIT; + return; +} + +/* + * Note: this function should be differnet with snap_do_cow. + * In smfs_do_cow, we check the EA for whether do cow for that inode. + * In smfs_needs_cow, we check whether we do need to do cow. + */ +int smfs_needs_cow(struct inode *inode) +{ + struct smfs_inode_info *smi_info = I2SMI(inode); + struct snap_inode_info *snap_info = NULL; + struct snap snap; + int index = -1; + ENTRY; + + snap_info = &(smi_info->sm_sninfo); + + snap_last(inode->i_sb, &snap); + /* decision .... if the snapshot is more recent than the object, + * then any change to the object should cause a COW. + */ + if (snap_info->sn_gen < snap.sn_gen ) + index = snap.sn_index; + + CDEBUG(D_INFO, "snap_needs_cow, ino %lu , get index %d\n", + inode->i_ino, index); + + RETURN(index); +} /* snap_needs_cow */ + +/* + * Make a copy of the data and plug a redirector in between if there + * is no redirector yet. + */ +int snap_do_cow(struct inode *inode, struct dentry *dparent, int del) +{ + struct snap_info *snap_info = S2SNAPI(inode->i_sb); + struct fsfilt_operations *snapops = snap_info->snap_fsfilt; + struct snap snap; + struct inode *ind = NULL; + + ENTRY; + + if (!snapops || !snapops->fs_create_indirect) + RETURN(-EINVAL); + + snap_last(inode->i_sb, &snap); + ind = snapops->fs_create_indirect(inode, snap.sn_index, snap.sn_gen, + dparent->d_inode, del); + if(!ind) + RETURN(-EINVAL); + + I2SMI(ind)->sm_sninfo.sn_flags = 0; + I2SMI(ind)->sm_sninfo.sn_gen = snap.sn_gen; + + iput(ind); + RETURN(0); +} + +int smfs_cow_create(struct inode *dir, struct dentry *dentry) +{ + int rc = 0; + ENTRY; + + if (smfs_needs_cow(dir) != -1) { + CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino); + if ((smfs_cow(dir, dentry->d_parent, 0))) { + CERROR("Do cow error\n"); + RETURN(-EINVAL); + } + } + RETURN(rc); +} + +int smfs_cow_setattr(struct inode *dir, struct dentry *dentry) +{ + int rc = 0; + ENTRY; + + RETURN(rc); +} + +int smfs_cow_link(struct inode *dir, struct dentry *dentry) +{ + int rc = 0; + ENTRY; + + RETURN(rc); +} + +int smfs_cow_unlink(struct inode *dir, struct dentry *dentry) +{ + int rc = 0; + ENTRY; + + RETURN(rc); +} + +int smfs_cow_rename(struct inode *dir, struct dentry *dentry) +{ + int rc = 0; + ENTRY; + + RETURN(rc); +} + +int smfs_cow_write(struct inode *dir, struct dentry *dentry) +{ + int rc = 0; + ENTRY; + + RETURN(rc); +} + +typedef int (*cow_funcs)(struct inode *dir, struct dentry *dentry); + +static cow_funcs smfs_cow_funcs[REINT_MAX + 1] = { + [REINT_SETATTR] smfs_cow_setattr, + [REINT_CREATE] smfs_cow_create, + [REINT_LINK] smfs_cow_link, + [REINT_UNLINK] smfs_cow_unlink, + [REINT_RENAME] smfs_cow_rename, + [REINT_WRITE] smfs_cow_write, +}; + +int smfs_cow(struct inode *dir, struct dentry *dentry, int op) +{ + return smfs_cow_funcs[op](dir, dentry); +} + diff --git a/lustre/smfs/smfs_internal.h b/lustre/smfs/smfs_internal.h index 2c02100..541afbf 100644 --- a/lustre/smfs/smfs_internal.h +++ b/lustre/smfs/smfs_internal.h @@ -196,7 +196,9 @@ extern int smfs_llog_add_rec(struct smfs_super_info * sinfo, void *data, /*ioctl.c*/ extern int init_smfs_psdev(void); extern void smfs_cleanup_psdev(void); +/*smfs_cow.c */ +extern int smfs_cow_init(struct super_block *sb); /* cache_space.c */ extern int do_cache_manage; struct cache_purge_queue { @@ -306,6 +308,21 @@ static inline int get_active_entry(struct inode *dir, __u64 *active_entry) GOTO(label, rc); \ } \ } +#if CONFIG_SNAP +/*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); \ + } \ +} while(0) +#else +#define SMFS_PRE_COW(dir, dentry, op, name, rc, label) +#endif #endif /*__KERNEL*/ #endif /* __LINUX_SMFS_H */ diff --git a/lustre/smfs/super.c b/lustre/smfs/super.c index 55d316a..b92eaf7 100644 --- a/lustre/smfs/super.c +++ b/lustre/smfs/super.c @@ -46,7 +46,8 @@ #include "smfs_internal.h" static char *smfs_options(char *data, char **devstr, char **namestr, - int *kml, int *cache, char **opts, int *iopen_nopriv) + int *kml, int *cache, char **opts, int *iopen_nopriv, + int *cow) { char *pos; struct option *opt_value = NULL; @@ -70,6 +71,8 @@ static char *smfs_options(char *data, char **devstr, char **namestr, } else if (!strcmp(opt_value->opt, "iopen_nopriv")) { if (iopen_nopriv != NULL) *iopen_nopriv = 1; + } else if (!strcmp(opt_value->opt, "snap")) { + *cow = 1; } else { break; } @@ -249,7 +252,7 @@ static int smfs_fill_super(struct super_block *sb, int iopen_nopriv = 0; struct inode *root_inode = NULL; - int err = 0, do_rec = 0, cache_hook = 0; + int err = 0, do_rec = 0, cache_hook = 0, do_cow = 0; char *devstr = NULL, *typestr = NULL, *opts = NULL; ENTRY; @@ -262,7 +265,7 @@ static int smfs_fill_super(struct super_block *sb, /* read and validate passed options. */ cache_data = smfs_options(data, &devstr, &typestr, &do_rec, &cache_hook, &opts, - &iopen_nopriv); + &iopen_nopriv, &do_cow); if (*cache_data) CWARN("smfs_fill_super(): options parsing stoped at " @@ -280,7 +283,7 @@ static int smfs_fill_super(struct super_block *sb, if (do_rec) smfs_rec_init(sb); if (cache_hook) cache_space_hook_init(sb); - + dget(S2CSB(sb)->s_root); root_ino = S2CSB(sb)->s_root->d_inode->i_ino; root_inode = iget(sb, root_ino); @@ -294,13 +297,9 @@ static int smfs_fill_super(struct super_block *sb, sm_umount_cache(sb); GOTO(out_err, err=-EINVAL); } - - sb->s_root = d_alloc_root(root_inode); - - if (!sb->s_root) { - sm_umount_cache(sb); - GOTO(out_err, err = -EINVAL); - } +#if CONFIG_SNAP + if (do_cow) smfs_cow_init(sb); +#endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) CDEBUG(D_SUPER, "sb %lx, &sb->u.generic_sbp: %lx\n", -- 1.8.3.1