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
{"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"},
subdir-m += ptlbd
endif # PATCHLEVEL = 4
-@SNAPFS_TRUE@subdir-m += snapfs
@INCLUDE_RULES@
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 \
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)
scripts/version_tag.pl
smfs/Makefile
smfs/autoMakefile
-snapfs/Makefile
-snapfs/autoMakefile
-snapfs/utils/Makefile
cmobd/Makefile
cmobd/autoMakefile
tests/Makefile
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))
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);
#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)
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))
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * Copyright (C) 2001-2003 Cluster File Systems, Inc. <info@clusterfs.com>
+ *
+ * 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 {
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 */
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"
(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))
#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)
#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"
}
/*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;
return 1;
return 0;
}
+
static inline int smfs_cache_hook(struct inode *inode)
{
struct smfs_super_info *smfs_info = I2CSB(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) \
{ \
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 */
--- /dev/null
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * Copyright (C) 2001-2003 Cluster File Systems, Inc. <info@clusterfs.com>
+ *
+ * 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*/
#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
#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))
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;
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);
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.
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
}
}
-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,
.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)
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;
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)
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;
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);
}
.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,
};
{"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"},
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@
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();
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,
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,
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);
--- /dev/null
+/* -*- 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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/stat.h>
+#include <linux/unistd.h>
+#include <linux/smp_lock.h>
+#include <linux/obd_class.h>
+#include <linux/obd_support.h>
+#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"
+#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);
+}
+
/*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 {
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 */
#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;
} 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;
}
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;
/* 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 "
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);
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",