Message ID | 4D8712E9.108@cn.fujitsu.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Hello, I would like to ask about the status of this feature/patch, is it accepted into btrfs code, and how can I use it? I am interested in enabling compression in a specific folder(force-compress would be ideal) of a large btrfs volume, and disabling it for the rest. On 21/3/2011 10:57 ??, liubo wrote: > Data compression and data cow are controlled across the entire FS by mount > options right now. ioctls are needed to set this on a per file or per > directory basis. This has been proposed previously, but VFS developers > wanted us to use generic ioctls rather than btrfs-specific ones. > > According to chris's comment, there should be just one true compression > method(probably LZO) stored in the super. However, before this, we would > wait for that one method is stable enough to be adopted into the super. > So I list it as a long term goal, and just store it in ram today. > > After applying this patch, we can use the generic "FS_IOC_SETFLAGS" ioctl to > control file and directory's datacow and compression attribute. > > NOTE: > - The compression type is selected by such rules: > If we mount btrfs with compress options, ie, zlib/lzo, the type is it. > Otherwise, we'll use the default compress type (zlib today). > > v1->v2: > Rebase the patch with the latest btrfs. > > Signed-off-by: Liu Bo<liubo2009@cn.fujitsu.com> > --- > fs/btrfs/ctree.h | 1 + > fs/btrfs/disk-io.c | 6 ++++++ > fs/btrfs/inode.c | 32 ++++++++++++++++++++++++++++---- > fs/btrfs/ioctl.c | 41 +++++++++++++++++++++++++++++++++++++---- > 4 files changed, 72 insertions(+), 8 deletions(-) > > diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h > index 8b4b9d1..b77d1a5 100644 > --- a/fs/btrfs/ctree.h > +++ b/fs/btrfs/ctree.h > @@ -1283,6 +1283,7 @@ struct btrfs_root { > #define BTRFS_INODE_NODUMP (1<< 8) > #define BTRFS_INODE_NOATIME (1<< 9) > #define BTRFS_INODE_DIRSYNC (1<< 10) > +#define BTRFS_INODE_COMPRESS (1<< 11) > > /* some macros to generate set/get funcs for the struct fields. This > * assumes there is a lefoo_to_cpu for every type, so lets make a simple > diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c > index 3e1ea3e..a894c12 100644 > --- a/fs/btrfs/disk-io.c > +++ b/fs/btrfs/disk-io.c > @@ -1762,6 +1762,12 @@ struct btrfs_root *open_ctree(struct super_block *sb, > > btrfs_check_super_valid(fs_info, sb->s_flags& MS_RDONLY); > > + /* > + * In the long term, we'll store the compression type in the super > + * block, and it'll be used for per file compression control. > + */ > + fs_info->compress_type = BTRFS_COMPRESS_ZLIB; > + > ret = btrfs_parse_options(tree_root, options); > if (ret) { > err = ret; > diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c > index db67821..e687bb9 100644 > --- a/fs/btrfs/inode.c > +++ b/fs/btrfs/inode.c > @@ -381,7 +381,8 @@ again: > */ > if (!(BTRFS_I(inode)->flags& BTRFS_INODE_NOCOMPRESS)&& > (btrfs_test_opt(root, COMPRESS) || > - (BTRFS_I(inode)->force_compress))) { > + (BTRFS_I(inode)->force_compress) || > + (BTRFS_I(inode)->flags& BTRFS_INODE_COMPRESS))) { > WARN_ON(pages); > pages = kzalloc(sizeof(struct page *) * nr_pages, GFP_NOFS); > > @@ -1253,7 +1254,8 @@ static int run_delalloc_range(struct inode *inode, struct page *locked_page, > ret = run_delalloc_nocow(inode, locked_page, start, end, > page_started, 0, nr_written); > else if (!btrfs_test_opt(root, COMPRESS)&& > - !(BTRFS_I(inode)->force_compress)) > + !(BTRFS_I(inode)->force_compress)&& > + !(BTRFS_I(inode)->flags& BTRFS_INODE_COMPRESS)) > ret = cow_file_range(inode, locked_page, start, end, > page_started, nr_written, 1); > else > @@ -4581,8 +4583,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, > location->offset = 0; > btrfs_set_key_type(location, BTRFS_INODE_ITEM_KEY); > > - btrfs_inherit_iflags(inode, dir); > - > if ((mode& S_IFREG)) { > if (btrfs_test_opt(root, NODATASUM)) > BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM; > @@ -4590,6 +4590,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, > BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW; > } > > + btrfs_inherit_iflags(inode, dir); > + > insert_inode_hash(inode); > inode_tree_add(inode); > return inode; > @@ -6803,6 +6805,26 @@ static int btrfs_getattr(struct vfsmount *mnt, > return 0; > } > > +/* > + * If a file is moved, it will inherit the cow and compression flags of the new > + * directory. > + */ > +static void fixup_inode_flags(struct inode *dir, struct inode *inode) > +{ > + struct btrfs_inode *b_dir = BTRFS_I(dir); > + struct btrfs_inode *b_inode = BTRFS_I(inode); > + > + if (b_dir->flags& BTRFS_INODE_NODATACOW) > + b_inode->flags |= BTRFS_INODE_NODATACOW; > + else > + b_inode->flags&= ~BTRFS_INODE_NODATACOW; > + > + if (b_dir->flags& BTRFS_INODE_COMPRESS) > + b_inode->flags |= BTRFS_INODE_COMPRESS; > + else > + b_inode->flags&= ~BTRFS_INODE_COMPRESS; > +} > + > static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, > struct inode *new_dir, struct dentry *new_dentry) > { > @@ -6936,6 +6958,8 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, > } > } > > + fixup_inode_flags(new_dir, old_inode); > + > ret = btrfs_add_link(trans, new_dir, old_inode, > new_dentry->d_name.name, > new_dentry->d_name.len, 0, index); > diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c > index 5fdb2ab..93e7f6c 100644 > --- a/fs/btrfs/ioctl.c > +++ b/fs/btrfs/ioctl.c > @@ -138,6 +138,24 @@ static int btrfs_ioctl_getflags(struct file *file, void __user *arg) > return 0; > } > > +static int check_flags(unsigned int flags) > +{ > + if (flags& ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ > + FS_NOATIME_FL | FS_NODUMP_FL | \ > + FS_SYNC_FL | FS_DIRSYNC_FL | \ > + FS_NOCOMP_FL | FS_COMPR_FL | \ > + FS_NOCOW_FL | FS_COW_FL)) > + return -EOPNOTSUPP; > + > + if ((flags& FS_NOCOMP_FL)&& (flags& FS_COMPR_FL)) > + return -EINVAL; > + > + if ((flags& FS_NOCOW_FL)&& (flags& FS_COW_FL)) > + return -EINVAL; > + > + return 0; > +} > + > static int btrfs_ioctl_setflags(struct file *file, void __user *arg) > { > struct inode *inode = file->f_path.dentry->d_inode; > @@ -153,10 +171,9 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) > if (copy_from_user(&flags, arg, sizeof(flags))) > return -EFAULT; > > - if (flags& ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ > - FS_NOATIME_FL | FS_NODUMP_FL | \ > - FS_SYNC_FL | FS_DIRSYNC_FL)) > - return -EOPNOTSUPP; > + ret = check_flags(flags); > + if (ret) > + return ret; > > if (!is_owner_or_cap(inode)) > return -EACCES; > @@ -201,6 +218,22 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) > else > ip->flags&= ~BTRFS_INODE_DIRSYNC; > > + /* > + * The COMPRESS flag can only be changed by users, while the NOCOMPRESS > + * flag may be changed automatically if compression code won't make > + * things smaller. > + */ > + if (flags& FS_NOCOMP_FL) { > + ip->flags&= ~BTRFS_INODE_COMPRESS; > + ip->flags |= BTRFS_INODE_NOCOMPRESS; > + } else if (flags& FS_COMPR_FL) { > + ip->flags |= BTRFS_INODE_COMPRESS; > + ip->flags&= ~BTRFS_INODE_NOCOMPRESS; > + } > + if (flags& FS_NOCOW_FL) > + ip->flags |= BTRFS_INODE_NODATACOW; > + else if (flags& FS_COW_FL) > + ip->flags&= ~BTRFS_INODE_NODATACOW; > > trans = btrfs_join_transaction(root, 1); > BUG_ON(IS_ERR(trans)); -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 04/04/2011 05:31 PM, Konstantinos Skarlatos wrote: > Hello, > I would like to ask about the status of this feature/patch, is it > accepted into btrfs code, and how can I use it? > Yes, it is now in the latest 2.6.39-rc1. > I am interested in enabling compression in a specific > folder(force-compress would be ideal) of a large btrfs volume, and > disabling it for the rest. > hmm, I'm making the tool's patch, and will come soon. :) > > On 21/3/2011 10:57 ??, liubo wrote: >> Data compression and data cow are controlled across the entire FS by >> mount >> options right now. ioctls are needed to set this on a per file or per >> directory basis. This has been proposed previously, but VFS developers >> wanted us to use generic ioctls rather than btrfs-specific ones. >> >> According to chris's comment, there should be just one true compression >> method(probably LZO) stored in the super. However, before this, we would >> wait for that one method is stable enough to be adopted into the super. >> So I list it as a long term goal, and just store it in ram today. >> >> After applying this patch, we can use the generic "FS_IOC_SETFLAGS" >> ioctl to >> control file and directory's datacow and compression attribute. >> >> NOTE: >> - The compression type is selected by such rules: >> If we mount btrfs with compress options, ie, zlib/lzo, the type is >> it. >> Otherwise, we'll use the default compress type (zlib today). >> >> v1->v2: >> Rebase the patch with the latest btrfs. >> >> Signed-off-by: Liu Bo<liubo2009@cn.fujitsu.com> >> --- >> fs/btrfs/ctree.h | 1 + >> fs/btrfs/disk-io.c | 6 ++++++ >> fs/btrfs/inode.c | 32 ++++++++++++++++++++++++++++---- >> fs/btrfs/ioctl.c | 41 +++++++++++++++++++++++++++++++++++++---- >> 4 files changed, 72 insertions(+), 8 deletions(-) >> >> diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h >> index 8b4b9d1..b77d1a5 100644 >> --- a/fs/btrfs/ctree.h >> +++ b/fs/btrfs/ctree.h >> @@ -1283,6 +1283,7 @@ struct btrfs_root { >> #define BTRFS_INODE_NODUMP (1<< 8) >> #define BTRFS_INODE_NOATIME (1<< 9) >> #define BTRFS_INODE_DIRSYNC (1<< 10) >> +#define BTRFS_INODE_COMPRESS (1<< 11) >> >> /* some macros to generate set/get funcs for the struct fields. This >> * assumes there is a lefoo_to_cpu for every type, so lets make a >> simple >> diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c >> index 3e1ea3e..a894c12 100644 >> --- a/fs/btrfs/disk-io.c >> +++ b/fs/btrfs/disk-io.c >> @@ -1762,6 +1762,12 @@ struct btrfs_root *open_ctree(struct >> super_block *sb, >> >> btrfs_check_super_valid(fs_info, sb->s_flags& MS_RDONLY); >> >> + /* >> + * In the long term, we'll store the compression type in the super >> + * block, and it'll be used for per file compression control. >> + */ >> + fs_info->compress_type = BTRFS_COMPRESS_ZLIB; >> + >> ret = btrfs_parse_options(tree_root, options); >> if (ret) { >> err = ret; >> diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c >> index db67821..e687bb9 100644 >> --- a/fs/btrfs/inode.c >> +++ b/fs/btrfs/inode.c >> @@ -381,7 +381,8 @@ again: >> */ >> if (!(BTRFS_I(inode)->flags& BTRFS_INODE_NOCOMPRESS)&& >> (btrfs_test_opt(root, COMPRESS) || >> - (BTRFS_I(inode)->force_compress))) { >> + (BTRFS_I(inode)->force_compress) || >> + (BTRFS_I(inode)->flags& BTRFS_INODE_COMPRESS))) { >> WARN_ON(pages); >> pages = kzalloc(sizeof(struct page *) * nr_pages, GFP_NOFS); >> >> @@ -1253,7 +1254,8 @@ static int run_delalloc_range(struct inode >> *inode, struct page *locked_page, >> ret = run_delalloc_nocow(inode, locked_page, start, end, >> page_started, 0, nr_written); >> else if (!btrfs_test_opt(root, COMPRESS)&& >> - !(BTRFS_I(inode)->force_compress)) >> + !(BTRFS_I(inode)->force_compress)&& >> + !(BTRFS_I(inode)->flags& BTRFS_INODE_COMPRESS)) >> ret = cow_file_range(inode, locked_page, start, end, >> page_started, nr_written, 1); >> else >> @@ -4581,8 +4583,6 @@ static struct inode *btrfs_new_inode(struct >> btrfs_trans_handle *trans, >> location->offset = 0; >> btrfs_set_key_type(location, BTRFS_INODE_ITEM_KEY); >> >> - btrfs_inherit_iflags(inode, dir); >> - >> if ((mode& S_IFREG)) { >> if (btrfs_test_opt(root, NODATASUM)) >> BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM; >> @@ -4590,6 +4590,8 @@ static struct inode *btrfs_new_inode(struct >> btrfs_trans_handle *trans, >> BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW; >> } >> >> + btrfs_inherit_iflags(inode, dir); >> + >> insert_inode_hash(inode); >> inode_tree_add(inode); >> return inode; >> @@ -6803,6 +6805,26 @@ static int btrfs_getattr(struct vfsmount *mnt, >> return 0; >> } >> >> +/* >> + * If a file is moved, it will inherit the cow and compression flags >> of the new >> + * directory. >> + */ >> +static void fixup_inode_flags(struct inode *dir, struct inode *inode) >> +{ >> + struct btrfs_inode *b_dir = BTRFS_I(dir); >> + struct btrfs_inode *b_inode = BTRFS_I(inode); >> + >> + if (b_dir->flags& BTRFS_INODE_NODATACOW) >> + b_inode->flags |= BTRFS_INODE_NODATACOW; >> + else >> + b_inode->flags&= ~BTRFS_INODE_NODATACOW; >> + >> + if (b_dir->flags& BTRFS_INODE_COMPRESS) >> + b_inode->flags |= BTRFS_INODE_COMPRESS; >> + else >> + b_inode->flags&= ~BTRFS_INODE_COMPRESS; >> +} >> + >> static int btrfs_rename(struct inode *old_dir, struct dentry >> *old_dentry, >> struct inode *new_dir, struct dentry *new_dentry) >> { >> @@ -6936,6 +6958,8 @@ static int btrfs_rename(struct inode *old_dir, >> struct dentry *old_dentry, >> } >> } >> >> + fixup_inode_flags(new_dir, old_inode); >> + >> ret = btrfs_add_link(trans, new_dir, old_inode, >> new_dentry->d_name.name, >> new_dentry->d_name.len, 0, index); >> diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c >> index 5fdb2ab..93e7f6c 100644 >> --- a/fs/btrfs/ioctl.c >> +++ b/fs/btrfs/ioctl.c >> @@ -138,6 +138,24 @@ static int btrfs_ioctl_getflags(struct file >> *file, void __user *arg) >> return 0; >> } >> >> +static int check_flags(unsigned int flags) >> +{ >> + if (flags& ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ >> + FS_NOATIME_FL | FS_NODUMP_FL | \ >> + FS_SYNC_FL | FS_DIRSYNC_FL | \ >> + FS_NOCOMP_FL | FS_COMPR_FL | \ >> + FS_NOCOW_FL | FS_COW_FL)) >> + return -EOPNOTSUPP; >> + >> + if ((flags& FS_NOCOMP_FL)&& (flags& FS_COMPR_FL)) >> + return -EINVAL; >> + >> + if ((flags& FS_NOCOW_FL)&& (flags& FS_COW_FL)) >> + return -EINVAL; >> + >> + return 0; >> +} >> + >> static int btrfs_ioctl_setflags(struct file *file, void __user *arg) >> { >> struct inode *inode = file->f_path.dentry->d_inode; >> @@ -153,10 +171,9 @@ static int btrfs_ioctl_setflags(struct file >> *file, void __user *arg) >> if (copy_from_user(&flags, arg, sizeof(flags))) >> return -EFAULT; >> >> - if (flags& ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ >> - FS_NOATIME_FL | FS_NODUMP_FL | \ >> - FS_SYNC_FL | FS_DIRSYNC_FL)) >> - return -EOPNOTSUPP; >> + ret = check_flags(flags); >> + if (ret) >> + return ret; >> >> if (!is_owner_or_cap(inode)) >> return -EACCES; >> @@ -201,6 +218,22 @@ static int btrfs_ioctl_setflags(struct file >> *file, void __user *arg) >> else >> ip->flags&= ~BTRFS_INODE_DIRSYNC; >> >> + /* >> + * The COMPRESS flag can only be changed by users, while the >> NOCOMPRESS >> + * flag may be changed automatically if compression code won't make >> + * things smaller. >> + */ >> + if (flags& FS_NOCOMP_FL) { >> + ip->flags&= ~BTRFS_INODE_COMPRESS; >> + ip->flags |= BTRFS_INODE_NOCOMPRESS; >> + } else if (flags& FS_COMPR_FL) { >> + ip->flags |= BTRFS_INODE_COMPRESS; >> + ip->flags&= ~BTRFS_INODE_NOCOMPRESS; >> + } >> + if (flags& FS_NOCOW_FL) >> + ip->flags |= BTRFS_INODE_NODATACOW; >> + else if (flags& FS_COW_FL) >> + ip->flags&= ~BTRFS_INODE_NODATACOW; >> >> trans = btrfs_join_transaction(root, 1); >> BUG_ON(IS_ERR(trans)); > > -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
liubo wrote: > On 04/04/2011 05:31 PM, Konstantinos Skarlatos wrote: >> Hello, >> I would like to ask about the status of this feature/patch, is it >> accepted into btrfs code, and how can I use it? >> > > Yes, it is now in the latest 2.6.39-rc1. > >> I am interested in enabling compression in a specific >> folder(force-compress would be ideal) of a large btrfs volume, and >> disabling it for the rest. >> > > hmm, I'm making the tool's patch, and will come soon. :) > What's wrong with this? # chattr -c -R /btrfs/folder (But force-compress is not implemented in the kernel) -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 8b4b9d1..b77d1a5 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -1283,6 +1283,7 @@ struct btrfs_root { #define BTRFS_INODE_NODUMP (1 << 8) #define BTRFS_INODE_NOATIME (1 << 9) #define BTRFS_INODE_DIRSYNC (1 << 10) +#define BTRFS_INODE_COMPRESS (1 << 11) /* some macros to generate set/get funcs for the struct fields. This * assumes there is a lefoo_to_cpu for every type, so lets make a simple diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 3e1ea3e..a894c12 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1762,6 +1762,12 @@ struct btrfs_root *open_ctree(struct super_block *sb, btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY); + /* + * In the long term, we'll store the compression type in the super + * block, and it'll be used for per file compression control. + */ + fs_info->compress_type = BTRFS_COMPRESS_ZLIB; + ret = btrfs_parse_options(tree_root, options); if (ret) { err = ret; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index db67821..e687bb9 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -381,7 +381,8 @@ again: */ if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS) && (btrfs_test_opt(root, COMPRESS) || - (BTRFS_I(inode)->force_compress))) { + (BTRFS_I(inode)->force_compress) || + (BTRFS_I(inode)->flags & BTRFS_INODE_COMPRESS))) { WARN_ON(pages); pages = kzalloc(sizeof(struct page *) * nr_pages, GFP_NOFS); @@ -1253,7 +1254,8 @@ static int run_delalloc_range(struct inode *inode, struct page *locked_page, ret = run_delalloc_nocow(inode, locked_page, start, end, page_started, 0, nr_written); else if (!btrfs_test_opt(root, COMPRESS) && - !(BTRFS_I(inode)->force_compress)) + !(BTRFS_I(inode)->force_compress) && + !(BTRFS_I(inode)->flags & BTRFS_INODE_COMPRESS)) ret = cow_file_range(inode, locked_page, start, end, page_started, nr_written, 1); else @@ -4581,8 +4583,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, location->offset = 0; btrfs_set_key_type(location, BTRFS_INODE_ITEM_KEY); - btrfs_inherit_iflags(inode, dir); - if ((mode & S_IFREG)) { if (btrfs_test_opt(root, NODATASUM)) BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM; @@ -4590,6 +4590,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW; } + btrfs_inherit_iflags(inode, dir); + insert_inode_hash(inode); inode_tree_add(inode); return inode; @@ -6803,6 +6805,26 @@ static int btrfs_getattr(struct vfsmount *mnt, return 0; } +/* + * If a file is moved, it will inherit the cow and compression flags of the new + * directory. + */ +static void fixup_inode_flags(struct inode *dir, struct inode *inode) +{ + struct btrfs_inode *b_dir = BTRFS_I(dir); + struct btrfs_inode *b_inode = BTRFS_I(inode); + + if (b_dir->flags & BTRFS_INODE_NODATACOW) + b_inode->flags |= BTRFS_INODE_NODATACOW; + else + b_inode->flags &= ~BTRFS_INODE_NODATACOW; + + if (b_dir->flags & BTRFS_INODE_COMPRESS) + b_inode->flags |= BTRFS_INODE_COMPRESS; + else + b_inode->flags &= ~BTRFS_INODE_COMPRESS; +} + static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { @@ -6936,6 +6958,8 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, } } + fixup_inode_flags(new_dir, old_inode); + ret = btrfs_add_link(trans, new_dir, old_inode, new_dentry->d_name.name, new_dentry->d_name.len, 0, index); diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 5fdb2ab..93e7f6c 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -138,6 +138,24 @@ static int btrfs_ioctl_getflags(struct file *file, void __user *arg) return 0; } +static int check_flags(unsigned int flags) +{ + if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ + FS_NOATIME_FL | FS_NODUMP_FL | \ + FS_SYNC_FL | FS_DIRSYNC_FL | \ + FS_NOCOMP_FL | FS_COMPR_FL | \ + FS_NOCOW_FL | FS_COW_FL)) + return -EOPNOTSUPP; + + if ((flags & FS_NOCOMP_FL) && (flags & FS_COMPR_FL)) + return -EINVAL; + + if ((flags & FS_NOCOW_FL) && (flags & FS_COW_FL)) + return -EINVAL; + + return 0; +} + static int btrfs_ioctl_setflags(struct file *file, void __user *arg) { struct inode *inode = file->f_path.dentry->d_inode; @@ -153,10 +171,9 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) if (copy_from_user(&flags, arg, sizeof(flags))) return -EFAULT; - if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ - FS_NOATIME_FL | FS_NODUMP_FL | \ - FS_SYNC_FL | FS_DIRSYNC_FL)) - return -EOPNOTSUPP; + ret = check_flags(flags); + if (ret) + return ret; if (!is_owner_or_cap(inode)) return -EACCES; @@ -201,6 +218,22 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) else ip->flags &= ~BTRFS_INODE_DIRSYNC; + /* + * The COMPRESS flag can only be changed by users, while the NOCOMPRESS + * flag may be changed automatically if compression code won't make + * things smaller. + */ + if (flags & FS_NOCOMP_FL) { + ip->flags &= ~BTRFS_INODE_COMPRESS; + ip->flags |= BTRFS_INODE_NOCOMPRESS; + } else if (flags & FS_COMPR_FL) { + ip->flags |= BTRFS_INODE_COMPRESS; + ip->flags &= ~BTRFS_INODE_NOCOMPRESS; + } + if (flags & FS_NOCOW_FL) + ip->flags |= BTRFS_INODE_NODATACOW; + else if (flags & FS_COW_FL) + ip->flags &= ~BTRFS_INODE_NODATACOW; trans = btrfs_join_transaction(root, 1); BUG_ON(IS_ERR(trans));