From patchwork Thu Feb 24 09:40:55 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: liubo X-Patchwork-Id: 586871 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p1O9ed6h023112 for ; Thu, 24 Feb 2011 09:40:40 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756034Ab1BXJke (ORCPT ); Thu, 24 Feb 2011 04:40:34 -0500 Received: from cn.fujitsu.com ([222.73.24.84]:49912 "EHLO song.cn.fujitsu.com" rhost-flags-OK-FAIL-OK-OK) by vger.kernel.org with ESMTP id S1751987Ab1BXJkc (ORCPT ); Thu, 24 Feb 2011 04:40:32 -0500 Received: from tang.cn.fujitsu.com (tang.cn.fujitsu.com [10.167.250.3]) by song.cn.fujitsu.com (Postfix) with ESMTP id 6534A17008E; Thu, 24 Feb 2011 17:40:30 +0800 (CST) Received: from mailserver.fnst.cn.fujitus.com (tang.cn.fujitsu.com [127.0.0.1]) by tang.cn.fujitsu.com (8.14.3/8.13.1) with ESMTP id p1O9Yioe025814; Thu, 24 Feb 2011 17:34:44 +0800 Received: from localhost.localdomain ([10.167.225.27]) by mailserver.fnst.cn.fujitus.com (Lotus Domino Release 8.5.1FP4) with ESMTP id 2011022417392645-214878 ; Thu, 24 Feb 2011 17:39:26 +0800 Message-ID: <4D6627A7.7050001@cn.fujitsu.com> Date: Thu, 24 Feb 2011 17:40:55 +0800 From: liubo User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1b3pre) Gecko/20090513 Fedora/3.0-2.3.beta2.fc11 Thunderbird/3.0b2 MIME-Version: 1.0 To: Linux Btrfs CC: linux-fsdevel Subject: [RFC PATCH] Btrfs: add ioctl to set compress or cow per file/dir X-MIMETrack: Itemize by SMTP Server on mailserver/fnst(Release 8.5.1FP4|July 25, 2010) at 2011-02-24 17:39:26, Serialize by Router on mailserver/fnst(Release 8.5.1FP4|July 25, 2010) at 2011-02-24 17:39:27, Serialize complete at 2011-02-24 17:39:27 Sender: linux-btrfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-btrfs@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Thu, 24 Feb 2011 09:40:40 +0000 (UTC) diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 7219537..c189183 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -587,11 +587,16 @@ struct btrfs_inode_item { /* modification sequence number for NFS */ __le64 sequence; + u8 compress_type; + /* * a little future expansion, for more than this we can * just grow the inode item and version it */ - __le64 reserved[4]; + u8 reserved_8; + __le16 reserved_16; + __le32 reserved_32; + __le64 reserved_64[3]; struct btrfs_timespec atime; struct btrfs_timespec ctime; struct btrfs_timespec mtime; @@ -1478,6 +1483,8 @@ BTRFS_SETGET_FUNCS(inode_gid, struct btrfs_inode_item, gid, 32); BTRFS_SETGET_FUNCS(inode_mode, struct btrfs_inode_item, mode, 32); BTRFS_SETGET_FUNCS(inode_rdev, struct btrfs_inode_item, rdev, 64); BTRFS_SETGET_FUNCS(inode_flags, struct btrfs_inode_item, flags, 64); +BTRFS_SETGET_FUNCS(inode_compress_type, struct btrfs_inode_item, + compress_type, 8); static inline struct btrfs_timespec * btrfs_inode_atime(struct btrfs_inode_item *inode_item) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index c9bc0af..0e11ad3 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -2515,6 +2515,9 @@ static void btrfs_read_locked_inode(struct inode *inode) BTRFS_I(inode)->block_group = btrfs_find_block_group(root, 0, alloc_group_block, 0); btrfs_free_path(path); + + BTRFS_I(inode)->force_compress = btrfs_inode_compress_type(leaf, + inode_item); inode_item = NULL; switch (inode->i_mode & S_IFMT) { @@ -2587,6 +2590,8 @@ static void fill_inode_item(struct btrfs_trans_handle *trans, btrfs_set_inode_rdev(leaf, item, inode->i_rdev); btrfs_set_inode_flags(leaf, item, BTRFS_I(inode)->flags); btrfs_set_inode_block_group(leaf, item, BTRFS_I(inode)->block_group); + btrfs_set_inode_compress_type(leaf, item, + BTRFS_I(inode)->force_compress); } /* @@ -4539,6 +4544,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, BTRFS_I(inode)->block_group = btrfs_find_block_group(root, 0, alloc_hint, owner); + BTRFS_I(inode)->force_compress = BTRFS_I(dir)->force_compress; + key[0].objectid = objectid; btrfs_set_key_type(&key[0], BTRFS_INODE_ITEM_KEY); key[0].offset = 0; @@ -4578,8 +4585,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; @@ -4587,6 +4592,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; @@ -6676,6 +6683,30 @@ static int btrfs_getattr(struct vfsmount *mnt, return 0; } +/* + * If directory is set by cow/compress ioctl, files that be moved/renamed here + * will update their inode flags. + */ +static inline void btrfs_change_cow_and_compress(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_NOCOMPRESS) { + b_inode->flags |= BTRFS_INODE_NOCOMPRESS; + b_inode->force_compress = BTRFS_COMPRESS_NONE; + } else { + b_inode->flags &= ~BTRFS_INODE_NOCOMPRESS; + b_inode->force_compress = b_dir->force_compress; + } +} + static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { @@ -6809,6 +6840,8 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, } } + btrfs_change_cow_and_compress(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 e397da4..1bb562a 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -155,7 +155,9 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ FS_NOATIME_FL | FS_NODUMP_FL | \ - FS_SYNC_FL | FS_DIRSYNC_FL)) + FS_SYNC_FL | FS_DIRSYNC_FL | \ + FS_NOCOMP_FL | FS_COMPR_FL | \ + FS_NOCOW_FL | FS_COW_FL)) return -EOPNOTSUPP; if (!is_owner_or_cap(inode)) @@ -163,8 +165,19 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) mutex_lock(&inode->i_mutex); - flags = btrfs_mask_flags(inode->i_mode, flags); oldflags = btrfs_flags_to_ioctl(ip->flags); + /* for compress, get original inode flag first */ + if (flags & FS_NOCOMP_FL || flags & FS_COMPR_FL || + flags & FS_NOCOW_FL || flags & FS_COW_FL) { + if (inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) { + ret = -EINVAL; + goto out_unlock; + } + + flags |= oldflags; + } + + flags = btrfs_mask_flags(inode->i_mode, flags); if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) { if (!capable(CAP_LINUX_IMMUTABLE)) { ret = -EPERM; @@ -200,7 +213,14 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg) ip->flags |= BTRFS_INODE_DIRSYNC; else ip->flags &= ~BTRFS_INODE_DIRSYNC; - + if (flags & FS_NOCOMP_FL) + ip->flags |= BTRFS_INODE_NOCOMPRESS; + else if (flags & FS_COMPR_FL) + 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)); @@ -2368,6 +2388,54 @@ static noinline long btrfs_ioctl_wait_sync(struct file *file, void __user *argp) return btrfs_wait_for_commit(root, transid); } +static noinline long btrfs_ioctl_set_compress_type(struct file *file, + void __user *argp) +{ + struct inode *inode = file->f_dentry->d_inode; + struct btrfs_inode *ip = BTRFS_I(inode); + struct btrfs_root *root = ip->root; + struct btrfs_trans_handle *trans; + unsigned int type; + int ret; + + if (btrfs_root_readonly(root)) + return -EROFS; + + if (inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) + return -EINVAL; + + if (copy_from_user(&type, argp, sizeof(type))) + return -EFAULT; + + if (type == BTRFS_COMPRESS_NONE || type > BTRFS_COMPRESS_TYPES) + return -EINVAL; + + mutex_lock(&inode->i_mutex); + + ret = mnt_want_write(file->f_vfsmnt); + if (ret) + goto out_unlock; + + /* compress type: zlib, lzo, NONE */ + ip->force_compress = type; + + trans = btrfs_start_transaction(root, 1); + if (IS_ERR(trans)) { + mnt_drop_write(file->f_vfsmnt); + goto out_unlock; + } + + ret = btrfs_update_inode(trans, root, inode); + + inode->i_ctime = CURRENT_TIME; + btrfs_end_transaction(trans, root); + + mnt_drop_write(file->f_vfsmnt); +out_unlock: + mutex_unlock(&inode->i_mutex); + return ret; +} + long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -2428,6 +2496,8 @@ long btrfs_ioctl(struct file *file, unsigned int return btrfs_ioctl_start_sync(file, argp); case BTRFS_IOC_WAIT_SYNC: return btrfs_ioctl_wait_sync(file, argp); + case BTRFS_IOC_SET_COMPRESS_TYPE: + return btrfs_ioctl_set_compress_type(file, argp); } return -ENOTTY; diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h index 8fb3821..a45a0b7 100644 --- a/fs/btrfs/ioctl.h +++ b/fs/btrfs/ioctl.h @@ -203,4 +203,5 @@ struct btrfs_ioctl_space_args { struct btrfs_ioctl_vol_args_v2) #define BTRFS_IOC_SUBVOL_GETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 25, __u64) #define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64) +#define BTRFS_IOC_SET_COMPRESS_TYPE _IOW(BTRFS_IOCTL_MAGIC, 27, unsigned int) #endif diff --git a/include/linux/fs.h b/include/linux/fs.h index 63d069b..235c75e 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -353,6 +353,8 @@ struct inodes_stat_t { #define FS_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ #define FS_EXTENT_FL 0x00080000 /* Extents */ #define FS_DIRECTIO_FL 0x00100000 /* Use direct i/o */ +#define FS_NOCOW_FL 0x00200000 /* Do not cow file */ +#define FS_COW_FL 0x00100000 /* Cow file */ #define FS_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ #define FS_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */