diff --git a/lustre/snapfs/cache.c b/lustre/snapfs/cache.c index 68efe982772fa9667103a46f6035ed5164c02313..62cb15ba92d0a8000d1d9daedbf85f32f4c288f3 100644 --- a/lustre/snapfs/cache.c +++ b/lustre/snapfs/cache.c @@ -58,7 +58,7 @@ struct snap_cache *snap_find_cache(kdev_t dev) lh = &(snap_caches[snap_cache_hash(dev)]); list_for_each_entry(cache, lh, cache_chain) { - if ( cache->cache_dev == dev ) + if (cache->cache_dev == dev) return cache; } return NULL; diff --git a/lustre/snapfs/clonefs.c b/lustre/snapfs/clonefs.c index b4f136ca9f97f5f59f1a31734e82ec1cf689779f..2292c495d8277342602ec8656e7e2f2f967ac29c 100644 --- a/lustre/snapfs/clonefs.c +++ b/lustre/snapfs/clonefs.c @@ -422,19 +422,17 @@ struct address_space_operations clonefs_file_address_ops = { static int clonefs_readlink(struct dentry *dentry, char *buf, int len) { - int res; struct inode * cache_inode; struct inode * old_inode; + int rc = -ENOENT; ENTRY; cache_inode = clonefs_get_inode(dentry->d_inode); - res = -ENOENT; - - if ( ! cache_inode ) { + if (!cache_inode) { CDEBUG(D_INODE, "clonefs_get_inode failed, NULL\n"); - RETURN(res); + RETURN(rc); } /* XXX: shall we allocate a new dentry ? @@ -446,8 +444,8 @@ static int clonefs_readlink(struct dentry *dentry, char *buf, int len) /* set dentry inode to cache inode */ dentry->d_inode = cache_inode; - if ( cache_inode->i_op->readlink ) { - res = cache_inode->i_op->readlink(dentry, buf, len); + if (cache_inode->i_op->readlink) { + rc = cache_inode->i_op->readlink(dentry, buf, len); }else { CDEBUG(D_INODE,"NO readlink for ino %lu\n", cache_inode->i_ino); } @@ -457,21 +455,21 @@ static int clonefs_readlink(struct dentry *dentry, char *buf, int len) iput(cache_inode); - RETURN(res); + RETURN(rc); } static int clonefs_follow_link(struct dentry * dentry, struct nameidata *nd) { struct inode * cache_inode; struct inode * old_inode; - int res; + int rc = -ENOENT; ENTRY; cache_inode = clonefs_get_inode(dentry->d_inode); - if ( ! cache_inode ) { + if (!cache_inode) { CDEBUG(D_INODE, "clonefs_get_inode failed, NULL\n"); - RETURN(-ENOENT); + RETURN(rc); } /* XXX: shall we allocate a new dentry ? @@ -483,8 +481,8 @@ static int clonefs_follow_link(struct dentry * dentry, struct nameidata *nd) /* set dentry inode to cache inode */ dentry->d_inode = cache_inode; - if ( cache_inode->i_op->follow_link ) { - res = cache_inode->i_op->follow_link(dentry, nd); + if (cache_inode->i_op->follow_link) { + rc = cache_inode->i_op->follow_link(dentry, nd); } /* restore the old inode */ @@ -492,16 +490,103 @@ static int clonefs_follow_link(struct dentry * dentry, struct nameidata *nd) iput(cache_inode); - RETURN(res); + RETURN(rc); } +static ssize_t +clonefs_getxattr(struct dentry *dentry, const char *name, + void *buffer, size_t size) +{ + struct inode * cache_inode; + struct inode * old_inode; + int rc = -ENOENT; + + ENTRY; + + cache_inode = clonefs_get_inode(dentry->d_inode); + if (!cache_inode) { + CDEBUG(D_INODE, "clonefs_get_inode failed, NULL\n"); + RETURN(rc); + } + + /* XXX: shall we allocate a new dentry ? + The following is safe for ext2, etc. because ext2_follow_link + only use the inode info */ + /* save the old dentry inode */ + old_inode = dentry->d_inode; + /* set dentry inode to cache inode */ + dentry->d_inode = cache_inode; + + if (cache_inode->i_op->getxattr) { + rc = cache_inode->i_op->getxattr(dentry, name, buffer, size); + } + + /* restore the old inode */ + dentry->d_inode = old_inode; + + iput(cache_inode); + + RETURN(rc); +} +static ssize_t +clonefs_listxattr(struct dentry *dentry, char *buffer, size_t size) +{ + struct inode * cache_inode; + struct inode * old_inode; + int rc = -ENOENT; + + ENTRY; + + cache_inode = clonefs_get_inode(dentry->d_inode); + if (!cache_inode) { + CDEBUG(D_INODE, "clonefs_get_inode failed, NULL\n"); + RETURN(rc); + } + + /* XXX: shall we allocate a new dentry ? + The following is safe for ext2, etc. because ext2_follow_link + only use the inode info */ + + /* save the old dentry inode */ + old_inode = dentry->d_inode; + /* set dentry inode to cache inode */ + dentry->d_inode = cache_inode; + + if (cache_inode->i_op->listxattr) { + rc = cache_inode->i_op->listxattr(dentry, buffer, size); + } + + /* restore the old inode */ + dentry->d_inode = old_inode; + + iput(cache_inode); + + RETURN(rc); + +} struct inode_operations clonefs_symlink_inode_ops = { /*FIXME later getxattr, listxattr, * other method need to be replaced too * */ - readlink: clonefs_readlink, /* readlink */ - follow_link: clonefs_follow_link,/* follow_link */ + readlink: clonefs_readlink, /* readlink */ + follow_link: clonefs_follow_link, /* follow_link */ + getxattr: clonefs_getxattr, /* get xattr */ + listxattr: clonefs_listxattr, /* list xattr */ }; +int clonefs_mounted(struct snap_cache *cache, int index) +{ + struct snap_clone_info *clone_sb; + struct list_head *list, *end; + + end = list = &cache->cache_clone_list; + + list_for_each_entry(clone_sb, list, clone_list_entry) { + if (clone_sb->clone_index == index) + return 1; + } + return 0; +} + diff --git a/lustre/snapfs/dir.c b/lustre/snapfs/dir.c index 4db0908bbfad85ff86dddf264fad91970825bb97..d139d209f718c6dc6c0309ce7d3a8e0251634283 100644 --- a/lustre/snapfs/dir.c +++ b/lustre/snapfs/dir.c @@ -37,10 +37,13 @@ static ino_t get_parent_ino(struct inode * inode) static void d_unadd_iput(struct dentry *dentry) { + spin_lock(&dcache_lock); list_del(&dentry->d_alias); INIT_LIST_HEAD(&dentry->d_alias); list_del(&dentry->d_hash); INIT_LIST_HEAD(&dentry->d_hash); + spin_unlock(&dcache_lock); + iput(dentry->d_inode); dentry->d_inode = NULL; } @@ -76,7 +79,8 @@ static struct dentry *currentfs_lookup(struct inode * dir,struct dentry *dentry) ino = 0xF0000000 | dir->i_ino; snap = iget(dir->i_sb, ino); - CDEBUG(D_INODE, ".snap inode ino %ld, mode %o\n", snap->i_ino, snap->i_mode); + CDEBUG(D_INODE, ".snap inode ino %ld, mode %o\n", + snap->i_ino, snap->i_mode); d_add(dentry, snap); RETURN(NULL); } @@ -87,10 +91,14 @@ static struct dentry *currentfs_lookup(struct inode * dir,struct dentry *dentry) } rc = iops->lookup(dir, dentry); - if ( rc || !dentry->d_inode) { + if (rc || !dentry->d_inode || + is_bad_inode(dentry->d_inode) || + IS_ERR(dentry->d_inode)) { RETURN(NULL); } - + + CDEBUG(D_INODE, "cache inode ino %lu, mode %o\n", + dentry->d_inode->i_ino, dentry->d_inode->i_mode); /* * If we are under dotsnap, we need save extra data into * dentry->d_fsdata: For dir, we only need _this_ snapshot's index; @@ -160,13 +168,13 @@ static int currentfs_create(struct inode *dir, struct dentry *dentry, int mode) } cache = snap_find_cache(dir->i_dev); - if ( !cache ) { + if (!cache) { RETURN(-EINVAL); } handle = snap_trans_start(cache, dir, SNAP_OP_CREATE); - if ( snap_needs_cow(dir) != -1 ) { + if (snap_needs_cow(dir) != -1) { CDEBUG(D_INODE, "snap_needs_cow for ino %lu \n",dir->i_ino); snap_debug_device_fail(dir->i_dev, SNAP_OP_CREATE, 1); if ((snap_do_cow(dir, get_parent_ino(dir), 0))) { @@ -242,7 +250,12 @@ static int currentfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) CERROR("Error in currentfs_mkdir, dentry->d_inode is NULL\n"); } - snap_debug_device_fail(dir->i_dev, SNAP_OP_MKDIR, 3); + set_filter_ops(cache, dentry->d_inode); + init_filter_data(dentry->d_inode, 0); + + CDEBUG(D_INODE, "inode %lu, i_op %p\n", dentry->d_inode->i_ino, dentry->d_inode->i_op); + snap_debug_device_fail(dir->i_dev, SNAP_OP_CREATE, 3); + exit: snap_trans_commit(cache, handle); @@ -320,8 +333,11 @@ static int currentfs_symlink(struct inode *dir, struct dentry *dentry, snap_debug_device_fail(dir->i_dev, SNAP_OP_SYMLINK, 2); rc = iops->symlink(dir, dentry, symname); - snap_debug_device_fail(dir->i_dev, SNAP_OP_SYMLINK, 3); + set_filter_ops(cache, dentry->d_inode); + init_filter_data(dentry->d_inode, 0); + + snap_debug_device_fail(dir->i_dev, SNAP_OP_SYMLINK, 3); exit: snap_trans_commit(cache, handle); RETURN(rc); @@ -360,6 +376,9 @@ static int currentfs_mknod(struct inode *dir, struct dentry *dentry, int mode, snap_debug_device_fail(dir->i_dev, SNAP_OP_MKNOD, 2); rc = iops->mknod(dir, dentry, mode, rdev); + + set_filter_ops(cache, dentry->d_inode); + init_filter_data(dentry->d_inode, 0); snap_debug_device_fail(dir->i_dev, SNAP_OP_MKNOD, 3); /* XXX do we need to set the correct snap_{*}_iops */ @@ -380,7 +399,6 @@ static int currentfs_rmdir(struct inode *dir, struct dentry *dentry) off_t i_size = 0; ino_t ino = 0; int keep_inode = 0; -// struct dentry_operations *save_dop = NULL; void *handle = NULL; ENTRY; @@ -416,23 +434,10 @@ static int currentfs_rmdir(struct inode *dir, struct dentry *dentry) if (snap_needs_cow(dentry->d_inode) != -1 || snap_is_redirector(dentry->d_inode)) { snap_debug_device_fail(dir->i_dev, SNAP_OP_RMDIR, 2); - snap_do_cow (dir, get_parent_ino(dir), SNAP_CREATE_IND_DEL_PRI); + snap_do_cow (dentry->d_inode, get_parent_ino(dentry->d_inode), + SNAP_CREATE_IND_DEL_PRI); keep_inode = 1; } -#if 0 - if ( keep_inode ) { - printk("set up dentry ops, before %p\n",dentry->d_op); - save_dop = dentry->d_op; - - filter_setup_dentry_ops(cache->cache_filter, - dentry->d_op, ¤tfs_dentry_ops); - dentry->d_op = filter_c2udops(cache->cache_filter); - - printk("set up dentry ops, after %p\n",dentry->d_op); - - } - -#endif if( keep_inode && dentry->d_inode ) { ino = dentry->d_inode->i_ino; @@ -445,31 +450,20 @@ static int currentfs_rmdir(struct inode *dir, struct dentry *dentry) rc = iops->rmdir(dir, dentry); snap_debug_device_fail(dir->i_dev, SNAP_OP_RMDIR, 5); - /* XXX : check this */ -#if 0 - if ( keep_inode ) { - dentry->d_op = save_dop; - printk("restore dentry ops, now at %p\n",dentry->d_op); - } - -#endif - if( keep_inode && ino) { - inode = iget ( dir->i_sb, ino); + inode = iget (dir->i_sb, ino); if( inode) { // inode->i_ctime = i_ctime; inode->i_nlink = i_nlink; inode->i_size = i_size; mark_inode_dirty(inode); iput( inode); -#ifdef CONFIG_SNAPFS_EXT3 /* * In Ext3, rmdir() will put this inode into * orphan list, we must remove it out. It's ugly!! */ if( cache->cache_type == FILTER_FS_EXT3 ) ext3_orphan_del(handle, inode); -#endif snap_debug_device_fail(dir->i_dev, SNAP_OP_RMDIR, 6); } } @@ -698,5 +692,8 @@ struct inode_operations currentfs_dir_iops = { rmdir: currentfs_rmdir, unlink: currentfs_unlink, rename: currentfs_rename, - lookup: currentfs_lookup + lookup: currentfs_lookup, + removexattr: currentfs_removexattr, + setattr: currentfs_setattr, + setxattr: currentfs_setxattr, }; diff --git a/lustre/snapfs/file.c b/lustre/snapfs/file.c index 25eea668a9b7d8ede68c647db801c7d60dde6a4d..a8a88607565411a50a319abe2432f3f514bc5031 100644 --- a/lustre/snapfs/file.c +++ b/lustre/snapfs/file.c @@ -43,7 +43,7 @@ static int copy_back_page(struct inode *dst, char *kaddr_src, *kaddr_dst; struct snap_cache *cache; struct address_space_operations *c_aops; - struct page *src_page, *dst_page; + struct page *src_page = NULL, *dst_page = NULL; unsigned long index, offset, bytes; int err = 0; ENTRY; @@ -96,6 +96,8 @@ static int copy_back_page(struct inode *dst, flush_dcache_page(dst_page); err = c_aops->commit_write(NULL, dst_page, offset, offset + bytes); + CDEBUG(D_SNAP, "copy back pages %p index %lu src %lu dst %lu \n", + dst_page, dst_page->index, src->i_ino, dst->i_ino); if (err) goto unlock_dst_page; err = 1; @@ -132,28 +134,36 @@ static ssize_t currentfs_write (struct file *filp, const char *buf, if ( !cache ) RETURN(-EINVAL); + down(&inode->i_sem); + if ( snap_needs_cow(inode) != -1 ) { CDEBUG(D_SNAP, "snap_needs_cow for ino %lu \n",inode->i_ino); snap_do_cow(inode, filp->f_dentry->d_parent->d_inode->i_ino, 0); } fops = filter_c2cffops(cache->cache_filter); - if (!fops || !fops->write) - RETURN(-EINVAL); - + if (!fops || !fops->write) { + up(&inode->i_sem); + RETURN(-EINVAL); + } if (filp->f_flags & O_APPEND) pos = inode->i_size; else { pos = *ppos; - if (pos != *ppos) + if (pos != *ppos){ + up(&inode->i_sem); RETURN(-EINVAL); + } } - if (pos & PAGE_CACHE_MASK) { + + CDEBUG(D_SNAP, "write offset %lld count %u \n", pos, count); + + if (pos & (PAGE_CACHE_SIZE - 1)) { start[0] = pos & PAGE_CACHE_MASK; end[0] = pos; } pos += count - 1; - if ((pos+1) & PAGE_CACHE_MASK) { + if ((pos+1) & (PAGE_CACHE_SIZE - 1)) { start[1] = pos; end[1] = PAGE_CACHE_ALIGN(pos); } @@ -161,7 +171,9 @@ static ssize_t currentfs_write (struct file *filp, const char *buf, if (((start[0] >> PAGE_CACHE_SHIFT) == (start[1] >> PAGE_CACHE_SHIFT)) || pos > inode->i_size) start[1] = -1; - + + CDEBUG(D_SNAP, "copy back start[0] %ld end[0] %ld start[1] %ld end[1] %ld \n", + start[0], end[0], start[1], end[1]); for (i = 0; i < 2; i++) { if (start[i] == -1) continue; @@ -189,11 +201,14 @@ static ssize_t currentfs_write (struct file *filp, const char *buf, if (result < 0) { iput(cache_inode); rc = result; + up(&inode->i_sem); goto exit; } iput(cache_inode); } } + + up(&inode->i_sem); rc = fops->write(filp, buf, count, ppos); exit: RETURN(rc); @@ -246,7 +261,6 @@ static int currentfs_readpage(struct file *file, struct page *page) table = &snap_tables[cache->cache_snap_tableno]; for (slot = table->tbl_count - 1; slot >= 1; slot--) { - cache_inode = NULL; index = table->snap_items[slot].index; cache_inode = snap_get_indirect(inode, NULL, index); @@ -259,12 +273,19 @@ static int currentfs_readpage(struct file *file, struct page *page) if (!search_older && c_aops->bmap(cache_inode->i_mapping, block)) break; iput(cache_inode); + cache_inode = NULL; } if (pri_inode) iput(pri_inode); - if (!cache_inode ) - RETURN(-EINVAL); - + if (!cache_inode) { + CDEBUG(D_SNAP, "block %lu is a hole of inode %lu \n", + block, inode->i_ino); + memset(kmap(page), 0, PAGE_CACHE_SIZE); + flush_dcache_page(page); + GOTO(exit, rc = 0); + } + CDEBUG(D_INODE, "readpage ino %lu icount %d \n", cache_inode->i_ino, + atomic_read(&cache_inode->i_count)); down(&cache_inode->i_sem); /*Here we have changed a file to read, @@ -284,13 +305,14 @@ static int currentfs_readpage(struct file *file, struct page *page) GOTO(exit_release, rc = -EIO); memcpy(kmap(page), kmap(cache_page), PAGE_CACHE_SIZE); + flush_dcache_page(page); kunmap(cache_page); page_cache_release(cache_page); up(&cache_inode->i_sem); iput(cache_inode); - +exit: kunmap(page); SetPageUptodate(page); UnlockPage(page); @@ -315,6 +337,8 @@ struct file_operations currentfs_file_fops = { }; struct inode_operations currentfs_file_iops = { - revalidate: NULL, + setattr: currentfs_setattr, + setxattr: currentfs_setxattr, + removexattr: currentfs_removexattr, }; diff --git a/lustre/snapfs/filter.c b/lustre/snapfs/filter.c index c17a4997cb64737448d3dbed8c9deed2b5e63689..f7d6f6f1c0488f0e007319126d82c9071a24b5e4 100644 --- a/lustre/snapfs/filter.c +++ b/lustre/snapfs/filter.c @@ -239,6 +239,13 @@ void filter_setup_dir_ops(struct filter_fs *cache, u_iops->mknod = filter_iops->mknod; if (cache_iops->permission && filter_iops->permission) u_iops->permission = filter_iops->permission; + if (cache_iops->setattr && filter_iops->setattr) + u_iops->setattr = filter_iops->setattr; + if (cache_iops->setxattr && filter_iops->setxattr) + u_iops->setxattr = filter_iops->setxattr; + if (cache_iops->removexattr && filter_iops->removexattr) + u_iops->removexattr = filter_iops->removexattr; + } /* copy dir fops */ @@ -290,6 +297,12 @@ void filter_setup_file_ops(struct filter_fs *cache, if (filter_iops) { if (filter_iops->revalidate) u_iops->revalidate = filter_iops->revalidate; + if (filter_iops->removexattr) + u_iops->removexattr = filter_iops->removexattr; + if (filter_iops->setxattr) + u_iops->setxattr = filter_iops->setxattr; + if (filter_iops->setattr) + u_iops->setattr = filter_iops->setattr; } if (filter_fops) { if (filter_fops->read) @@ -337,6 +350,11 @@ void filter_setup_symlink_ops(struct filter_fs *cache, u_iops->readlink = filter_iops->readlink; if (cache_iops->follow_link && filter_iops->follow_link) u_iops->follow_link = filter_iops->follow_link; + if (cache_iops->getxattr && filter_iops->getxattr) + u_iops->getxattr = filter_iops->getxattr; + if (cache_iops->listxattr && filter_iops->listxattr) + u_iops->listxattr = filter_iops->listxattr; + } EXIT; } diff --git a/lustre/snapfs/inode.c b/lustre/snapfs/inode.c index 25619a87f5f224f1d4c47af9b6c1b80e9d33e287..97bfd464200be9c1b0dc110451c28fb1d5a79174 100644 --- a/lustre/snapfs/inode.c +++ b/lustre/snapfs/inode.c @@ -64,6 +64,8 @@ void init_filter_data(struct inode *inode, return; } snapops = filter_c2csnapops(cache->cache_filter); + + if (inode->i_filterdata) return; inode->i_filterdata = (struct filter_inode_info *) \ kmem_cache_alloc(filter_info_cache, SLAB_KERNEL); @@ -104,7 +106,95 @@ void set_filter_ops(struct snap_cache *cache, struct inode *inode) inode->i_ino, inode->i_op); } } +int currentfs_setxattr(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags) +{ + struct snap_cache *cache; + struct inode *inode = dentry->d_inode; + struct inode_operations *iops; + int rc; + + ENTRY; + + cache = snap_find_cache(inode->i_dev); + if (!cache) { + CERROR("currentfs_setxattr: cannot find cache\n"); + RETURN(-EINVAL); + } + + iops = filter_c2cfiops(cache->cache_filter); + + if (!iops || !iops->setxattr) { + RETURN(-EINVAL); + } + if ( snap_needs_cow(inode) != -1 ) { + CDEBUG(D_SNAP, "snap_needs_cow for ino %lu \n",inode->i_ino); + snap_do_cow(inode, dentry->d_parent->d_inode->i_ino, 0); + } + + rc = iops->setxattr(dentry, name, value, size, flags); + + RETURN(rc); +} +int currentfs_removexattr(struct dentry *dentry, const char *name) +{ + struct snap_cache *cache; + struct inode *inode = dentry->d_inode; + struct inode_operations *iops; + int rc; + + ENTRY; + + cache = snap_find_cache(inode->i_dev); + if (!cache) { + CERROR("currentfs_setxattr: cannot find cache\n"); + RETURN(-EINVAL); + } + + iops = filter_c2cfiops(cache->cache_filter); + + if (!iops || !iops->removexattr) { + RETURN(-EINVAL); + } + + if (snap_needs_cow(inode) != -1) { + CDEBUG(D_SNAP, "snap_needs_cow for ino %lu \n",inode->i_ino); + snap_do_cow(inode, dentry->d_parent->d_inode->i_ino, 0); + } + rc = iops->removexattr(dentry, name); + + RETURN(rc); +} + +int currentfs_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct snap_cache *cache; + struct inode *inode = dentry->d_inode; + struct inode_operations *iops; + int rc; + + ENTRY; + + cache = snap_find_cache(inode->i_dev); + if (!cache) { + CERROR("currentfs_setxattr: cannot find cache\n"); + RETURN(-EINVAL); + } + iops = filter_c2cfiops(cache->cache_filter); + + if (!iops || !iops->setattr) { + RETURN(-EINVAL); + } + if ( snap_needs_cow(inode) != -1 ) { + CDEBUG(D_SNAP, "snap_needs_cow for ino %lu \n",inode->i_ino); + snap_do_cow(inode, dentry->d_parent->d_inode->i_ino, 0); + } + + rc = iops->setattr(dentry, attr); + + RETURN(rc); +} /* Superblock operations. */ static void currentfs_read_inode(struct inode *inode) { @@ -113,7 +203,6 @@ static void currentfs_read_inode(struct inode *inode) if( !inode ) return; - CDEBUG(D_INODE, "read_inode ino %lu\n", inode->i_ino); cache = snap_find_cache(inode->i_dev); @@ -131,10 +220,14 @@ static void currentfs_read_inode(struct inode *inode) if(filter_c2csops(cache->cache_filter)) filter_c2csops(cache->cache_filter)->read_inode(inode); + CDEBUG(D_INODE, "read_inode ino %lu icount %d \n", + inode->i_ino, atomic_read(&inode->i_count)); set_filter_ops(cache, inode); /*init filter_data struct * FIXME flag should be set future*/ init_filter_data(inode, 0); + CDEBUG(D_INODE, "read_inode ino %lu icount %d \n", + inode->i_ino, atomic_read(&inode->i_count)); return; } @@ -217,3 +310,8 @@ struct super_operations currentfs_super_ops = { put_super: currentfs_put_super, clear_inode: currentfs_clear_inode, }; + + + + + diff --git a/lustre/snapfs/snapfs_internal.h b/lustre/snapfs/snapfs_internal.h index 6ce3e3eb3fcbe7a0ddf83ea2ab76cf5aa56cb7f3..da9d9927acca20db092152a37f26c1e3c3732dde 100644 --- a/lustre/snapfs/snapfs_internal.h +++ b/lustre/snapfs/snapfs_internal.h @@ -209,7 +209,7 @@ struct snap_obd_data { unsigned int snap_index;/* which snapshot is ours */ unsigned int snap_table;/* which table do we use */ }; -#define DISK_SNAPTABLE_ATTR "Snaptable" +#define DISK_SNAPTABLE_ATTR "Snaptable12" #define DISK_SNAP_TABLE_MAGIC 0x1976 struct snap_disk_table { unsigned int magic; @@ -287,6 +287,10 @@ void cleanup_filter_info_cache(void); int init_filter_info_cache(void); extern void init_filter_data(struct inode *inode, int flag); extern void set_filter_ops(struct snap_cache *cache, struct inode *inode); +extern int currentfs_setxattr(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags); +extern int currentfs_removexattr(struct dentry *dentry, const char *name); +extern int currentfs_setattr(struct dentry *dentry, struct iattr *attr); /* dir.c */ extern struct inode_operations currentfs_dir_iops; extern struct file_operations currentfs_dir_fops; @@ -306,6 +310,8 @@ extern struct dentry_operations currentfs_dentry_ops; extern int init_option(char *data); extern void cleanup_option(void); extern int get_opt(struct option **opt, char **pos); +/* clonefs.c */ +int clonefs_mounted(struct snap_cache *cache, int index); #define FILTER_DID_SUPER_OPS 0x1 #define FILTER_DID_INODE_OPS 0x2 diff --git a/lustre/snapfs/snaptable.c b/lustre/snapfs/snaptable.c index 0af46c3b6bd78d5f0db4274213613ffdcadeedf2..5759058f7db72af33e557ba62f3193ea5f68131f 100644 --- a/lustre/snapfs/snaptable.c +++ b/lustre/snapfs/snaptable.c @@ -22,22 +22,6 @@ struct snap_table snap_tables[SNAP_MAX_TABLES]; -#if 0 -static void snap_lock_table(int table_no) -{ - - spin_lock(snap_tables[table_no].tbl_lock); - -} - -static void snap_unlock_table(int table_no) -{ - - spin_unlock(snap_tables[table_no].tbl_lock); - -} -#endif - int snap_index2slot(struct snap_table *snap_table, int snap_index) { int slot; @@ -210,8 +194,10 @@ static int snaptable_add_item(struct ioc_snap_tbl_data *data) table->snap_items[count].time = CURRENT_TIME; /* find table index */ index = get_index_of_item(table, data->snaps[0].name); - if (index < 0) + if (index < 0) { + CERROR("snaptable full Or Duplicate name in snaptable\n"); GOTO(exit, rc = -EINVAL); + } table->snap_items[count].index = index; table->snap_items[count].flags = 0; @@ -285,6 +271,9 @@ static int delete_inode(struct inode *primary, void *param) } old_ind = redirect->i_ino; iput(redirect); + + /* In destroy indirect inode, we lock the primary inode here */ + down(&primary->i_sem); slot = snap_index2slot(table, index) - 1; if (slot > 0) { this_index = table->snap_items[slot].index; @@ -294,33 +283,29 @@ static int delete_inode(struct inode *primary, void *param) } else { snap_set_indirect(primary, old_ind, this_index, 0); snap_set_indirect(primary, 0, index, 0); + up(&primary->i_sem); RETURN(0); } } - - /* get the FIRST index after this and before NOW */ - /* used for destroy_indirect and block level cow */ - /* XXX fix this later, now use tbl_count, not NOW */ + delete_slot = snap_index2slot(table, index); - for (slot = table->tbl_count; slot > delete_slot; slot --) { + for (slot = table->tbl_count - 1; slot > delete_slot; slot --) { my_table[slot - delete_slot] = table->snap_items[slot].index; } - next_ind = snap_get_indirect - (primary, my_table, table->tbl_count - delete_slot ); - if (next_ind && (next_ind->i_ino == primary->i_ino)) { - iput(next_ind); - next_ind = NULL; - } + + this_index = table->tbl_count - delete_slot - 1; + next_ind = snap_get_indirect(primary, my_table, this_index); - if (next_ind && (next_ind->i_ino == old_ind)) { + if (next_ind && (next_ind->i_ino == primary->i_ino)) { iput(next_ind); next_ind = NULL; } - rc = snap_destroy_indirect(primary, index, next_ind); + up(&primary->i_sem); + if (next_ind) iput(next_ind); - + if (rc != 0) CERROR("snap_destroy_indirect(ino %lu,index %d),ret %d\n", primary->i_ino, index, rc); @@ -339,6 +324,7 @@ static int snap_delete(struct super_block *sb, struct snap_iterdata *data) /* This function will delete one item(a snapshot) in the snaptable * and will also delete the item in the disk. + * FIXME later, this should be in a transaction. */ int snaptable_delete_item(struct super_block *sb, struct snap_iterdata *data) { @@ -346,19 +332,26 @@ int snaptable_delete_item(struct super_block *sb, struct snap_iterdata *data) struct snap_disk_table *disk_snap_table; struct snapshot_operations *snapops; struct snap_cache *cache; - int tableno = data->tableno, index, i, slot, rc, count; + int tableno = data->tableno; + int index, i, del_slot, rc; if (!(cache = snap_find_cache((kdev_t)data->dev))) RETURN(-ENODEV); - snapops = filter_c2csnapops(cache->cache_filter); - if (!snapops || !snapops->set_meta_attr) - RETURN(-EINVAL); - if (tableno < 0 || tableno > SNAP_MAX_TABLES) { CERROR("invalid table number %d\n", tableno); RETURN(-EINVAL); } + + snapops = filter_c2csnapops(cache->cache_filter); + if (!snapops || !snapops->set_meta_attr) + RETURN(-EINVAL); + + index = data->index; + if (clonefs_mounted(cache, index)) { + CERROR("Please first umount this clonefs \n"); + RETURN(-EBUSY); + } /*first delete the snapshot * FIXME if snap delete error, how to handle this error*/ rc = snap_delete(sb, data); @@ -366,55 +359,63 @@ int snaptable_delete_item(struct super_block *sb, struct snap_iterdata *data) RETURN(-EINVAL); /*delete item in snaptable */ table = &snap_tables[tableno]; - index = data->index; - slot = snap_index2slot(table, index); - if (slot < 0) + del_slot = snap_index2slot(table, index); + if (del_slot < 0) RETURN(-EINVAL); down_interruptible(&table->tbl_sema); - while(slot < table->tbl_count) { - struct snap *item = &table->snap_items[slot]; - item->time = table->snap_items[slot + 1].time; - item->flags = table->snap_items[slot + 1].flags; - item->gen = table->snap_items[slot + 1].gen; - item->index = table->snap_items[slot + 1].index; - memcpy(&item->name[0], &table->snap_items[slot + 1].name[0], - SNAP_MAX_NAMELEN); - } - - table->tbl_count --; SNAP_ALLOC(disk_snap_table, sizeof(struct snap_disk_table)); - if (!disk_snap_table) + if (!disk_snap_table) { + up(&table->tbl_sema); RETURN(-ENOMEM); + } + /* we will delete the item snap_table to disk */ - + + index = del_slot; + /*Move the items after the delete slot forward one step*/ + memset(&table->snap_items[index], 0, sizeof(struct snap)); + while(index < table->tbl_count - 1) { + struct snap *item = &table->snap_items[index]; + + item->time = table->snap_items[index + 1].time; + item->flags = table->snap_items[index + 1].flags; + item->gen = table->snap_items[index + 1].gen; + item->index = table->snap_items[index + 1].index; + memcpy(&item->name[0], &table->snap_items[index + 1].name[0], + SNAP_MAX_NAMELEN); + index ++; + } + + table->tbl_count --; + disk_snap_table->magic = cpu_to_le32((__u32)DISK_SNAP_TABLE_MAGIC); - disk_snap_table->count = cpu_to_le32((__u32)table->tbl_count); - disk_snap_table->generation = cpu_to_le32((__u32)table->generation); + disk_snap_table->count = cpu_to_le32((__u32)table->tbl_count - 1); + disk_snap_table->generation = cpu_to_le32((__u32)table->generation + 1); memset(&disk_snap_table->snap_items[0], 0, SNAP_MAX * sizeof(struct snap_disk)); - count = table->tbl_count; - - for (i = 1; i <= count; i++) { - struct snap *item = &table->snap_items[i]; - disk_snap_table->snap_items[i].time = cpu_to_le64((__u64)item->time); - disk_snap_table->snap_items[i].gen = cpu_to_le32((__u32)item->gen); - disk_snap_table->snap_items[i].flags = cpu_to_le32((__u32)item->flags); - disk_snap_table->snap_items[i].index = cpu_to_le32((__u32)item->index); - memcpy(&disk_snap_table->snap_items[i].name , item->name, SNAP_MAX_NAMELEN); + for (i = 0; i < table->tbl_count - 1; i++) { + struct snap_disk *disk_item = &disk_snap_table->snap_items[i]; + struct snap *item = &table->snap_items[i+1]; + + disk_item[i].time = cpu_to_le64((__u64)item->time); + disk_item[i].gen = cpu_to_le32((__u32)item->gen); + disk_item[i].flags = cpu_to_le32((__u32)item->flags); + disk_item[i].index = cpu_to_le32((__u32)item->index); + memcpy(&disk_item[i].name , item->name, SNAP_MAX_NAMELEN); } + rc = snapops->set_meta_attr(cache->cache_sb, DISK_SNAPTABLE_ATTR, (char*)disk_snap_table, sizeof(struct snap_disk_table)); SNAP_FREE(disk_snap_table, sizeof(struct snap_disk_table)); up(&table->tbl_sema); - - RETURN(0); + RETURN(rc); } int snapfs_read_snaptable(struct snap_cache *cache, int tableno) @@ -592,13 +593,12 @@ static int delete_new_inode(struct inode *pri, void *param) ENTRY; - if(!pri) return 0; - - if(snap_is_redirector(pri)){ - EXIT; - return 0; - } + if(!pri) + RETURN(0); + if(snap_is_redirector(pri)) + RETURN(0); + data = (struct snap_iterdata*) param; if(data) { @@ -619,14 +619,12 @@ static int delete_new_inode(struct inode *pri, void *param) } pri->i_nlink = 0; } - return 0; - + RETURN(0); } static int restore_inode(struct inode *pri, void *param) { struct snap_iterdata * data; -// struct snap_cache *cache; int tableno = 0; int index = 1; @@ -640,7 +638,7 @@ static int restore_inode(struct inode *pri, void *param) ENTRY; - if(!pri) return 0; + if(!pri) RETURN(0); data = (struct snap_iterdata*) param; @@ -690,8 +688,7 @@ static int restore_inode(struct inode *pri, void *param) else { CDEBUG(D_SNAP, "ino %lu is older, don't restore\n", pri->i_ino); } - EXIT; - return 0; + RETURN(0); } //int snap_restore(struct super_block *sb, void *data) @@ -718,7 +715,7 @@ int snap_get_index_from_name(int tableno, char *name) table = &snap_tables[tableno]; - for ( slot = 0 ; slot < SNAP_MAX ; slot++ ) { + for ( slot = 0 ; slot < table->tbl_count; slot++) { if (!strcmp(&table->snap_items[slot].name[0], name)) { return table->snap_items[slot].index; } @@ -754,9 +751,11 @@ int snap_iterate_func( struct ioc_snap_tbl_data *data, unsigned int cmd) table = &snap_tables[tableno]; index = snap_get_index_from_name(tableno, data->snaps[0].name); - if (index < 0) + if (index < 0) { + CERROR("Could not find %s in snaptable\n", + data->snaps[0].name); RETURN(-EINVAL); - + } iterate_data.dev = (kdev_t)data->dev; iterate_data.index = index; iterate_data.tableno = tableno; @@ -784,7 +783,7 @@ int snap_iterate_func( struct ioc_snap_tbl_data *data, unsigned int cmd) rc = -EINVAL; break; } - RETURN(0); + RETURN(rc); } #define BUF_SIZE 1024 @@ -873,7 +872,8 @@ int snap_ioctl (struct inode * inode, struct file * filp, } */ memcpy(name, data->name, name_len); - printk("dev %d , len %d, name_len %d, find name is [%s]\n", dev, input.ioc_inlen, name_len, name); + printk("dev %d , len %d, name_len %d, find name is [%s]\n", + dev, input.ioc_inlen, name_len, name); cache = snap_find_cache(dev); if ( !cache ) { EXIT; diff --git a/lustre/snapfs/utils/snapctl.c b/lustre/snapfs/utils/snapctl.c index 78415ccaf4d7d63b5f5e7b5fad43c967dff9892d..f11bb05c5de37ff3fb756dd0a8c54dde893cc9d0 100644 --- a/lustre/snapfs/utils/snapctl.c +++ b/lustre/snapfs/utils/snapctl.c @@ -174,23 +174,13 @@ static int open_device(char *name, unsigned int dev) } return 0; } - -int snap_dev_open(int argc, char **argv) +static int open_snap_device(char *name) { struct snap_mnt *snaplist; - char *dev_name; - int rc; - - if (argc != 2) { - fprintf(stderr, "The argument count is not right \n"); - return CMD_HELP; - } - - dev_name = argv[1]; - + int rc; get_snaplist(); list_for_each_entry(snaplist, &snap_list, snap_mnt_list) { - if (!strcmp(&snaplist->device.name[0], dev_name)) { + if (!strcmp(&snaplist->device.name[0], name)) { rc = open_device(&snaplist->device.name[0], snaplist->device.dev); release_snap_list(); @@ -198,9 +188,25 @@ int snap_dev_open(int argc, char **argv) } } release_snap_list(); - fprintf(stderr, "%s are not snapdevice\n", dev_name); + fprintf(stderr, "%s are not snapdevice\n", name); return (-EINVAL); } +int snap_dev_open(int argc, char **argv) +{ + char *dev_name; + int rc; + + if (argc != 2) { + fprintf(stderr, "The argument count is not right \n"); + return CMD_HELP; + } + + dev_name = argv[1]; + rc = open_snap_device(dev_name); + if (rc) + fprintf(stderr, "%s are not snapdevice\n", dev_name); + return (rc); +} int snap_dev_list(int argc, char **argv) { struct snap_mnt *snaplist; @@ -244,6 +250,7 @@ static inline void print_snap_table(void * buf) } int snap_snap_list(int argc, char **argv) { + char *dev_name = NULL; int i, rc = 0; if (argc != 1 && argc != 2) { @@ -251,10 +258,17 @@ int snap_snap_list(int argc, char **argv) return CMD_HELP; } if (open_device_table.count == 0) { - fprintf(stderr, "Please open a snapdevice first\n"); - return (-EINVAL); + if (argc == 2) { + dev_name = argv[1]; + } + if (dev_name) { + rc = open_snap_device(dev_name); + } + if (!dev_name || rc) { + fprintf(stderr, "Please open a snapdevice first\n"); + return (-EINVAL); + } } - for (i = 0; i < open_device_table.count; i++) { struct ioc_snap_tbl_data *snap_ioc_data; @@ -281,16 +295,26 @@ int snap_snap_list(int argc, char **argv) } int snap_snap_del(int argc, char **argv) { + char *dev_name = NULL, *snap_name = NULL; int rc = 0, i; if (argc != 3 && argc !=2) { fprintf(stderr, "The argument count is not right \n"); return CMD_HELP; } - if (open_device_table.count == 0) { - fprintf(stderr, "Please open a snapdevice first\n"); - return (-EINVAL); + if (argc == 3) { + dev_name = argv[1]; + } else if (argc == 4) { + dev_name = argv[2]; + } + if (dev_name) { + rc = open_snap_device(dev_name); + } + if (!dev_name || rc) { + fprintf(stderr, "Please open a snapdevice first\n"); + return (-EINVAL); + } } for (i = 0; i < open_device_table.count; i++) { struct ioc_snap_tbl_data *snap_ioc_data; @@ -302,38 +326,53 @@ int snap_snap_del(int argc, char **argv) if (argc == 3) { snap_ioc_data->no = atoi(argv[1]); - memcpy(snap_ioc_data->snaps[0].name, - argv[2], strlen(argv[2])); + if (!snap_name) + snap_name = argv[2]; } else { snap_ioc_data->no = 0; - memcpy(snap_ioc_data->snaps[0].name, - argv[1], strlen(argv[1])); + if (!snap_name) + snap_name = argv[1]; } + memcpy(snap_ioc_data->snaps[0].name, + snap_name, strlen(snap_name)); + snap_ioc_data->snaps[0].time = time(NULL); IOC_PACK(sizeof(struct ioc_snap_tbl_data) + sizeof(struct snap)); if ((rc = ioctl(open_device_table.device[i].fd, IOC_SNAP_DELETE, buf))) { - fprintf(stderr, "del %s failed \n", argv[1]); + fprintf(stderr, "del %s failed \n", snap_name); } else { - fprintf(stderr, "del %s success\n", argv[1]); + fprintf(stderr, "del %s success\n", snap_name); } } return rc; } int snap_snap_add(int argc, char **argv) { + char *dev_name = NULL, *snap_name = NULL; int rc = 0, i; - if (argc != 3 && argc !=2) { + if (argc != 3 && argc !=2 && argc !=4) { fprintf(stderr, "The argument count is not right \n"); return CMD_HELP; } - if (open_device_table.count == 0) { - fprintf(stderr, "Please open a snapdevice first\n"); - return (-EINVAL); + if (argc == 3) { + dev_name = argv[1]; + snap_name = argv[2]; + } else if (argc == 4) { + dev_name = argv[2]; + snap_name = argv[3]; + } + if (dev_name) { + rc = open_snap_device(dev_name); + } + if (!dev_name || rc) { + fprintf(stderr, "Please open a snapdevice first\n"); + return (-EINVAL); + } } for (i = 0; i < open_device_table.count; i++) { struct ioc_snap_tbl_data *snap_ioc_data; @@ -345,22 +384,24 @@ int snap_snap_add(int argc, char **argv) if (argc == 3) { snap_ioc_data->no = atoi(argv[1]); - memcpy(snap_ioc_data->snaps[0].name, - argv[2], strlen(argv[2])); + if (!snap_name) + snap_name = argv[2]; } else { snap_ioc_data->no = 0; - memcpy(snap_ioc_data->snaps[0].name, - argv[1], strlen(argv[1])); + if (!snap_name) + snap_name = argv[1]; } + memcpy(snap_ioc_data->snaps[0].name, + snap_name, strlen(snap_name)); snap_ioc_data->snaps[0].time = time(NULL); IOC_PACK(sizeof(struct ioc_snap_tbl_data) + sizeof(struct snap)); if ((rc = ioctl(open_device_table.device[i].fd, IOC_SNAP_ADD, buf))) { - fprintf(stderr, "add %s failed \n", argv[1]); + fprintf(stderr, "add %s failed \n", snap_name); } else { - fprintf(stderr, "add %s success\n", argv[1]); + fprintf(stderr, "add %s success\n", snap_name); } } return rc;