aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r--fs/btrfs/ioctl.c197
1 files changed, 188 insertions, 9 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 2624b53ea783..eff18f5b5362 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -50,7 +50,177 @@
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;
116
117 if (!dir)
118 return;
119
120 flags = BTRFS_I(dir)->flags;
121
122 if (S_ISREG(inode->i_mode))
123 flags &= ~BTRFS_INODE_DIRSYNC;
124 else if (!S_ISDIR(inode->i_mode))
125 flags &= (BTRFS_INODE_NODUMP | BTRFS_INODE_NOATIME);
126
127 BTRFS_I(inode)->flags = flags;
128 btrfs_update_iflags(inode);
129}
130
131static int btrfs_ioctl_getflags(struct file *file, void __user *arg)
132{
133 struct btrfs_inode *ip = BTRFS_I(file->f_path.dentry->d_inode);
134 unsigned int flags = btrfs_flags_to_ioctl(ip->flags);
135
136 if (copy_to_user(arg, &flags, sizeof(flags)))
137 return -EFAULT;
138 return 0;
139}
140
141static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
142{
143 struct inode *inode = file->f_path.dentry->d_inode;
144 struct btrfs_inode *ip = BTRFS_I(inode);
145 struct btrfs_root *root = ip->root;
146 struct btrfs_trans_handle *trans;
147 unsigned int flags, oldflags;
148 int ret;
149
150 if (copy_from_user(&flags, arg, sizeof(flags)))
151 return -EFAULT;
152
153 if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \
154 FS_NOATIME_FL | FS_NODUMP_FL | \
155 FS_SYNC_FL | FS_DIRSYNC_FL))
156 return -EOPNOTSUPP;
53 157
158 if (!is_owner_or_cap(inode))
159 return -EACCES;
160
161 mutex_lock(&inode->i_mutex);
162
163 flags = btrfs_mask_flags(inode->i_mode, flags);
164 oldflags = btrfs_flags_to_ioctl(ip->flags);
165 if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) {
166 if (!capable(CAP_LINUX_IMMUTABLE)) {
167 ret = -EPERM;
168 goto out_unlock;
169 }
170 }
171
172 ret = mnt_want_write(file->f_path.mnt);
173 if (ret)
174 goto out_unlock;
175
176 if (flags & FS_SYNC_FL)
177 ip->flags |= BTRFS_INODE_SYNC;
178 else
179 ip->flags &= ~BTRFS_INODE_SYNC;
180 if (flags & FS_IMMUTABLE_FL)
181 ip->flags |= BTRFS_INODE_IMMUTABLE;
182 else
183 ip->flags &= ~BTRFS_INODE_IMMUTABLE;
184 if (flags & FS_APPEND_FL)
185 ip->flags |= BTRFS_INODE_APPEND;
186 else
187 ip->flags &= ~BTRFS_INODE_APPEND;
188 if (flags & FS_NODUMP_FL)
189 ip->flags |= BTRFS_INODE_NODUMP;
190 else
191 ip->flags &= ~BTRFS_INODE_NODUMP;
192 if (flags & FS_NOATIME_FL)
193 ip->flags |= BTRFS_INODE_NOATIME;
194 else
195 ip->flags &= ~BTRFS_INODE_NOATIME;
196 if (flags & FS_DIRSYNC_FL)
197 ip->flags |= BTRFS_INODE_DIRSYNC;
198 else
199 ip->flags &= ~BTRFS_INODE_DIRSYNC;
200
201
202 trans = btrfs_join_transaction(root, 1);
203 BUG_ON(!trans);
204
205 ret = btrfs_update_inode(trans, root, inode);
206 BUG_ON(ret);
207
208 btrfs_update_iflags(inode);
209 inode->i_ctime = CURRENT_TIME;
210 btrfs_end_transaction(trans, root);
211
212 mnt_drop_write(file->f_path.mnt);
213 out_unlock:
214 mutex_unlock(&inode->i_mutex);
215 return 0;
216}
217
218static int btrfs_ioctl_getversion(struct file *file, int __user *arg)
219{
220 struct inode *inode = file->f_path.dentry->d_inode;
221
222 return put_user(inode->i_generation, arg);
223}
54 224
55static noinline int create_subvol(struct btrfs_root *root, 225static noinline int create_subvol(struct btrfs_root *root,
56 struct dentry *dentry, 226 struct dentry *dentry,
@@ -82,22 +252,25 @@ static noinline int create_subvol(struct btrfs_root *root,
82 if (ret) 252 if (ret)
83 goto fail; 253 goto fail;
84 254
85 leaf = btrfs_alloc_free_block(trans, root, root->leafsize, 0, 255 leaf = btrfs_alloc_free_block(trans, root, root->leafsize,
86 objectid, trans->transid, 0, 0, 0); 256 0, objectid, NULL, 0, 0, 0);
87 if (IS_ERR(leaf)) { 257 if (IS_ERR(leaf)) {
88 ret = PTR_ERR(leaf); 258 ret = PTR_ERR(leaf);
89 goto fail; 259 goto fail;
90 } 260 }
91 261
92 btrfs_set_header_nritems(leaf, 0); 262 memset_extent_buffer(leaf, 0, 0, sizeof(struct btrfs_header));
93 btrfs_set_header_level(leaf, 0);
94 btrfs_set_header_bytenr(leaf, leaf->start); 263 btrfs_set_header_bytenr(leaf, leaf->start);
95 btrfs_set_header_generation(leaf, trans->transid); 264 btrfs_set_header_generation(leaf, trans->transid);
265 btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV);
96 btrfs_set_header_owner(leaf, objectid); 266 btrfs_set_header_owner(leaf, objectid);
97 267
98 write_extent_buffer(leaf, root->fs_info->fsid, 268 write_extent_buffer(leaf, root->fs_info->fsid,
99 (unsigned long)btrfs_header_fsid(leaf), 269 (unsigned long)btrfs_header_fsid(leaf),
100 BTRFS_FSID_SIZE); 270 BTRFS_FSID_SIZE);
271 write_extent_buffer(leaf, root->fs_info->chunk_tree_uuid,
272 (unsigned long)btrfs_header_chunk_tree_uuid(leaf),
273 BTRFS_UUID_SIZE);
101 btrfs_mark_buffer_dirty(leaf); 274 btrfs_mark_buffer_dirty(leaf);
102 275
103 inode_item = &root_item.inode; 276 inode_item = &root_item.inode;
@@ -125,7 +298,7 @@ static noinline int create_subvol(struct btrfs_root *root,
125 btrfs_set_root_dirid(&root_item, new_dirid); 298 btrfs_set_root_dirid(&root_item, new_dirid);
126 299
127 key.objectid = objectid; 300 key.objectid = objectid;
128 key.offset = 1; 301 key.offset = 0;
129 btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); 302 btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
130 ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, 303 ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key,
131 &root_item); 304 &root_item);
@@ -911,10 +1084,10 @@ static long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
911 if (disko) { 1084 if (disko) {
912 inode_add_bytes(inode, datal); 1085 inode_add_bytes(inode, datal);
913 ret = btrfs_inc_extent_ref(trans, root, 1086 ret = btrfs_inc_extent_ref(trans, root,
914 disko, diskl, leaf->start, 1087 disko, diskl, 0,
915 root->root_key.objectid, 1088 root->root_key.objectid,
916 trans->transid, 1089 inode->i_ino,
917 inode->i_ino); 1090 new_key.offset - datao);
918 BUG_ON(ret); 1091 BUG_ON(ret);
919 } 1092 }
920 } else if (type == BTRFS_FILE_EXTENT_INLINE) { 1093 } else if (type == BTRFS_FILE_EXTENT_INLINE) {
@@ -1074,6 +1247,12 @@ long btrfs_ioctl(struct file *file, unsigned int
1074 void __user *argp = (void __user *)arg; 1247 void __user *argp = (void __user *)arg;
1075 1248
1076 switch (cmd) { 1249 switch (cmd) {
1250 case FS_IOC_GETFLAGS:
1251 return btrfs_ioctl_getflags(file, argp);
1252 case FS_IOC_SETFLAGS:
1253 return btrfs_ioctl_setflags(file, argp);
1254 case FS_IOC_GETVERSION:
1255 return btrfs_ioctl_getversion(file, argp);
1077 case BTRFS_IOC_SNAP_CREATE: 1256 case BTRFS_IOC_SNAP_CREATE:
1078 return btrfs_ioctl_snap_create(file, argp, 0); 1257 return btrfs_ioctl_snap_create(file, argp, 0);
1079 case BTRFS_IOC_SUBVOL_CREATE: 1258 case BTRFS_IOC_SUBVOL_CREATE: