aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2009-04-17 04:37:41 -0400
committerChris Mason <chris.mason@oracle.com>2009-06-10 11:29:52 -0400
commit6cbff00f4632c8060b06bfc9585805217f11e12e (patch)
tree1886c4c855662172b84be2bfbd2aa5ac6a5c429d /fs/btrfs
parentc289811cc096c57ff35550ee8132793a4f9b5b59 (diff)
Btrfs: implement FS_IOC_GETFLAGS/SETFLAGS/GETVERSION
Add support for the standard attributes set via chattr and read via lsattr. Currently we store the attributes in the flags value in the btrfs inode, but I wonder whether we should split it into two so that we don't have to keep converting between the two formats. Remove the btrfs_clear_flag/btrfs_set_flag/btrfs_test_flag macros as they were confusing the existing code and got in the way of the new additions. Also add the FS_IOC_GETVERSION ioctl for getting i_generation as it's trivial. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/btrfs_inode.h1
-rw-r--r--fs/btrfs/compression.c6
-rw-r--r--fs/btrfs/ctree.h16
-rw-r--r--fs/btrfs/inode.c27
-rw-r--r--fs/btrfs/ioctl.c171
5 files changed, 200 insertions, 21 deletions
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index ecf5f7d8166f..acb4f3517582 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -157,5 +157,4 @@ static inline void btrfs_i_size_write(struct inode *inode, u64 size)
157 BTRFS_I(inode)->disk_i_size = size; 157 BTRFS_I(inode)->disk_i_size = size;
158} 158}
159 159
160
161#endif 160#endif
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c
index ab07627084f1..de1e2fd32080 100644
--- a/fs/btrfs/compression.c
+++ b/fs/btrfs/compression.c
@@ -123,7 +123,7 @@ static int check_compressed_csum(struct inode *inode,
123 u32 csum; 123 u32 csum;
124 u32 *cb_sum = &cb->sums; 124 u32 *cb_sum = &cb->sums;
125 125
126 if (btrfs_test_flag(inode, NODATASUM)) 126 if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)
127 return 0; 127 return 0;
128 128
129 for (i = 0; i < cb->nr_pages; i++) { 129 for (i = 0; i < cb->nr_pages; i++) {
@@ -670,7 +670,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
670 */ 670 */
671 atomic_inc(&cb->pending_bios); 671 atomic_inc(&cb->pending_bios);
672 672
673 if (!btrfs_test_flag(inode, NODATASUM)) { 673 if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
674 btrfs_lookup_bio_sums(root, inode, comp_bio, 674 btrfs_lookup_bio_sums(root, inode, comp_bio,
675 sums); 675 sums);
676 } 676 }
@@ -697,7 +697,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
697 ret = btrfs_bio_wq_end_io(root->fs_info, comp_bio, 0); 697 ret = btrfs_bio_wq_end_io(root->fs_info, comp_bio, 0);
698 BUG_ON(ret); 698 BUG_ON(ret);
699 699
700 if (!btrfs_test_flag(inode, NODATASUM)) 700 if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM))
701 btrfs_lookup_bio_sums(root, inode, comp_bio, sums); 701 btrfs_lookup_bio_sums(root, inode, comp_bio, sums);
702 702
703 ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0); 703 ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0);
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 5fa7d7d287a4..4d6e0b6f21ea 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1115,12 +1115,14 @@ struct btrfs_root {
1115#define BTRFS_INODE_READONLY (1 << 2) 1115#define BTRFS_INODE_READONLY (1 << 2)
1116#define BTRFS_INODE_NOCOMPRESS (1 << 3) 1116#define BTRFS_INODE_NOCOMPRESS (1 << 3)
1117#define BTRFS_INODE_PREALLOC (1 << 4) 1117#define BTRFS_INODE_PREALLOC (1 << 4)
1118#define btrfs_clear_flag(inode, flag) (BTRFS_I(inode)->flags &= \ 1118#define BTRFS_INODE_SYNC (1 << 5)
1119 ~BTRFS_INODE_##flag) 1119#define BTRFS_INODE_IMMUTABLE (1 << 6)
1120#define btrfs_set_flag(inode, flag) (BTRFS_I(inode)->flags |= \ 1120#define BTRFS_INODE_APPEND (1 << 7)
1121 BTRFS_INODE_##flag) 1121#define BTRFS_INODE_NODUMP (1 << 8)
1122#define btrfs_test_flag(inode, flag) (BTRFS_I(inode)->flags & \ 1122#define BTRFS_INODE_NOATIME (1 << 9)
1123 BTRFS_INODE_##flag) 1123#define BTRFS_INODE_DIRSYNC (1 << 10)
1124
1125
1124/* some macros to generate set/get funcs for the struct fields. This 1126/* some macros to generate set/get funcs for the struct fields. This
1125 * assumes there is a lefoo_to_cpu for every type, so lets make a simple 1127 * assumes there is a lefoo_to_cpu for every type, so lets make a simple
1126 * one for u8: 1128 * one for u8:
@@ -2260,6 +2262,8 @@ int btrfs_cont_expand(struct inode *inode, loff_t size);
2260 2262
2261/* ioctl.c */ 2263/* ioctl.c */
2262long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); 2264long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
2265void btrfs_update_iflags(struct inode *inode);
2266void btrfs_inherit_iflags(struct inode *inode, struct inode *dir);
2263 2267
2264/* file.c */ 2268/* file.c */
2265int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync); 2269int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 917bf10597c6..5b68330f8585 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -368,7 +368,7 @@ again:
368 * inode has not been flagged as nocompress. This flag can 368 * inode has not been flagged as nocompress. This flag can
369 * change at any time if we discover bad compression ratios. 369 * change at any time if we discover bad compression ratios.
370 */ 370 */
371 if (!btrfs_test_flag(inode, NOCOMPRESS) && 371 if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS) &&
372 btrfs_test_opt(root, COMPRESS)) { 372 btrfs_test_opt(root, COMPRESS)) {
373 WARN_ON(pages); 373 WARN_ON(pages);
374 pages = kzalloc(sizeof(struct page *) * nr_pages, GFP_NOFS); 374 pages = kzalloc(sizeof(struct page *) * nr_pages, GFP_NOFS);
@@ -469,7 +469,7 @@ again:
469 nr_pages_ret = 0; 469 nr_pages_ret = 0;
470 470
471 /* flag the file so we don't compress in the future */ 471 /* flag the file so we don't compress in the future */
472 btrfs_set_flag(inode, NOCOMPRESS); 472 BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS;
473 } 473 }
474 if (will_compress) { 474 if (will_compress) {
475 *num_added += 1; 475 *num_added += 1;
@@ -862,7 +862,7 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page,
862 async_cow->locked_page = locked_page; 862 async_cow->locked_page = locked_page;
863 async_cow->start = start; 863 async_cow->start = start;
864 864
865 if (btrfs_test_flag(inode, NOCOMPRESS)) 865 if (BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS)
866 cur_end = end; 866 cur_end = end;
867 else 867 else
868 cur_end = min(end, start + 512 * 1024 - 1); 868 cur_end = min(end, start + 512 * 1024 - 1);
@@ -1133,10 +1133,10 @@ static int run_delalloc_range(struct inode *inode, struct page *locked_page,
1133 int ret; 1133 int ret;
1134 struct btrfs_root *root = BTRFS_I(inode)->root; 1134 struct btrfs_root *root = BTRFS_I(inode)->root;
1135 1135
1136 if (btrfs_test_flag(inode, NODATACOW)) 1136 if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW)
1137 ret = run_delalloc_nocow(inode, locked_page, start, end, 1137 ret = run_delalloc_nocow(inode, locked_page, start, end,
1138 page_started, 1, nr_written); 1138 page_started, 1, nr_written);
1139 else if (btrfs_test_flag(inode, PREALLOC)) 1139 else if (BTRFS_I(inode)->flags & BTRFS_INODE_PREALLOC)
1140 ret = run_delalloc_nocow(inode, locked_page, start, end, 1140 ret = run_delalloc_nocow(inode, locked_page, start, end,
1141 page_started, 0, nr_written); 1141 page_started, 0, nr_written);
1142 else if (!btrfs_test_opt(root, COMPRESS)) 1142 else if (!btrfs_test_opt(root, COMPRESS))
@@ -1290,7 +1290,7 @@ static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
1290 int ret = 0; 1290 int ret = 0;
1291 int skip_sum; 1291 int skip_sum;
1292 1292
1293 skip_sum = btrfs_test_flag(inode, NODATASUM); 1293 skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
1294 1294
1295 ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0); 1295 ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0);
1296 BUG_ON(ret); 1296 BUG_ON(ret);
@@ -1790,7 +1790,8 @@ static int btrfs_readpage_end_io_hook(struct page *page, u64 start, u64 end,
1790 ClearPageChecked(page); 1790 ClearPageChecked(page);
1791 goto good; 1791 goto good;
1792 } 1792 }
1793 if (btrfs_test_flag(inode, NODATASUM)) 1793
1794 if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)
1794 return 0; 1795 return 0;
1795 1796
1796 if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID && 1797 if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID &&
@@ -2156,6 +2157,8 @@ static void btrfs_read_locked_inode(struct inode *inode)
2156 init_special_inode(inode, inode->i_mode, rdev); 2157 init_special_inode(inode, inode->i_mode, rdev);
2157 break; 2158 break;
2158 } 2159 }
2160
2161 btrfs_update_iflags(inode);
2159 return; 2162 return;
2160 2163
2161make_bad: 2164make_bad:
@@ -3586,9 +3589,9 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
3586 btrfs_find_block_group(root, 0, alloc_hint, owner); 3589 btrfs_find_block_group(root, 0, alloc_hint, owner);
3587 if ((mode & S_IFREG)) { 3590 if ((mode & S_IFREG)) {
3588 if (btrfs_test_opt(root, NODATASUM)) 3591 if (btrfs_test_opt(root, NODATASUM))
3589 btrfs_set_flag(inode, NODATASUM); 3592 BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM;
3590 if (btrfs_test_opt(root, NODATACOW)) 3593 if (btrfs_test_opt(root, NODATACOW))
3591 btrfs_set_flag(inode, NODATACOW); 3594 BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW;
3592 } 3595 }
3593 3596
3594 key[0].objectid = objectid; 3597 key[0].objectid = objectid;
@@ -3642,6 +3645,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
3642 location->offset = 0; 3645 location->offset = 0;
3643 btrfs_set_key_type(location, BTRFS_INODE_ITEM_KEY); 3646 btrfs_set_key_type(location, BTRFS_INODE_ITEM_KEY);
3644 3647
3648 btrfs_inherit_iflags(inode, dir);
3649
3645 insert_inode_hash(inode); 3650 insert_inode_hash(inode);
3646 inode_tree_add(inode); 3651 inode_tree_add(inode);
3647 return inode; 3652 return inode;
@@ -5075,7 +5080,7 @@ static int prealloc_file_range(struct btrfs_trans_handle *trans,
5075out: 5080out:
5076 if (cur_offset > start) { 5081 if (cur_offset > start) {
5077 inode->i_ctime = CURRENT_TIME; 5082 inode->i_ctime = CURRENT_TIME;
5078 btrfs_set_flag(inode, PREALLOC); 5083 BTRFS_I(inode)->flags |= BTRFS_INODE_PREALLOC;
5079 if (!(mode & FALLOC_FL_KEEP_SIZE) && 5084 if (!(mode & FALLOC_FL_KEEP_SIZE) &&
5080 cur_offset > i_size_read(inode)) 5085 cur_offset > i_size_read(inode))
5081 btrfs_i_size_write(inode, cur_offset); 5086 btrfs_i_size_write(inode, cur_offset);
@@ -5196,7 +5201,7 @@ static int btrfs_set_page_dirty(struct page *page)
5196 5201
5197static int btrfs_permission(struct inode *inode, int mask) 5202static int btrfs_permission(struct inode *inode, int mask)
5198{ 5203{
5199 if (btrfs_test_flag(inode, READONLY) && (mask & MAY_WRITE)) 5204 if ((BTRFS_I(inode)->flags & BTRFS_INODE_READONLY) && (mask & MAY_WRITE))
5200 return -EACCES; 5205 return -EACCES;
5201 return generic_permission(inode, mask, btrfs_check_acl); 5206 return generic_permission(inode, mask, btrfs_check_acl);
5202} 5207}
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 54dfd45cc591..926332a73cde 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -50,7 +50,172 @@
50#include "volumes.h" 50#include "volumes.h"
51#include "locking.h" 51#include "locking.h"
52 52
53/* Mask out flags that are inappropriate for the given type of inode. */
54static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags)
55{
56 if (S_ISDIR(mode))
57 return flags;
58 else if (S_ISREG(mode))
59 return flags & ~FS_DIRSYNC_FL;
60 else
61 return flags & (FS_NODUMP_FL | FS_NOATIME_FL);
62}
63
64/*
65 * Export inode flags to the format expected by the FS_IOC_GETFLAGS ioctl.
66 */
67static unsigned int btrfs_flags_to_ioctl(unsigned int flags)
68{
69 unsigned int iflags = 0;
70
71 if (flags & BTRFS_INODE_SYNC)
72 iflags |= FS_SYNC_FL;
73 if (flags & BTRFS_INODE_IMMUTABLE)
74 iflags |= FS_IMMUTABLE_FL;
75 if (flags & BTRFS_INODE_APPEND)
76 iflags |= FS_APPEND_FL;
77 if (flags & BTRFS_INODE_NODUMP)
78 iflags |= FS_NODUMP_FL;
79 if (flags & BTRFS_INODE_NOATIME)
80 iflags |= FS_NOATIME_FL;
81 if (flags & BTRFS_INODE_DIRSYNC)
82 iflags |= FS_DIRSYNC_FL;
83
84 return iflags;
85}
86
87/*
88 * Update inode->i_flags based on the btrfs internal flags.
89 */
90void btrfs_update_iflags(struct inode *inode)
91{
92 struct btrfs_inode *ip = BTRFS_I(inode);
93
94 inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);
95
96 if (ip->flags & BTRFS_INODE_SYNC)
97 inode->i_flags |= S_SYNC;
98 if (ip->flags & BTRFS_INODE_IMMUTABLE)
99 inode->i_flags |= S_IMMUTABLE;
100 if (ip->flags & BTRFS_INODE_APPEND)
101 inode->i_flags |= S_APPEND;
102 if (ip->flags & BTRFS_INODE_NOATIME)
103 inode->i_flags |= S_NOATIME;
104 if (ip->flags & BTRFS_INODE_DIRSYNC)
105 inode->i_flags |= S_DIRSYNC;
106}
107
108/*
109 * Inherit flags from the parent inode.
110 *
111 * Unlike extN we don't have any flags we don't want to inherit currently.
112 */
113void btrfs_inherit_iflags(struct inode *inode, struct inode *dir)
114{
115 unsigned int flags = BTRFS_I(dir)->flags;
116
117 if (S_ISREG(inode->i_mode))
118 flags &= ~BTRFS_INODE_DIRSYNC;
119 else if (!S_ISDIR(inode->i_mode))
120 flags &= (BTRFS_INODE_NODUMP | BTRFS_INODE_NOATIME);
121
122 BTRFS_I(inode)->flags = flags;
123 btrfs_update_iflags(inode);
124}
125
126static int btrfs_ioctl_getflags(struct file *file, void __user *arg)
127{
128 struct btrfs_inode *ip = BTRFS_I(file->f_path.dentry->d_inode);
129 unsigned int flags = btrfs_flags_to_ioctl(ip->flags);
130
131 if (copy_to_user(arg, &flags, sizeof(flags)))
132 return -EFAULT;
133 return 0;
134}
135
136static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
137{
138 struct inode *inode = file->f_path.dentry->d_inode;
139 struct btrfs_inode *ip = BTRFS_I(inode);
140 struct btrfs_root *root = ip->root;
141 struct btrfs_trans_handle *trans;
142 unsigned int flags, oldflags;
143 int ret;
144
145 if (copy_from_user(&flags, arg, sizeof(flags)))
146 return -EFAULT;
147
148 if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \
149 FS_NOATIME_FL | FS_NODUMP_FL | \
150 FS_SYNC_FL | FS_DIRSYNC_FL))
151 return -EOPNOTSUPP;
53 152
153 if (!is_owner_or_cap(inode))
154 return -EACCES;
155
156 mutex_lock(&inode->i_mutex);
157
158 flags = btrfs_mask_flags(inode->i_mode, flags);
159 oldflags = btrfs_flags_to_ioctl(ip->flags);
160 if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) {
161 if (!capable(CAP_LINUX_IMMUTABLE)) {
162 ret = -EPERM;
163 goto out_unlock;
164 }
165 }
166
167 ret = mnt_want_write(file->f_path.mnt);
168 if (ret)
169 goto out_unlock;
170
171 if (flags & FS_SYNC_FL)
172 ip->flags |= BTRFS_INODE_SYNC;
173 else
174 ip->flags &= ~BTRFS_INODE_SYNC;
175 if (flags & FS_IMMUTABLE_FL)
176 ip->flags |= BTRFS_INODE_IMMUTABLE;
177 else
178 ip->flags &= ~BTRFS_INODE_IMMUTABLE;
179 if (flags & FS_APPEND_FL)
180 ip->flags |= BTRFS_INODE_APPEND;
181 else
182 ip->flags &= ~BTRFS_INODE_APPEND;
183 if (flags & FS_NODUMP_FL)
184 ip->flags |= BTRFS_INODE_NODUMP;
185 else
186 ip->flags &= ~BTRFS_INODE_NODUMP;
187 if (flags & FS_NOATIME_FL)
188 ip->flags |= BTRFS_INODE_NOATIME;
189 else
190 ip->flags &= ~BTRFS_INODE_NOATIME;
191 if (flags & FS_DIRSYNC_FL)
192 ip->flags |= BTRFS_INODE_DIRSYNC;
193 else
194 ip->flags &= ~BTRFS_INODE_DIRSYNC;
195
196
197 trans = btrfs_join_transaction(root, 1);
198 BUG_ON(!trans);
199
200 ret = btrfs_update_inode(trans, root, inode);
201 BUG_ON(ret);
202
203 btrfs_update_iflags(inode);
204 inode->i_ctime = CURRENT_TIME;
205 btrfs_end_transaction(trans, root);
206
207 mnt_drop_write(file->f_path.mnt);
208 out_unlock:
209 mutex_unlock(&inode->i_mutex);
210 return 0;
211}
212
213static int btrfs_ioctl_getversion(struct file *file, int __user *arg)
214{
215 struct inode *inode = file->f_path.dentry->d_inode;
216
217 return put_user(inode->i_generation, arg);
218}
54 219
55static noinline int create_subvol(struct btrfs_root *root, 220static noinline int create_subvol(struct btrfs_root *root,
56 struct dentry *dentry, 221 struct dentry *dentry,
@@ -1077,6 +1242,12 @@ long btrfs_ioctl(struct file *file, unsigned int
1077 void __user *argp = (void __user *)arg; 1242 void __user *argp = (void __user *)arg;
1078 1243
1079 switch (cmd) { 1244 switch (cmd) {
1245 case FS_IOC_GETFLAGS:
1246 return btrfs_ioctl_getflags(file, argp);
1247 case FS_IOC_SETFLAGS:
1248 return btrfs_ioctl_setflags(file, argp);
1249 case FS_IOC_GETVERSION:
1250 return btrfs_ioctl_getversion(file, argp);
1080 case BTRFS_IOC_SNAP_CREATE: 1251 case BTRFS_IOC_SNAP_CREATE:
1081 return btrfs_ioctl_snap_create(file, argp, 0); 1252 return btrfs_ioctl_snap_create(file, argp, 0);
1082 case BTRFS_IOC_SUBVOL_CREATE: 1253 case BTRFS_IOC_SUBVOL_CREATE: