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 flags);
- int (* fs_get_md)(struct inode *inode, void *md, int size, int flags);
+ int size);
+ int (* fs_get_md)(struct inode *inode, void *md, int size);
/* this method is needed to make IO operation fsfilt nature depend. */
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
int (* fs_get_snap_info)(struct super_block *sb, struct inode *inode,
void* key, __u32 keylen, void *val,
__u32 *vallen);
+ int (* fs_set_snap_item)(struct super_block *sb, char *name);
};
extern int fsfilt_register_ops(struct fsfilt_operations *fs_ops);
}
static inline int
fsfilt_set_md(struct obd_device *obd, struct inode *inode,
- void *handle, void *md, int size, int flags)
+ void *handle, void *md, int size)
{
- return obd->obd_fsops->fs_set_md(inode, handle, md, size, flags);
+ return obd->obd_fsops->fs_set_md(inode, handle, md, size);
}
static inline int
fsfilt_get_md(struct obd_device *obd, struct inode *inode,
- void *md, int size, int flags)
+ void *md, int size)
{
- return obd->obd_fsops->fs_get_md(inode, md, size, flags);
+ return obd->obd_fsops->fs_get_md(inode, md, size);
}
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
return obd->obd_fsops->fs_del_dir_entry(obd, dentry);
}
+static inline int
+fsfilt_set_snap_item(struct obd_device *obd, struct super_block *sb,
+ char *name)
+{
+ if (obd->obd_fsops->fs_set_snap_item)
+ return obd->obd_fsops->fs_set_snap_item(sb, name);
+ return 0;
+}
#endif /* __KERNEL__ */
#endif
(inode->i_sb->s_fs_info))->sm_cache_fsfilt)
#endif
-#define I2SNAPOPS(inode) ((S2SMI(inode->i_sb))->smsi_snap_info->snap_cache_fsfilt)
+#define I2SNAPI(inode) (&(I2SMI(inode)->sm_sninfo))
+#define I2SNAPCOPS(inode) ((S2SMI(inode->i_sb))->smsi_snap_info->snap_cache_fsfilt)
+#define I2SNAPOPS(inode) ((S2SMI(inode->i_sb))->smsi_snap_info->snap_fsfilt)
#define S2SNAPI(sb) (S2SMI(sb)->smsi_snap_info)
#define F2SMFI(file) ((struct smfs_file_info *)((file->private_data)))
#define SNAP_MAX_NAMELEN 64
#define MAX_SNAPTABLE_COUNT "MAXSnapCount"
-#define SNAP_TABLE_MAGIC 0x19760218
+#define SNAPTABLE_MAGIC 0x19760218
#define SNAPTABLE_INFO "snaptable"
#define SNAP_GENERATION "snap_generation"
struct snap {
unsigned int sn_index;
unsigned int sn_gen;
unsigned int sn_flags;
- char name[SNAP_MAX_NAMELEN];
+ char sn_name[SNAP_MAX_NAMELEN];
};
struct snap_table {
spinlock_t sntbl_lock;
struct snap_table *sntbl;
};
-
+extern int smfs_add_snap_item(struct super_block *sb, char *name);
#endif /*_LUSTRE_SNAP_H*/
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/lustre_snap.h>
+#include <linux/lustre_smfs.h>
static void *fsfilt_smfs_start(struct inode *inode, int op,
void *desc_private, int logs)
{
return rc;
}
+static int fsfilt_smfs_set_snap_item(struct super_block *sb, char *name)
+{
+ int rc = 0;
+
+ ENTRY;
+#if CONFIG_SNAPFS
+ rc = smfs_add_snap_item(sb, name);
+#endif
+ RETURN(rc);
+}
+
static struct fsfilt_operations fsfilt_smfs_ops = {
.fs_type = "smfs",
.fs_owner = THIS_MODULE,
.fs_get_ino_write_extents = fsfilt_smfs_get_ino_write_extents,
.fs_free_write_extents = fsfilt_smfs_free_extents,
.fs_write_extents = fsfilt_smfs_write_extents,
+ .fs_set_snap_item = fsfilt_smfs_set_snap_item,
+
/* FIXME-UMKA: probably fsfilt_smfs_get_op_len() should be
* put here too. */
};
rc = ext3_xattr_get(inode, EXT3_SNAP_INDEX,EXT3_SNAP_GENERATION,
(char *)val, *vallen);
+ if (rc == -ENOATTR) {
+ *((__u32 *)val) = 0;
+ *vallen = sizeof(int);
+ rc = 0;
+ }
RETURN(rc);
}
RETURN(-EINVAL);
if (keylen >= strlen(SNAPTABLE_INFO)
&& strcmp(key, SNAPTABLE_INFO) == 0) {
- struct inode *inode = sb->s_root->d_inode;
+ struct inode *root_inode = sb->s_root->d_inode;
handle_t *handle;
- handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS);
+ handle = ext3_journal_start(root_inode, EXT3_XATTR_TRANS_BLOCKS);
if( !handle )
RETURN(-EINVAL);
- rc = ext3_xattr_set(handle, inode, EXT3_SNAP_INDEX,
+ rc = ext3_xattr_set(handle, root_inode, EXT3_SNAP_INDEX,
EXT3_SNAPTABLE_EA, val, *vallen, 0);
- ext3_journal_stop(handle,inode);
+ ext3_journal_stop(handle,root_inode);
RETURN(rc);
} else if (keylen >= strlen(SNAP_GENERATION)
&& strcmp(key, SNAP_GENERATION) == 0) {
+ LASSERT(inode);
rc = ext3_set_generation(inode, *(int*)val);
RETURN(rc);
struct inode *parent,
int del)
{
- struct fsfilt_operations *snap_fsfilt = I2SNAPOPS(inode);
+ struct fsfilt_operations *snap_fsfilt = I2SNAPCOPS(inode);
struct inode *cache_inode = NULL;
struct inode *cache_parent = NULL;
struct inode *cache_ind_inode = NULL;
static struct inode* fsfilt_smfs_get_indirect(struct inode *inode,
int *table, int slot)
{
- struct fsfilt_operations *snap_fsfilt = I2SNAPOPS(inode);
+ struct fsfilt_operations *snap_fsfilt = I2SNAPCOPS(inode);
struct inode *cache_inode = NULL;
struct inode *cache_ind_inode = NULL;
struct inode *ind_inode = NULL;
static int fsfilt_smfs_set_indirect(struct inode *inode, int index,
ino_t ind_ino, ino_t parent_ino)
{
- struct fsfilt_operations *snap_fsfilt = I2SNAPOPS(inode);
+ struct fsfilt_operations *snap_fsfilt = I2SNAPCOPS(inode);
struct inode *cache_inode = NULL;
int rc = -EIO;
ENTRY;
static int fsfilt_smfs_is_redirector(struct inode *inode)
{
- struct fsfilt_operations *snap_fsfilt = I2SNAPOPS(inode);
+ struct fsfilt_operations *snap_fsfilt = I2SNAPCOPS(inode);
struct inode *cache_inode = NULL;
int rc = -EIO;
ENTRY;
}
static int fsfilt_smfs_is_indirect(struct inode *inode)
{
- struct fsfilt_operations *snap_fsfilt = I2SNAPOPS(inode);
+ struct fsfilt_operations *snap_fsfilt = I2SNAPCOPS(inode);
struct inode *cache_inode = NULL;
int rc = -EIO;
ENTRY;
}
static ino_t fsfilt_smfs_get_indirect_ino(struct inode *inode, int index)
{
- struct fsfilt_operations *snap_fsfilt = I2SNAPOPS(inode);
+ struct fsfilt_operations *snap_fsfilt = I2SNAPCOPS(inode);
struct inode *cache_inode = NULL;
int rc = -EIO;
ENTRY;
static int fsfilt_smfs_destroy_indirect(struct inode *inode, int index,
struct inode *next_ind)
{
- struct fsfilt_operations *snap_fsfilt = I2SNAPOPS(inode);
+ struct fsfilt_operations *snap_fsfilt = I2SNAPCOPS(inode);
struct inode *cache_inode = NULL;
struct inode *cache_next = NULL;
int rc = -EIO;
}
static int fsfilt_smfs_restore_indirect(struct inode *inode, int index)
{
- struct fsfilt_operations *snap_fsfilt = I2SNAPOPS(inode);
+ struct fsfilt_operations *snap_fsfilt = I2SNAPCOPS(inode);
struct inode *cache_inode = NULL;
int rc = -EIO;
ENTRY;
static int fsfilt_smfs_copy_block(struct inode *dst, struct inode *src, int blk)
{
- struct fsfilt_operations *snap_fsfilt = I2SNAPOPS(dst);
+ struct fsfilt_operations *snap_fsfilt = I2SNAPCOPS(dst);
struct inode *cache_dst = NULL;
struct inode *cache_src = NULL;
int rc = -EIO;
snap_fsfilt = S2SNAPI(sb)->snap_cache_fsfilt;
} else if (inode) {
cache_inode = I2CI(inode);
- snap_fsfilt = I2SNAPOPS(inode);
+ snap_fsfilt = I2SNAPCOPS(inode);
}
if (snap_fsfilt == NULL)
snap_fsfilt = S2SNAPI(sb)->snap_cache_fsfilt;
} else if (inode) {
cache_inode = I2CI(inode);
- snap_fsfilt = I2SNAPOPS(inode);
+ snap_fsfilt = I2SNAPCOPS(inode);
}
if (snap_fsfilt == NULL)
RETURN(rc);
}
-
struct fsfilt_operations fsfilt_smfs_snap_ops = {
.fs_type = "smfs_snap",
.fs_owner = THIS_MODULE,
OBD_FREE(cfg_buf, data->ioc_plen1);
RETURN(rc);
}
-
+ case OBD_IOC_SNAP_ADD: {
+ char *name = data->ioc_inlbuf1;
+ if (name) {
+ rc = fsfilt_set_snap_item(obd, mds->mds_sb, name);
+ }
+ RETURN(rc);
+ }
case OBD_IOC_PARSE: {
struct llog_ctxt *ctxt =
llog_get_context(&obd->obd_llogs, LLOG_CONFIG_ORIG_CTXT);
post_smfs_inode(inode, cache_inode);
sm_set_inode_ops(cache_inode, inode);
-
+#if CONFIG_SNAPFS
+ if (SMFS_DO_COW(S2SMI(inode->i_sb))) {
+ smfs_init_snap_inode_info(inode, *((int *)opaque));
+ }
+#endif
CDEBUG(D_INODE, "read_inode ino %lu icount %d \n",
inode->i_ino, atomic_read(&inode->i_count));
return;
static int smfs_init_snaptabe(struct super_block *sb)
{
struct snap_info *snap_info = S2SNAPI(sb);
- struct fsfilt_operations *snapops;
+ struct snap_table *snap_table = NULL;
+ struct fsfilt_operations *snapops = snap_info->snap_fsfilt;
int rc = 0, size, table_size, vallen;
-
+
ENTRY;
init_MUTEX(&snap_info->sntbl_sema);
CERROR("No MEM\n");
RETURN(-ENOMEM);
}
+ snap_table = snap_info->sntbl;
+
+ snap_table->sntbl_magic = cpu_to_le32((__u32)SNAPTABLE_MAGIC);
+ snap_table->sntbl_max_count = size;
/*get snaptable info*/
+
rc = snapops->fs_get_snap_info(sb, NULL, SNAPTABLE_INFO,
strlen(SNAPTABLE_INFO),
- snap_info->sntbl, &table_size);
-
+ snap_table, &table_size);
if (rc < 0) {
if (rc == -ENOATTR) {
- snap_info->sntbl->sntbl_count = 1;
+ snap_table->sntbl_count = 0;
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);
+ OBD_FREE(snap_table, table_size);
RETURN(rc);
}
}
- if (le32_to_cpu(snap_info->sntbl->sntbl_magic) != SNAP_TABLE_MAGIC) {
+ if (le32_to_cpu(snap_table->sntbl_magic) != SNAPTABLE_MAGIC) {
CERROR("On disk snaptable is not right \n");
- OBD_FREE(snap_info->sntbl, table_size);
+ OBD_FREE(snap_table, table_size);
RETURN(-EIO);
}
- snap_info->sntbl->sntbl_max_count = size;
-
- return 0;
+ RETURN(rc);
}
int smfs_cow_init(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;
+ struct snap_table *snap_table = snap_info->sntbl;
+ int rc = 0, table_size;
ENTRY;
SMFS_CLEAN_COW(smfs_info);
- SMFS_CLEAN_INODE_COW(inode);
+
+ if (snap_info->snap_fsfilt)
+ fsfilt_put_ops(snap_info->snap_fsfilt);
+ if (snap_info->snap_cache_fsfilt)
+ fsfilt_put_ops(snap_info->snap_cache_fsfilt);
- if (snap_info->sntbl) {
- int table_size = SNAPTABLE_SIZE(snap_info->sntbl->sntbl_max_count);
+ if (snap_table) {
+ table_size = SNAPTABLE_SIZE(snap_table->sntbl_max_count);
OBD_FREE(snap_info->sntbl, table_size);
}
if (snap_info)
RETURN(rc);
}
+/*FIXME Note indirect and primary inode
+* should be recorgnized here*/
+int smfs_init_snap_inode_info(struct inode *inode, int flags)
+{
+ struct snap_inode_info *sni_info = I2SNAPI(inode);
+ struct fsfilt_operations *snapops = I2SNAPOPS(inode);
+ int vallen, rc = 0;
+ ENTRY;
+
+ sni_info->sn_flags = flags;
+ vallen = sizeof(sni_info->sn_gen);
+
+ rc = snapops->fs_get_snap_info(NULL, inode, SNAP_GENERATION,
+ strlen(SNAP_GENERATION),
+ &sni_info->sn_gen, &vallen);
+
+ 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
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;
+ if (table->sntbl_count == 0) {
+ memset(snap, 0, sizeof(struct snap));
+ } else {
+ 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;
}
+static int inline get_index_of_item(struct snap_table *table, char *name)
+{
+ int count = table->sntbl_count;
+ int i, j;
+ ENTRY;
+
+ for (i = 0; i < table->sntbl_max_count; i++) {
+ if (!strcmp(name, table->sntbl_items[i].sn_name)) {
+ CERROR("Duplicate name %s in snaptable\n", name);
+ RETURN(-EINVAL);
+ }
+ }
+
+ for (i = 0; i < table->sntbl_max_count; i++) {
+ int found = 0;
+ for (j = 0; j < (count + 1); j++) {
+ if (table->sntbl_items[j].sn_index == i) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ RETURN(i);
+ }
+ CERROR("snaptable Full\n");
+ RETURN(-ENOSPC);
+}
+
+int smfs_add_snap_item(struct super_block *sb, char *name)
+{
+ struct snap_info *snap_info = S2SNAPI(sb);
+ struct fsfilt_operations *snapops = snap_info->snap_fsfilt;
+ struct snap_table *snap_table = snap_info->sntbl;
+ struct snap *snap_item;
+ int table_size, count = 0, index = 0, rc = 0;
+
+ count = snap_table->sntbl_count + 1;
+ /* XXX Is down this sema necessary*/
+ down_interruptible(&snap_info->sntbl_sema);
+ snap_item = &snap_table->sntbl_items[count];
+
+ /*add item in snap_table set generation*/
+ snap_item->sn_time = CURRENT_TIME;
+ /* find table index */
+ index = get_index_of_item(snap_table, name);
+ if (index < 0)
+ GOTO(exit, rc = index);
+
+ snap_item->sn_index = index;
+ snap_item->sn_flags = 0;
+ snap_item->sn_gen = snap_table->sntbl_generation + 1;
+ memcpy(snap_item->sn_name, name, SNAP_MAX_NAMELEN);
+ /* Wrote the whole snap_table to disk */
+ table_size = SNAPTABLE_SIZE(snap_table->sntbl_max_count);
+
+ rc = snapops->fs_set_snap_info(sb, NULL, SNAPTABLE_INFO,
+ strlen(SNAPTABLE_INFO),
+ snap_table, &table_size);
+ if (rc) {
+ CERROR("Set snaptable error rc=%d\n", rc);
+ GOTO(exit, rc);
+ }
+ snap_table->sntbl_count++;
+ snap_table->sntbl_generation++;
+exit:
+ up(&snap_info->sntbl_sema);
+ RETURN(rc);
+
+}
+EXPORT_SYMBOL(smfs_add_snap_item);
/*
* 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.
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
+#if CONFIG_SNAPFS
/*snap macros*/
#define SMFS_PRE_COW(dir, dentry, op, name, rc, label) \
do { \
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)
#endif
cache_space_hook_exit(sb);
if (SMFS_DO_REC(S2SMI(sb)))
smfs_rec_cleanup(sb);
+#if CONFIG_SNAPFS
+ if (SMFS_DO_COW(S2SMI(sb)))
+ smfs_cow_cleanup(sb);
+#endif
if (sb)
sm_umount_cache(sb);
return;
sm_umount_cache(sb);
GOTO(out_err, err=-EINVAL);
}
-#if CONFIG_SNAP
+#if CONFIG_SNAPFS
if (do_cow) smfs_cow_init(sb);
#endif
--- /dev/null
+#!/bin/bash
+
+MDSDEV=smfs OSTDEV=smfs FSTYPE=smfs MDS_MOUNT_OPTS="kml,snap" OST_MOUNT_OPTS="kml,snap" \
+OSTSIZE=100000 MDSSIZE=50000 MDS_BACKFSTYPE=ext3 OST_BACKFSTYPE=ext3 \
+MDS_BACKDEV=/tmp/mds1-$(hostname) OST_BACKDEV=/tmp/ost1-$(hostname) sh llmount.sh
"usage: lsync\n"},
{"cache_off", jt_obd_cache_off, 0,
"usage: lsync\n"},
+ /*snap operations*/
+ {"snap_add", jt_obd_snap_add, 0, "usage: snap_add <snap_name>\n"},
/* Llog operations */
{"llog_catlist", jt_llog_catlist, 0,
"list all catalog logs on current device.\n"
rc);
return rc;
}
+int jt_obd_snap_add(int argc, char **argv)
+{
+ struct obd_ioctl_data data;
+ int rc = 0;
+
+ if (argc != 2)
+ return CMD_HELP;
+ IOC_INIT(data);
+
+ data.ioc_inllen1 = strlen(argv[1]) + 1;
+ data.ioc_inlbuf1 = argv[1];
+ IOC_PACK(argv[0], data);
+
+ rc = l_ioctl(OBD_DEV_ID, OBD_IOC_SNAP_ADD, buf);
+
+ if (rc)
+ fprintf(stderr, "OBD_IOC_SNAP_ADD failed: rc=%d\n", rc);
+ return rc;
+}
static void signal_server(int sig)
{
if (sig == SIGINT) {