Blame view
fs/btrfs/ioctl.c
74.4 KB
f46b5a66b Btrfs: split out ... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* * Copyright (C) 2007 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License v2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. */ #include <linux/kernel.h> #include <linux/bio.h> #include <linux/buffer_head.h> #include <linux/file.h> #include <linux/fs.h> |
cb8e70901 Btrfs: Fix subvol... |
24 |
#include <linux/fsnotify.h> |
f46b5a66b Btrfs: split out ... |
25 26 27 28 29 |
#include <linux/pagemap.h> #include <linux/highmem.h> #include <linux/time.h> #include <linux/init.h> #include <linux/string.h> |
f46b5a66b Btrfs: split out ... |
30 |
#include <linux/backing-dev.h> |
cb8e70901 Btrfs: Fix subvol... |
31 |
#include <linux/mount.h> |
f46b5a66b Btrfs: split out ... |
32 |
#include <linux/mpage.h> |
cb8e70901 Btrfs: Fix subvol... |
33 |
#include <linux/namei.h> |
f46b5a66b Btrfs: split out ... |
34 35 36 37 38 |
#include <linux/swap.h> #include <linux/writeback.h> #include <linux/statfs.h> #include <linux/compat.h> #include <linux/bit_spinlock.h> |
cb8e70901 Btrfs: Fix subvol... |
39 |
#include <linux/security.h> |
f46b5a66b Btrfs: split out ... |
40 |
#include <linux/xattr.h> |
7ea394f11 Btrfs: Fix nodata... |
41 |
#include <linux/vmalloc.h> |
5a0e3ad6a include cleanup: ... |
42 |
#include <linux/slab.h> |
f7039b1d5 Btrfs: add btrfs_... |
43 |
#include <linux/blkdev.h> |
4b4e25f2a Btrfs: compat cod... |
44 |
#include "compat.h" |
f46b5a66b Btrfs: split out ... |
45 46 47 48 49 50 51 |
#include "ctree.h" #include "disk-io.h" #include "transaction.h" #include "btrfs_inode.h" #include "ioctl.h" #include "print-tree.h" #include "volumes.h" |
925baeddc Btrfs: Start btre... |
52 |
#include "locking.h" |
581bb0509 Btrfs: Cache free... |
53 |
#include "inode-map.h" |
d7728c960 btrfs: new ioctls... |
54 |
#include "backref.h" |
f46b5a66b Btrfs: split out ... |
55 |
|
6cbff00f4 Btrfs: implement ... |
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
/* Mask out flags that are inappropriate for the given type of inode. */ static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags) { if (S_ISDIR(mode)) return flags; else if (S_ISREG(mode)) return flags & ~FS_DIRSYNC_FL; else return flags & (FS_NODUMP_FL | FS_NOATIME_FL); } /* * Export inode flags to the format expected by the FS_IOC_GETFLAGS ioctl. */ static unsigned int btrfs_flags_to_ioctl(unsigned int flags) { unsigned int iflags = 0; if (flags & BTRFS_INODE_SYNC) iflags |= FS_SYNC_FL; if (flags & BTRFS_INODE_IMMUTABLE) iflags |= FS_IMMUTABLE_FL; if (flags & BTRFS_INODE_APPEND) iflags |= FS_APPEND_FL; if (flags & BTRFS_INODE_NODUMP) iflags |= FS_NODUMP_FL; if (flags & BTRFS_INODE_NOATIME) iflags |= FS_NOATIME_FL; if (flags & BTRFS_INODE_DIRSYNC) iflags |= FS_DIRSYNC_FL; |
d0092bdda Btrfs: fix FS_IOC... |
86 87 88 89 90 91 92 |
if (flags & BTRFS_INODE_NODATACOW) iflags |= FS_NOCOW_FL; if ((flags & BTRFS_INODE_COMPRESS) && !(flags & BTRFS_INODE_NOCOMPRESS)) iflags |= FS_COMPR_FL; else if (flags & BTRFS_INODE_NOCOMPRESS) iflags |= FS_NOCOMP_FL; |
6cbff00f4 Btrfs: implement ... |
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
return iflags; } /* * Update inode->i_flags based on the btrfs internal flags. */ void btrfs_update_iflags(struct inode *inode) { struct btrfs_inode *ip = BTRFS_I(inode); inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); if (ip->flags & BTRFS_INODE_SYNC) inode->i_flags |= S_SYNC; if (ip->flags & BTRFS_INODE_IMMUTABLE) inode->i_flags |= S_IMMUTABLE; if (ip->flags & BTRFS_INODE_APPEND) inode->i_flags |= S_APPEND; if (ip->flags & BTRFS_INODE_NOATIME) inode->i_flags |= S_NOATIME; if (ip->flags & BTRFS_INODE_DIRSYNC) inode->i_flags |= S_DIRSYNC; } /* * Inherit flags from the parent inode. * |
e27425d61 Btrfs: only inher... |
121 |
* Currently only the compression flags and the cow flags are inherited. |
6cbff00f4 Btrfs: implement ... |
122 123 124 |
*/ void btrfs_inherit_iflags(struct inode *inode, struct inode *dir) { |
0b4dcea57 Btrfs: fix oops w... |
125 126 127 128 129 130 |
unsigned int flags; if (!dir) return; flags = BTRFS_I(dir)->flags; |
6cbff00f4 Btrfs: implement ... |
131 |
|
e27425d61 Btrfs: only inher... |
132 133 134 135 136 137 138 139 140 141 |
if (flags & BTRFS_INODE_NOCOMPRESS) { BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS; BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS; } else if (flags & BTRFS_INODE_COMPRESS) { BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS; BTRFS_I(inode)->flags |= BTRFS_INODE_COMPRESS; } if (flags & BTRFS_INODE_NODATACOW) BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW; |
6cbff00f4 Btrfs: implement ... |
142 |
|
6cbff00f4 Btrfs: implement ... |
143 144 145 146 147 148 149 150 151 152 153 154 |
btrfs_update_iflags(inode); } static int btrfs_ioctl_getflags(struct file *file, void __user *arg) { struct btrfs_inode *ip = BTRFS_I(file->f_path.dentry->d_inode); unsigned int flags = btrfs_flags_to_ioctl(ip->flags); if (copy_to_user(arg, &flags, sizeof(flags))) return -EFAULT; return 0; } |
75e7cb7fe Btrfs: Per file/d... |
155 156 157 158 159 |
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 | \ |
e1e8fb6a1 fs: remove FS_COW_FL |
160 161 |
FS_NOCOMP_FL | FS_COMPR_FL | FS_NOCOW_FL)) |
75e7cb7fe Btrfs: Per file/d... |
162 163 164 165 |
return -EOPNOTSUPP; if ((flags & FS_NOCOMP_FL) && (flags & FS_COMPR_FL)) return -EINVAL; |
75e7cb7fe Btrfs: Per file/d... |
166 167 |
return 0; } |
6cbff00f4 Btrfs: implement ... |
168 169 170 171 172 173 174 175 |
static int btrfs_ioctl_setflags(struct file *file, void __user *arg) { struct inode *inode = file->f_path.dentry->d_inode; struct btrfs_inode *ip = BTRFS_I(inode); struct btrfs_root *root = ip->root; struct btrfs_trans_handle *trans; unsigned int flags, oldflags; int ret; |
b83cc9693 Btrfs: Add readon... |
176 177 |
if (btrfs_root_readonly(root)) return -EROFS; |
6cbff00f4 Btrfs: implement ... |
178 179 |
if (copy_from_user(&flags, arg, sizeof(flags))) return -EFAULT; |
75e7cb7fe Btrfs: Per file/d... |
180 181 182 |
ret = check_flags(flags); if (ret) return ret; |
f46b5a66b Btrfs: split out ... |
183 |
|
2e1496707 userns: rename is... |
184 |
if (!inode_owner_or_capable(inode)) |
6cbff00f4 Btrfs: implement ... |
185 186 187 188 189 190 191 192 193 194 195 196 |
return -EACCES; mutex_lock(&inode->i_mutex); flags = btrfs_mask_flags(inode->i_mode, flags); oldflags = btrfs_flags_to_ioctl(ip->flags); if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) { if (!capable(CAP_LINUX_IMMUTABLE)) { ret = -EPERM; goto out_unlock; } } |
a561be710 switch a bunch of... |
197 |
ret = mnt_want_write_file(file); |
6cbff00f4 Btrfs: implement ... |
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
if (ret) goto out_unlock; if (flags & FS_SYNC_FL) ip->flags |= BTRFS_INODE_SYNC; else ip->flags &= ~BTRFS_INODE_SYNC; if (flags & FS_IMMUTABLE_FL) ip->flags |= BTRFS_INODE_IMMUTABLE; else ip->flags &= ~BTRFS_INODE_IMMUTABLE; if (flags & FS_APPEND_FL) ip->flags |= BTRFS_INODE_APPEND; else ip->flags &= ~BTRFS_INODE_APPEND; if (flags & FS_NODUMP_FL) ip->flags |= BTRFS_INODE_NODUMP; else ip->flags &= ~BTRFS_INODE_NODUMP; if (flags & FS_NOATIME_FL) ip->flags |= BTRFS_INODE_NOATIME; else ip->flags &= ~BTRFS_INODE_NOATIME; if (flags & FS_DIRSYNC_FL) ip->flags |= BTRFS_INODE_DIRSYNC; else ip->flags &= ~BTRFS_INODE_DIRSYNC; |
e1e8fb6a1 fs: remove FS_COW_FL |
225 226 227 228 |
if (flags & FS_NOCOW_FL) ip->flags |= BTRFS_INODE_NODATACOW; else ip->flags &= ~BTRFS_INODE_NODATACOW; |
6cbff00f4 Btrfs: implement ... |
229 |
|
75e7cb7fe Btrfs: Per file/d... |
230 231 232 233 234 235 236 237 238 239 240 |
/* * 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; |
ebcb904df Btrfs: fix FS_IOC... |
241 242 |
} else { ip->flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS); |
75e7cb7fe Btrfs: Per file/d... |
243 |
} |
6cbff00f4 Btrfs: implement ... |
244 |
|
7a7eaa40a Btrfs: take away ... |
245 |
trans = btrfs_join_transaction(root); |
3612b4959 btrfs: fix return... |
246 |
BUG_ON(IS_ERR(trans)); |
6cbff00f4 Btrfs: implement ... |
247 |
|
306424cc8 Btrfs: fix ctime ... |
248 249 |
btrfs_update_iflags(inode); inode->i_ctime = CURRENT_TIME; |
6cbff00f4 Btrfs: implement ... |
250 251 |
ret = btrfs_update_inode(trans, root, inode); BUG_ON(ret); |
6cbff00f4 Btrfs: implement ... |
252 |
btrfs_end_transaction(trans, root); |
2a79f17e4 vfs: mnt_drop_wri... |
253 |
mnt_drop_write_file(file); |
2d4e6f6ad Btrfs: fix return... |
254 255 |
ret = 0; |
6cbff00f4 Btrfs: implement ... |
256 257 |
out_unlock: mutex_unlock(&inode->i_mutex); |
2d4e6f6ad Btrfs: fix return... |
258 |
return ret; |
6cbff00f4 Btrfs: implement ... |
259 260 261 262 263 264 265 266 |
} static int btrfs_ioctl_getversion(struct file *file, int __user *arg) { struct inode *inode = file->f_path.dentry->d_inode; return put_user(inode->i_generation, arg); } |
f46b5a66b Btrfs: split out ... |
267 |
|
f7039b1d5 Btrfs: add btrfs_... |
268 269 270 271 272 273 274 275 276 |
static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg) { struct btrfs_root *root = fdentry(file)->d_sb->s_fs_info; struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_device *device; struct request_queue *q; struct fstrim_range range; u64 minlen = ULLONG_MAX; u64 num_devices = 0; |
6c41761fc btrfs: separate s... |
277 |
u64 total_bytes = btrfs_super_total_bytes(root->fs_info->super_copy); |
f7039b1d5 Btrfs: add btrfs_... |
278 279 280 281 |
int ret; if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
1f78160ce Btrfs: using rcu ... |
282 283 284 |
rcu_read_lock(); list_for_each_entry_rcu(device, &fs_info->fs_devices->devices, dev_list) { |
f7039b1d5 Btrfs: add btrfs_... |
285 286 287 288 289 290 291 292 293 |
if (!device->bdev) continue; q = bdev_get_queue(device->bdev); if (blk_queue_discard(q)) { num_devices++; minlen = min((u64)q->limits.discard_granularity, minlen); } } |
1f78160ce Btrfs: using rcu ... |
294 |
rcu_read_unlock(); |
f4c697e64 btrfs: return EIN... |
295 |
|
f7039b1d5 Btrfs: add btrfs_... |
296 297 |
if (!num_devices) return -EOPNOTSUPP; |
f7039b1d5 Btrfs: add btrfs_... |
298 299 |
if (copy_from_user(&range, arg, sizeof(range))) return -EFAULT; |
f4c697e64 btrfs: return EIN... |
300 301 |
if (range.start > total_bytes) return -EINVAL; |
f7039b1d5 Btrfs: add btrfs_... |
302 |
|
f4c697e64 btrfs: return EIN... |
303 |
range.len = min(range.len, total_bytes - range.start); |
f7039b1d5 Btrfs: add btrfs_... |
304 305 306 307 308 309 310 311 312 313 |
range.minlen = max(range.minlen, minlen); ret = btrfs_trim_fs(root, &range); if (ret < 0) return ret; if (copy_to_user(arg, &range, sizeof(range))) return -EFAULT; return 0; } |
cb8e70901 Btrfs: Fix subvol... |
314 315 |
static noinline int create_subvol(struct btrfs_root *root, struct dentry *dentry, |
72fd032e9 Btrfs: add SNAP_C... |
316 317 |
char *name, int namelen, u64 *async_transid) |
f46b5a66b Btrfs: split out ... |
318 319 320 321 322 323 |
{ struct btrfs_trans_handle *trans; struct btrfs_key key; struct btrfs_root_item root_item; struct btrfs_inode_item *inode_item; struct extent_buffer *leaf; |
76dda93c6 Btrfs: add snapsh... |
324 |
struct btrfs_root *new_root; |
2fbe8c8ad get rid of useles... |
325 |
struct dentry *parent = dentry->d_parent; |
6a9122130 Btrfs: use dget_p... |
326 |
struct inode *dir; |
f46b5a66b Btrfs: split out ... |
327 328 329 330 |
int ret; int err; u64 objectid; u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID; |
3de4586c5 Btrfs: Allow subv... |
331 |
u64 index = 0; |
f46b5a66b Btrfs: split out ... |
332 |
|
581bb0509 Btrfs: Cache free... |
333 |
ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid); |
2fbe8c8ad get rid of useles... |
334 |
if (ret) |
a22285a6a Btrfs: Integrate ... |
335 |
return ret; |
6a9122130 Btrfs: use dget_p... |
336 337 |
dir = parent->d_inode; |
9ed74f2db Btrfs: proper -EN... |
338 339 340 341 342 343 |
/* * 1 - inode item * 2 - refs * 1 - root item * 2 - dir items */ |
a22285a6a Btrfs: Integrate ... |
344 |
trans = btrfs_start_transaction(root, 6); |
2fbe8c8ad get rid of useles... |
345 |
if (IS_ERR(trans)) |
a22285a6a Btrfs: Integrate ... |
346 |
return PTR_ERR(trans); |
f46b5a66b Btrfs: split out ... |
347 |
|
5d4f98a28 Btrfs: Mixed back... |
348 349 |
leaf = btrfs_alloc_free_block(trans, root, root->leafsize, 0, objectid, NULL, 0, 0, 0); |
8e8a1e31f Btrfs: Fix a few ... |
350 351 352 353 |
if (IS_ERR(leaf)) { ret = PTR_ERR(leaf); goto fail; } |
f46b5a66b Btrfs: split out ... |
354 |
|
5d4f98a28 Btrfs: Mixed back... |
355 |
memset_extent_buffer(leaf, 0, 0, sizeof(struct btrfs_header)); |
f46b5a66b Btrfs: split out ... |
356 357 |
btrfs_set_header_bytenr(leaf, leaf->start); btrfs_set_header_generation(leaf, trans->transid); |
5d4f98a28 Btrfs: Mixed back... |
358 |
btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV); |
f46b5a66b Btrfs: split out ... |
359 360 361 362 363 |
btrfs_set_header_owner(leaf, objectid); write_extent_buffer(leaf, root->fs_info->fsid, (unsigned long)btrfs_header_fsid(leaf), BTRFS_FSID_SIZE); |
5d4f98a28 Btrfs: Mixed back... |
364 365 366 |
write_extent_buffer(leaf, root->fs_info->chunk_tree_uuid, (unsigned long)btrfs_header_chunk_tree_uuid(leaf), BTRFS_UUID_SIZE); |
f46b5a66b Btrfs: split out ... |
367 368 369 370 371 372 373 |
btrfs_mark_buffer_dirty(leaf); inode_item = &root_item.inode; memset(inode_item, 0, sizeof(*inode_item)); inode_item->generation = cpu_to_le64(1); inode_item->size = cpu_to_le64(3); inode_item->nlink = cpu_to_le32(1); |
a76a3cd40 Btrfs: Count spac... |
374 |
inode_item->nbytes = cpu_to_le64(root->leafsize); |
f46b5a66b Btrfs: split out ... |
375 |
inode_item->mode = cpu_to_le32(S_IFDIR | 0755); |
08fe4db17 Btrfs: Fix uninit... |
376 377 378 |
root_item.flags = 0; root_item.byte_limit = 0; inode_item->flags = cpu_to_le64(BTRFS_INODE_ROOT_ITEM_INIT); |
f46b5a66b Btrfs: split out ... |
379 |
btrfs_set_root_bytenr(&root_item, leaf->start); |
84234f3a1 Btrfs: Add root t... |
380 |
btrfs_set_root_generation(&root_item, trans->transid); |
f46b5a66b Btrfs: split out ... |
381 382 |
btrfs_set_root_level(&root_item, 0); btrfs_set_root_refs(&root_item, 1); |
86b9f2eca Btrfs: Fix per ro... |
383 |
btrfs_set_root_used(&root_item, leaf->len); |
80ff38566 Btrfs: update nod... |
384 |
btrfs_set_root_last_snapshot(&root_item, 0); |
f46b5a66b Btrfs: split out ... |
385 386 387 |
memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress)); root_item.drop_level = 0; |
925baeddc Btrfs: Start btre... |
388 |
btrfs_tree_unlock(leaf); |
f46b5a66b Btrfs: split out ... |
389 390 391 392 393 394 |
free_extent_buffer(leaf); leaf = NULL; btrfs_set_root_dirid(&root_item, new_dirid); key.objectid = objectid; |
5d4f98a28 Btrfs: Mixed back... |
395 |
key.offset = 0; |
f46b5a66b Btrfs: split out ... |
396 397 398 399 400 |
btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, &root_item); if (ret) goto fail; |
76dda93c6 Btrfs: add snapsh... |
401 402 403 404 405 |
key.offset = (u64)-1; new_root = btrfs_read_fs_root_no_name(root->fs_info, &key); BUG_ON(IS_ERR(new_root)); btrfs_record_root_in_trans(trans, new_root); |
d82a6f1d7 Btrfs: kill BTRFS... |
406 |
ret = btrfs_create_subvol_root(trans, new_root, new_dirid); |
f46b5a66b Btrfs: split out ... |
407 408 409 |
/* * insert the directory item */ |
3de4586c5 Btrfs: Allow subv... |
410 411 412 413 |
ret = btrfs_set_inode_index(dir, &index); BUG_ON(ret); ret = btrfs_insert_dir_item(trans, root, |
16cdcec73 btrfs: implement ... |
414 |
name, namelen, dir, &key, |
3de4586c5 Btrfs: Allow subv... |
415 |
BTRFS_FT_DIR, index); |
f46b5a66b Btrfs: split out ... |
416 417 |
if (ret) goto fail; |
0660b5af3 Btrfs: Add backre... |
418 |
|
52c261799 Btrfs: update dir... |
419 420 421 |
btrfs_i_size_write(dir, dir->i_size + namelen * 2); ret = btrfs_update_inode(trans, root, dir); BUG_ON(ret); |
0660b5af3 Btrfs: Add backre... |
422 |
ret = btrfs_add_root_ref(trans, root->fs_info->tree_root, |
4df27c4d5 Btrfs: change how... |
423 |
objectid, root->root_key.objectid, |
33345d015 Btrfs: Always use... |
424 |
btrfs_ino(dir), index, name, namelen); |
0660b5af3 Btrfs: Add backre... |
425 |
|
76dda93c6 Btrfs: add snapsh... |
426 |
BUG_ON(ret); |
f46b5a66b Btrfs: split out ... |
427 |
|
76dda93c6 Btrfs: add snapsh... |
428 |
d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry)); |
f46b5a66b Btrfs: split out ... |
429 |
fail: |
72fd032e9 Btrfs: add SNAP_C... |
430 431 432 433 434 435 |
if (async_transid) { *async_transid = trans->transid; err = btrfs_commit_transaction_async(trans, root, 1); } else { err = btrfs_commit_transaction(trans, root); } |
f46b5a66b Btrfs: split out ... |
436 437 |
if (err && !ret) ret = err; |
f46b5a66b Btrfs: split out ... |
438 439 |
return ret; } |
72fd032e9 Btrfs: add SNAP_C... |
440 |
static int create_snapshot(struct btrfs_root *root, struct dentry *dentry, |
b83cc9693 Btrfs: Add readon... |
441 442 |
char *name, int namelen, u64 *async_transid, bool readonly) |
f46b5a66b Btrfs: split out ... |
443 |
{ |
2e4bfab97 Btrfs: Avoid orph... |
444 |
struct inode *inode; |
f46b5a66b Btrfs: split out ... |
445 446 |
struct btrfs_pending_snapshot *pending_snapshot; struct btrfs_trans_handle *trans; |
2e4bfab97 Btrfs: Avoid orph... |
447 |
int ret; |
f46b5a66b Btrfs: split out ... |
448 449 450 |
if (!root->ref_cows) return -EINVAL; |
3de4586c5 Btrfs: Allow subv... |
451 |
pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_NOFS); |
a22285a6a Btrfs: Integrate ... |
452 453 454 455 |
if (!pending_snapshot) return -ENOMEM; btrfs_init_block_rsv(&pending_snapshot->block_rsv); |
3de4586c5 Btrfs: Allow subv... |
456 |
pending_snapshot->dentry = dentry; |
f46b5a66b Btrfs: split out ... |
457 |
pending_snapshot->root = root; |
b83cc9693 Btrfs: Add readon... |
458 |
pending_snapshot->readonly = readonly; |
a22285a6a Btrfs: Integrate ... |
459 460 461 462 463 464 465 466 467 |
trans = btrfs_start_transaction(root->fs_info->extent_root, 5); if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto fail; } ret = btrfs_snap_reserve_metadata(trans, pending_snapshot); BUG_ON(ret); |
8351583e3 Btrfs: protect th... |
468 |
spin_lock(&root->fs_info->trans_lock); |
f46b5a66b Btrfs: split out ... |
469 470 |
list_add(&pending_snapshot->list, &trans->transaction->pending_snapshots); |
8351583e3 Btrfs: protect th... |
471 |
spin_unlock(&root->fs_info->trans_lock); |
72fd032e9 Btrfs: add SNAP_C... |
472 473 474 475 476 477 478 479 |
if (async_transid) { *async_transid = trans->transid; ret = btrfs_commit_transaction_async(trans, root->fs_info->extent_root, 1); } else { ret = btrfs_commit_transaction(trans, root->fs_info->extent_root); } |
2e4bfab97 Btrfs: Avoid orph... |
480 |
BUG_ON(ret); |
a22285a6a Btrfs: Integrate ... |
481 482 483 484 |
ret = pending_snapshot->error; if (ret) goto fail; |
66b4ffd11 Btrfs: handle err... |
485 486 487 |
ret = btrfs_orphan_cleanup(pending_snapshot->snap); if (ret) goto fail; |
f46b5a66b Btrfs: split out ... |
488 |
|
2fbe8c8ad get rid of useles... |
489 |
inode = btrfs_lookup_dentry(dentry->d_parent->d_inode, dentry); |
2e4bfab97 Btrfs: Avoid orph... |
490 491 492 493 494 495 496 497 |
if (IS_ERR(inode)) { ret = PTR_ERR(inode); goto fail; } BUG_ON(!inode); d_instantiate(dentry, inode); ret = 0; fail: |
a22285a6a Btrfs: Integrate ... |
498 |
kfree(pending_snapshot); |
f46b5a66b Btrfs: split out ... |
499 500 |
return ret; } |
4260f7c75 Btrfs: allow subv... |
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 |
/* copy of check_sticky in fs/namei.c() * It's inline, so penalty for filesystems that don't use sticky bit is * minimal. */ static inline int btrfs_check_sticky(struct inode *dir, struct inode *inode) { uid_t fsuid = current_fsuid(); if (!(dir->i_mode & S_ISVTX)) return 0; if (inode->i_uid == fsuid) return 0; if (dir->i_uid == fsuid) return 0; return !capable(CAP_FOWNER); } /* copy of may_delete in fs/namei.c() * Check whether we can remove a link victim from directory dir, check * whether the type of victim is right. * 1. We can't do it if dir is read-only (done in permission()) * 2. We should have write and exec permissions on dir * 3. We can't remove anything from append-only dir * 4. We can't do anything with immutable dir (done in permission()) * 5. If the sticky bit on dir is set we should either * a. be owner of dir, or * b. be owner of victim, or * c. have CAP_FOWNER capability * 6. If the victim is append-only or immutable we can't do antyhing with * links pointing to it. * 7. If we were asked to remove a directory and victim isn't one - ENOTDIR. * 8. If we were asked to remove a non-directory and victim isn't one - EISDIR. * 9. We can't remove a root or mountpoint. * 10. We don't allow removal of NFS sillyrenamed files; it's handled by * nfs_async_unlink(). */ static int btrfs_may_delete(struct inode *dir,struct dentry *victim,int isdir) { int error; if (!victim->d_inode) return -ENOENT; BUG_ON(victim->d_parent->d_inode != dir); audit_inode_child(victim, dir); error = inode_permission(dir, MAY_WRITE | MAY_EXEC); if (error) return error; if (IS_APPEND(dir)) return -EPERM; if (btrfs_check_sticky(dir, victim->d_inode)|| IS_APPEND(victim->d_inode)|| IS_IMMUTABLE(victim->d_inode) || IS_SWAPFILE(victim->d_inode)) return -EPERM; if (isdir) { if (!S_ISDIR(victim->d_inode->i_mode)) return -ENOTDIR; if (IS_ROOT(victim)) return -EBUSY; } else if (S_ISDIR(victim->d_inode->i_mode)) return -EISDIR; if (IS_DEADDIR(dir)) return -ENOENT; if (victim->d_flags & DCACHE_NFSFS_RENAMED) return -EBUSY; return 0; } |
cb8e70901 Btrfs: Fix subvol... |
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 |
/* copy of may_create in fs/namei.c() */ static inline int btrfs_may_create(struct inode *dir, struct dentry *child) { if (child->d_inode) return -EEXIST; if (IS_DEADDIR(dir)) return -ENOENT; return inode_permission(dir, MAY_WRITE | MAY_EXEC); } /* * Create a new subvolume below @parent. This is largely modeled after * sys_mkdirat and vfs_mkdir, but we only do a single component lookup * inside this filesystem so it's quite a bit simpler. */ |
76dda93c6 Btrfs: add snapsh... |
585 586 |
static noinline int btrfs_mksubvol(struct path *parent, char *name, int namelen, |
72fd032e9 Btrfs: add SNAP_C... |
587 |
struct btrfs_root *snap_src, |
b83cc9693 Btrfs: Add readon... |
588 |
u64 *async_transid, bool readonly) |
cb8e70901 Btrfs: Fix subvol... |
589 |
{ |
76dda93c6 Btrfs: add snapsh... |
590 |
struct inode *dir = parent->dentry->d_inode; |
cb8e70901 Btrfs: Fix subvol... |
591 592 |
struct dentry *dentry; int error; |
76dda93c6 Btrfs: add snapsh... |
593 |
mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); |
cb8e70901 Btrfs: Fix subvol... |
594 595 596 597 598 599 600 601 602 |
dentry = lookup_one_len(name, parent->dentry, namelen); error = PTR_ERR(dentry); if (IS_ERR(dentry)) goto out_unlock; error = -EEXIST; if (dentry->d_inode) goto out_dput; |
cb8e70901 Btrfs: Fix subvol... |
603 604 605 |
error = mnt_want_write(parent->mnt); if (error) goto out_dput; |
76dda93c6 Btrfs: add snapsh... |
606 |
error = btrfs_may_create(dir, dentry); |
cb8e70901 Btrfs: Fix subvol... |
607 608 |
if (error) goto out_drop_write; |
76dda93c6 Btrfs: add snapsh... |
609 610 611 612 |
down_read(&BTRFS_I(dir)->root->fs_info->subvol_sem); if (btrfs_root_refs(&BTRFS_I(dir)->root->root_item) == 0) goto out_up_read; |
3de4586c5 Btrfs: Allow subv... |
613 |
if (snap_src) { |
72fd032e9 Btrfs: add SNAP_C... |
614 |
error = create_snapshot(snap_src, dentry, |
b83cc9693 Btrfs: Add readon... |
615 |
name, namelen, async_transid, readonly); |
3de4586c5 Btrfs: Allow subv... |
616 |
} else { |
76dda93c6 Btrfs: add snapsh... |
617 |
error = create_subvol(BTRFS_I(dir)->root, dentry, |
72fd032e9 Btrfs: add SNAP_C... |
618 |
name, namelen, async_transid); |
3de4586c5 Btrfs: Allow subv... |
619 |
} |
76dda93c6 Btrfs: add snapsh... |
620 621 622 623 |
if (!error) fsnotify_mkdir(dir, dentry); out_up_read: up_read(&BTRFS_I(dir)->root->fs_info->subvol_sem); |
cb8e70901 Btrfs: Fix subvol... |
624 625 626 627 628 |
out_drop_write: mnt_drop_write(parent->mnt); out_dput: dput(dentry); out_unlock: |
76dda93c6 Btrfs: add snapsh... |
629 |
mutex_unlock(&dir->i_mutex); |
cb8e70901 Btrfs: Fix subvol... |
630 631 |
return error; } |
4cb5300bc Btrfs: add mount ... |
632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 |
/* * When we're defragging a range, we don't want to kick it off again * if it is really just waiting for delalloc to send it down. * If we find a nice big extent or delalloc range for the bytes in the * file you want to defrag, we return 0 to let you know to skip this * part of the file */ static int check_defrag_in_cache(struct inode *inode, u64 offset, int thresh) { struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; struct extent_map *em = NULL; struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; u64 end; read_lock(&em_tree->lock); em = lookup_extent_mapping(em_tree, offset, PAGE_CACHE_SIZE); read_unlock(&em_tree->lock); if (em) { end = extent_map_end(em); free_extent_map(em); if (end - offset > thresh) return 0; } /* if we already have a nice delalloc here, just stop */ thresh /= 2; end = count_range_bits(io_tree, &offset, offset + thresh, thresh, EXTENT_DELALLOC, 1); if (end >= thresh) return 0; return 1; } /* * helper function to walk through a file and find extents * newer than a specific transid, and smaller than thresh. * * This is used by the defragging code to find new and small * extents */ static int find_new_extents(struct btrfs_root *root, struct inode *inode, u64 newer_than, u64 *off, int thresh) { struct btrfs_path *path; struct btrfs_key min_key; struct btrfs_key max_key; struct extent_buffer *leaf; struct btrfs_file_extent_item *extent; int type; int ret; |
a4689d2bd btrfs: use btrfs_... |
683 |
u64 ino = btrfs_ino(inode); |
4cb5300bc Btrfs: add mount ... |
684 685 686 687 |
path = btrfs_alloc_path(); if (!path) return -ENOMEM; |
a4689d2bd btrfs: use btrfs_... |
688 |
min_key.objectid = ino; |
4cb5300bc Btrfs: add mount ... |
689 690 |
min_key.type = BTRFS_EXTENT_DATA_KEY; min_key.offset = *off; |
a4689d2bd btrfs: use btrfs_... |
691 |
max_key.objectid = ino; |
4cb5300bc Btrfs: add mount ... |
692 693 694 695 696 697 698 699 700 701 |
max_key.type = (u8)-1; max_key.offset = (u64)-1; path->keep_locks = 1; while(1) { ret = btrfs_search_forward(root, &min_key, &max_key, path, 0, newer_than); if (ret != 0) goto none; |
a4689d2bd btrfs: use btrfs_... |
702 |
if (min_key.objectid != ino) |
4cb5300bc Btrfs: add mount ... |
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 |
goto none; if (min_key.type != BTRFS_EXTENT_DATA_KEY) goto none; leaf = path->nodes[0]; extent = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_file_extent_item); type = btrfs_file_extent_type(leaf, extent); if (type == BTRFS_FILE_EXTENT_REG && btrfs_file_extent_num_bytes(leaf, extent) < thresh && check_defrag_in_cache(inode, min_key.offset, thresh)) { *off = min_key.offset; btrfs_free_path(path); return 0; } if (min_key.offset == (u64)-1) goto none; min_key.offset++; btrfs_release_path(path); } none: btrfs_free_path(path); return -ENOENT; } |
940100a4a Btrfs: be more se... |
730 |
static int should_defrag_range(struct inode *inode, u64 start, u64 len, |
1e701a329 Btrfs: add new de... |
731 732 |
int thresh, u64 *last_len, u64 *skip, u64 *defrag_end) |
940100a4a Btrfs: be more se... |
733 734 735 736 737 738 739 |
{ struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; struct extent_map *em = NULL; struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; int ret = 1; /* |
008873eaf Btrfs: honor exte... |
740 |
* make sure that once we start defragging an extent, we keep on |
940100a4a Btrfs: be more se... |
741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 |
* defragging it */ if (start < *defrag_end) return 1; *skip = 0; /* * hopefully we have this extent in the tree already, try without * the full extent lock */ read_lock(&em_tree->lock); em = lookup_extent_mapping(em_tree, start, len); read_unlock(&em_tree->lock); if (!em) { /* get the big lock and read metadata off disk */ lock_extent(io_tree, start, start + len - 1, GFP_NOFS); em = btrfs_get_extent(inode, NULL, 0, start, len, 0); unlock_extent(io_tree, start, start + len - 1, GFP_NOFS); |
6cf8bfbf5 Btrfs: check btrf... |
761 |
if (IS_ERR(em)) |
940100a4a Btrfs: be more se... |
762 763 764 765 766 767 768 769 770 771 |
return 0; } /* this will cover holes, and inline extents */ if (em->block_start >= EXTENT_MAP_LAST_BYTE) ret = 0; /* * we hit a real extent, if it is big don't bother defragging it again */ |
1e701a329 Btrfs: add new de... |
772 |
if ((*last_len == 0 || *last_len >= thresh) && em->len >= thresh) |
940100a4a Btrfs: be more se... |
773 774 775 776 777 778 779 780 781 782 783 |
ret = 0; /* * last_len ends up being a counter of how many bytes we've defragged. * every time we choose not to defrag an extent, we reset *last_len * so that the next tiny extent will force a defrag. * * The end result of this is that tiny extents before a single big * extent will force at least part of that big extent to be defragged. */ if (ret) { |
940100a4a Btrfs: be more se... |
784 785 786 787 788 789 790 791 792 793 |
*defrag_end = extent_map_end(em); } else { *last_len = 0; *skip = extent_map_end(em); *defrag_end = 0; } free_extent_map(em); return ret; } |
4cb5300bc Btrfs: add mount ... |
794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 |
/* * it doesn't do much good to defrag one or two pages * at a time. This pulls in a nice chunk of pages * to COW and defrag. * * It also makes sure the delalloc code has enough * dirty data to avoid making new small extents as part * of the defrag * * It's a good idea to start RA on this range * before calling this. */ static int cluster_pages_for_defrag(struct inode *inode, struct page **pages, unsigned long start_index, int num_pages) |
f46b5a66b Btrfs: split out ... |
810 |
{ |
4cb5300bc Btrfs: add mount ... |
811 812 813 814 815 816 817 |
unsigned long file_end; u64 isize = i_size_read(inode); u64 page_start; u64 page_end; int ret; int i; int i_done; |
3eaa28852 Btrfs: Fix the de... |
818 |
struct btrfs_ordered_extent *ordered; |
4cb5300bc Btrfs: add mount ... |
819 |
struct extent_state *cached_state = NULL; |
3b16a4e3c Btrfs: use the in... |
820 |
gfp_t mask = btrfs_alloc_write_mask(inode->i_mapping); |
4cb5300bc Btrfs: add mount ... |
821 822 823 824 |
if (isize == 0) return 0; file_end = (isize - 1) >> PAGE_CACHE_SHIFT; |
660d3f6cd Btrfs: fix how we... |
825 |
mutex_lock(&inode->i_mutex); |
4cb5300bc Btrfs: add mount ... |
826 827 |
ret = btrfs_delalloc_reserve_space(inode, num_pages << PAGE_CACHE_SHIFT); |
660d3f6cd Btrfs: fix how we... |
828 |
mutex_unlock(&inode->i_mutex); |
4cb5300bc Btrfs: add mount ... |
829 830 831 832 833 834 835 836 837 |
if (ret) return ret; again: ret = 0; i_done = 0; /* step one, lock all the pages */ for (i = 0; i < num_pages; i++) { struct page *page; |
a94733d0b Btrfs: use find_o... |
838 |
page = find_or_create_page(inode->i_mapping, |
3b16a4e3c Btrfs: use the in... |
839 |
start_index + i, mask); |
4cb5300bc Btrfs: add mount ... |
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 |
if (!page) break; if (!PageUptodate(page)) { btrfs_readpage(NULL, page); lock_page(page); if (!PageUptodate(page)) { unlock_page(page); page_cache_release(page); ret = -EIO; break; } } isize = i_size_read(inode); file_end = (isize - 1) >> PAGE_CACHE_SHIFT; if (!isize || page->index > file_end || page->mapping != inode->i_mapping) { /* whoops, we blew past eof, skip this page */ unlock_page(page); page_cache_release(page); break; } pages[i] = page; i_done++; } if (!i_done || ret) goto out; if (!(inode->i_sb->s_flags & MS_ACTIVE)) goto out; /* * so now we have a nice long stream of locked * and up to date pages, lets wait on them */ for (i = 0; i < i_done; i++) wait_on_page_writeback(pages[i]); page_start = page_offset(pages[0]); page_end = page_offset(pages[i_done - 1]) + PAGE_CACHE_SIZE; lock_extent_bits(&BTRFS_I(inode)->io_tree, page_start, page_end - 1, 0, &cached_state, GFP_NOFS); ordered = btrfs_lookup_first_ordered_extent(inode, page_end - 1); if (ordered && ordered->file_offset + ordered->len > page_start && ordered->file_offset < page_end) { btrfs_put_ordered_extent(ordered); unlock_extent_cached(&BTRFS_I(inode)->io_tree, page_start, page_end - 1, &cached_state, GFP_NOFS); for (i = 0; i < i_done; i++) { unlock_page(pages[i]); page_cache_release(pages[i]); } btrfs_wait_ordered_range(inode, page_start, page_end - page_start); goto again; } if (ordered) btrfs_put_ordered_extent(ordered); clear_extent_bit(&BTRFS_I(inode)->io_tree, page_start, page_end - 1, EXTENT_DIRTY | EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING, 0, 0, &cached_state, GFP_NOFS); if (i_done != num_pages) { |
9e0baf60d Btrfs: fix enospc... |
909 910 911 |
spin_lock(&BTRFS_I(inode)->lock); BTRFS_I(inode)->outstanding_extents++; spin_unlock(&BTRFS_I(inode)->lock); |
4cb5300bc Btrfs: add mount ... |
912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 |
btrfs_delalloc_release_space(inode, (num_pages - i_done) << PAGE_CACHE_SHIFT); } btrfs_set_extent_delalloc(inode, page_start, page_end - 1, &cached_state); unlock_extent_cached(&BTRFS_I(inode)->io_tree, page_start, page_end - 1, &cached_state, GFP_NOFS); for (i = 0; i < i_done; i++) { clear_page_dirty_for_io(pages[i]); ClearPageChecked(pages[i]); set_page_extent_mapped(pages[i]); set_page_dirty(pages[i]); unlock_page(pages[i]); page_cache_release(pages[i]); } return i_done; out: for (i = 0; i < i_done; i++) { unlock_page(pages[i]); page_cache_release(pages[i]); } btrfs_delalloc_release_space(inode, num_pages << PAGE_CACHE_SHIFT); return ret; } int btrfs_defrag_file(struct inode *inode, struct file *file, struct btrfs_ioctl_defrag_range_args *range, u64 newer_than, unsigned long max_to_defrag) { struct btrfs_root *root = BTRFS_I(inode)->root; |
1a419d85a btrfs: Allow to s... |
948 |
struct btrfs_super_block *disk_super; |
4cb5300bc Btrfs: add mount ... |
949 |
struct file_ra_state *ra = NULL; |
f46b5a66b Btrfs: split out ... |
950 |
unsigned long last_index; |
151a31b25 Btrfs: use i_size... |
951 |
u64 isize = i_size_read(inode); |
1a419d85a btrfs: Allow to s... |
952 |
u64 features; |
940100a4a Btrfs: be more se... |
953 954 955 |
u64 last_len = 0; u64 skip = 0; u64 defrag_end = 0; |
4cb5300bc Btrfs: add mount ... |
956 |
u64 newer_off = range->start; |
f46b5a66b Btrfs: split out ... |
957 |
unsigned long i; |
008873eaf Btrfs: honor exte... |
958 |
unsigned long ra_index = 0; |
f46b5a66b Btrfs: split out ... |
959 |
int ret; |
4cb5300bc Btrfs: add mount ... |
960 |
int defrag_count = 0; |
1a419d85a btrfs: Allow to s... |
961 |
int compress_type = BTRFS_COMPRESS_ZLIB; |
4cb5300bc Btrfs: add mount ... |
962 |
int extent_thresh = range->extent_thresh; |
008873eaf Btrfs: honor exte... |
963 964 |
int max_cluster = (256 * 1024) >> PAGE_CACHE_SHIFT; int cluster = max_cluster; |
4cb5300bc Btrfs: add mount ... |
965 966 967 968 969 |
u64 new_align = ~((u64)128 * 1024 - 1); struct page **pages = NULL; if (extent_thresh == 0) extent_thresh = 256 * 1024; |
1a419d85a btrfs: Allow to s... |
970 971 972 973 974 975 976 |
if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS) { if (range->compress_type > BTRFS_COMPRESS_TYPES) return -EINVAL; if (range->compress_type) compress_type = range->compress_type; } |
f46b5a66b Btrfs: split out ... |
977 |
|
151a31b25 Btrfs: use i_size... |
978 |
if (isize == 0) |
940100a4a Btrfs: be more se... |
979 |
return 0; |
4cb5300bc Btrfs: add mount ... |
980 981 982 983 984 985 986 987 988 989 990 991 |
/* * if we were not given a file, allocate a readahead * context */ if (!file) { ra = kzalloc(sizeof(*ra), GFP_NOFS); if (!ra) return -ENOMEM; file_ra_state_init(ra, inode->i_mapping); } else { ra = &file->f_ra; } |
008873eaf Btrfs: honor exte... |
992 |
pages = kmalloc(sizeof(struct page *) * max_cluster, |
4cb5300bc Btrfs: add mount ... |
993 994 995 996 997 998 999 |
GFP_NOFS); if (!pages) { ret = -ENOMEM; goto out_ra; } /* find the last page to defrag */ |
1e701a329 Btrfs: add new de... |
1000 |
if (range->start + range->len > range->start) { |
151a31b25 Btrfs: use i_size... |
1001 |
last_index = min_t(u64, isize - 1, |
1e701a329 Btrfs: add new de... |
1002 1003 |
range->start + range->len - 1) >> PAGE_CACHE_SHIFT; } else { |
151a31b25 Btrfs: use i_size... |
1004 |
last_index = (isize - 1) >> PAGE_CACHE_SHIFT; |
1e701a329 Btrfs: add new de... |
1005 |
} |
4cb5300bc Btrfs: add mount ... |
1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 |
if (newer_than) { ret = find_new_extents(root, inode, newer_than, &newer_off, 64 * 1024); if (!ret) { range->start = newer_off; /* * we always align our defrag to help keep * the extents in the file evenly spaced */ i = (newer_off & new_align) >> PAGE_CACHE_SHIFT; |
4cb5300bc Btrfs: add mount ... |
1016 1017 1018 1019 1020 1021 |
} else goto out_ra; } else { i = range->start >> PAGE_CACHE_SHIFT; } if (!max_to_defrag) |
5ca496604 Btrfs: fix wrong ... |
1022 |
max_to_defrag = last_index; |
4cb5300bc Btrfs: add mount ... |
1023 |
|
2a0f7f576 Btrfs: fix recurs... |
1024 1025 1026 1027 1028 1029 |
/* * make writeback starts from i, so the defrag range can be * written sequentially. */ if (i < inode->i_mapping->writeback_index) inode->i_mapping->writeback_index = i; |
f7f43cc84 Btrfs: make sure ... |
1030 1031 1032 |
while (i <= last_index && defrag_count < max_to_defrag && (i < (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT)) { |
4cb5300bc Btrfs: add mount ... |
1033 1034 1035 1036 1037 1038 1039 1040 1041 |
/* * make sure we stop running if someone unmounts * the FS */ if (!(inode->i_sb->s_flags & MS_ACTIVE)) break; if (!newer_than && !should_defrag_range(inode, (u64)i << PAGE_CACHE_SHIFT, |
1e701a329 Btrfs: add new de... |
1042 |
PAGE_CACHE_SIZE, |
4cb5300bc Btrfs: add mount ... |
1043 |
extent_thresh, |
1e701a329 Btrfs: add new de... |
1044 |
&last_len, &skip, |
940100a4a Btrfs: be more se... |
1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 |
&defrag_end)) { unsigned long next; /* * the should_defrag function tells us how much to skip * bump our counter by the suggested amount */ next = (skip + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; i = max(i + 1, next); continue; } |
008873eaf Btrfs: honor exte... |
1055 1056 1057 1058 1059 1060 1061 1062 |
if (!newer_than) { cluster = (PAGE_CACHE_ALIGN(defrag_end) >> PAGE_CACHE_SHIFT) - i; cluster = min(cluster, max_cluster); } else { cluster = max_cluster; } |
1e701a329 Btrfs: add new de... |
1063 |
if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS) |
1a419d85a btrfs: Allow to s... |
1064 |
BTRFS_I(inode)->force_compress = compress_type; |
940100a4a Btrfs: be more se... |
1065 |
|
008873eaf Btrfs: honor exte... |
1066 1067 1068 1069 1070 1071 |
if (i + cluster > ra_index) { ra_index = max(i, ra_index); btrfs_force_ra(inode->i_mapping, ra, file, ra_index, cluster); ra_index += max_cluster; } |
940100a4a Btrfs: be more se... |
1072 |
|
008873eaf Btrfs: honor exte... |
1073 |
ret = cluster_pages_for_defrag(inode, pages, i, cluster); |
4cb5300bc Btrfs: add mount ... |
1074 1075 1076 1077 1078 |
if (ret < 0) goto out_ra; defrag_count += ret; balance_dirty_pages_ratelimited_nr(inode->i_mapping, ret); |
4cb5300bc Btrfs: add mount ... |
1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 |
if (newer_than) { if (newer_off == (u64)-1) break; newer_off = max(newer_off + 1, (u64)i << PAGE_CACHE_SHIFT); ret = find_new_extents(root, inode, newer_than, &newer_off, 64 * 1024); if (!ret) { range->start = newer_off; i = (newer_off & new_align) >> PAGE_CACHE_SHIFT; |
4cb5300bc Btrfs: add mount ... |
1093 1094 |
} else { break; |
f46b5a66b Btrfs: split out ... |
1095 |
} |
4cb5300bc Btrfs: add mount ... |
1096 |
} else { |
008873eaf Btrfs: honor exte... |
1097 |
if (ret > 0) { |
cbcc83265 Btrfs: fix defrag... |
1098 |
i += ret; |
008873eaf Btrfs: honor exte... |
1099 1100 |
last_len += ret << PAGE_CACHE_SHIFT; } else { |
cbcc83265 Btrfs: fix defrag... |
1101 |
i++; |
008873eaf Btrfs: honor exte... |
1102 1103 |
last_len = 0; } |
f46b5a66b Btrfs: split out ... |
1104 |
} |
f46b5a66b Btrfs: split out ... |
1105 |
} |
1e701a329 Btrfs: add new de... |
1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 |
if ((range->flags & BTRFS_DEFRAG_RANGE_START_IO)) filemap_flush(inode->i_mapping); if ((range->flags & BTRFS_DEFRAG_RANGE_COMPRESS)) { /* the filemap_flush will queue IO into the worker threads, but * we have to make sure the IO is actually started and that * ordered extents get created before we return */ atomic_inc(&root->fs_info->async_submit_draining); while (atomic_read(&root->fs_info->nr_async_submits) || atomic_read(&root->fs_info->async_delalloc_pages)) { wait_event(root->fs_info->async_submit_wait, (atomic_read(&root->fs_info->nr_async_submits) == 0 && atomic_read(&root->fs_info->async_delalloc_pages) == 0)); } atomic_dec(&root->fs_info->async_submit_draining); mutex_lock(&inode->i_mutex); |
261507a02 btrfs: Allow to a... |
1124 |
BTRFS_I(inode)->force_compress = BTRFS_COMPRESS_NONE; |
1e701a329 Btrfs: add new de... |
1125 1126 |
mutex_unlock(&inode->i_mutex); } |
6c41761fc btrfs: separate s... |
1127 |
disk_super = root->fs_info->super_copy; |
1a419d85a btrfs: Allow to s... |
1128 1129 1130 1131 1132 |
features = btrfs_super_incompat_flags(disk_super); if (range->compress_type == BTRFS_COMPRESS_LZO) { features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO; btrfs_set_super_incompat_flags(disk_super, features); } |
60ccf82f5 btrfs: fix memory... |
1133 |
ret = defrag_count; |
940100a4a Btrfs: be more se... |
1134 |
|
4cb5300bc Btrfs: add mount ... |
1135 1136 1137 1138 |
out_ra: if (!file) kfree(ra); kfree(pages); |
940100a4a Btrfs: be more se... |
1139 |
return ret; |
f46b5a66b Btrfs: split out ... |
1140 |
} |
76dda93c6 Btrfs: add snapsh... |
1141 1142 |
static noinline int btrfs_ioctl_resize(struct btrfs_root *root, void __user *arg) |
f46b5a66b Btrfs: split out ... |
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 |
{ u64 new_size; u64 old_size; u64 devid = 1; struct btrfs_ioctl_vol_args *vol_args; struct btrfs_trans_handle *trans; struct btrfs_device *device = NULL; char *sizestr; char *devstr = NULL; int ret = 0; |
f46b5a66b Btrfs: split out ... |
1153 |
int mod = 0; |
c146afad2 Btrfs: mount ro a... |
1154 1155 |
if (root->fs_info->sb->s_flags & MS_RDONLY) return -EROFS; |
e441d54de Btrfs: add permis... |
1156 1157 |
if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
dae7b665c btrfs: use memdup... |
1158 1159 1160 |
vol_args = memdup_user(arg, sizeof(*vol_args)); if (IS_ERR(vol_args)) return PTR_ERR(vol_args); |
5516e5957 Btrfs: Null termi... |
1161 1162 |
vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; |
f46b5a66b Btrfs: split out ... |
1163 |
|
7d9eb12c8 Btrfs: Add lockin... |
1164 |
mutex_lock(&root->fs_info->volume_mutex); |
f46b5a66b Btrfs: split out ... |
1165 1166 1167 1168 1169 1170 1171 1172 |
sizestr = vol_args->name; devstr = strchr(sizestr, ':'); if (devstr) { char *end; sizestr = devstr + 1; *devstr = '\0'; devstr = vol_args->name; devid = simple_strtoull(devstr, &end, 10); |
5bb146823 Btrfs: prefix res... |
1173 1174 |
printk(KERN_INFO "btrfs: resizing devid %llu ", |
21380931e Btrfs: Fix a bunc... |
1175 |
(unsigned long long)devid); |
f46b5a66b Btrfs: split out ... |
1176 |
} |
2b82032c3 Btrfs: Seed devic... |
1177 |
device = btrfs_find_device(root, devid, NULL, NULL); |
f46b5a66b Btrfs: split out ... |
1178 |
if (!device) { |
5bb146823 Btrfs: prefix res... |
1179 1180 |
printk(KERN_INFO "btrfs: resizer unable to find device %llu ", |
21380931e Btrfs: Fix a bunc... |
1181 |
(unsigned long long)devid); |
f46b5a66b Btrfs: split out ... |
1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 |
ret = -EINVAL; goto out_unlock; } if (!strcmp(sizestr, "max")) new_size = device->bdev->bd_inode->i_size; else { if (sizestr[0] == '-') { mod = -1; sizestr++; } else if (sizestr[0] == '+') { mod = 1; sizestr++; } |
91748467a btrfs: use memparse |
1195 |
new_size = memparse(sizestr, NULL); |
f46b5a66b Btrfs: split out ... |
1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 |
if (new_size == 0) { ret = -EINVAL; goto out_unlock; } } old_size = device->total_bytes; if (mod < 0) { if (new_size > old_size) { ret = -EINVAL; goto out_unlock; } new_size = old_size - new_size; } else if (mod > 0) { new_size = old_size + new_size; } if (new_size < 256 * 1024 * 1024) { ret = -EINVAL; goto out_unlock; } if (new_size > device->bdev->bd_inode->i_size) { ret = -EFBIG; goto out_unlock; } do_div(new_size, root->sectorsize); new_size *= root->sectorsize; |
5bb146823 Btrfs: prefix res... |
1225 1226 |
printk(KERN_INFO "btrfs: new size for %s is %llu ", |
f46b5a66b Btrfs: split out ... |
1227 1228 1229 |
device->name, (unsigned long long)new_size); if (new_size > old_size) { |
a22285a6a Btrfs: Integrate ... |
1230 |
trans = btrfs_start_transaction(root, 0); |
98d5dc13e btrfs: fix return... |
1231 1232 1233 1234 |
if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto out_unlock; } |
f46b5a66b Btrfs: split out ... |
1235 1236 |
ret = btrfs_grow_device(trans, device, new_size); btrfs_commit_transaction(trans, root); |
ece7d20e8 Btrfs: Don't erro... |
1237 |
} else if (new_size < old_size) { |
f46b5a66b Btrfs: split out ... |
1238 1239 1240 1241 |
ret = btrfs_shrink_device(device, new_size); } out_unlock: |
7d9eb12c8 Btrfs: Add lockin... |
1242 |
mutex_unlock(&root->fs_info->volume_mutex); |
f46b5a66b Btrfs: split out ... |
1243 1244 1245 |
kfree(vol_args); return ret; } |
72fd032e9 Btrfs: add SNAP_C... |
1246 1247 1248 1249 |
static noinline int btrfs_ioctl_snap_create_transid(struct file *file, char *name, unsigned long fd, int subvol, |
b83cc9693 Btrfs: Add readon... |
1250 1251 |
u64 *transid, bool readonly) |
f46b5a66b Btrfs: split out ... |
1252 |
{ |
cb8e70901 Btrfs: Fix subvol... |
1253 |
struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; |
3de4586c5 Btrfs: Allow subv... |
1254 |
struct file *src_file; |
f46b5a66b Btrfs: split out ... |
1255 |
int namelen; |
3de4586c5 Btrfs: Allow subv... |
1256 |
int ret = 0; |
f46b5a66b Btrfs: split out ... |
1257 |
|
c146afad2 Btrfs: mount ro a... |
1258 1259 |
if (root->fs_info->sb->s_flags & MS_RDONLY) return -EROFS; |
72fd032e9 Btrfs: add SNAP_C... |
1260 1261 |
namelen = strlen(name); if (strchr(name, '/')) { |
f46b5a66b Btrfs: split out ... |
1262 1263 1264 |
ret = -EINVAL; goto out; } |
3de4586c5 Btrfs: Allow subv... |
1265 |
if (subvol) { |
72fd032e9 Btrfs: add SNAP_C... |
1266 |
ret = btrfs_mksubvol(&file->f_path, name, namelen, |
b83cc9693 Btrfs: Add readon... |
1267 |
NULL, transid, readonly); |
cb8e70901 Btrfs: Fix subvol... |
1268 |
} else { |
3de4586c5 Btrfs: Allow subv... |
1269 |
struct inode *src_inode; |
72fd032e9 Btrfs: add SNAP_C... |
1270 |
src_file = fget(fd); |
3de4586c5 Btrfs: Allow subv... |
1271 1272 1273 1274 1275 1276 1277 |
if (!src_file) { ret = -EINVAL; goto out; } src_inode = src_file->f_path.dentry->d_inode; if (src_inode->i_sb != file->f_path.dentry->d_inode->i_sb) { |
d397712bc Btrfs: Fix checkp... |
1278 1279 1280 |
printk(KERN_INFO "btrfs: Snapshot src from " "another FS "); |
3de4586c5 Btrfs: Allow subv... |
1281 1282 1283 1284 |
ret = -EINVAL; fput(src_file); goto out; } |
72fd032e9 Btrfs: add SNAP_C... |
1285 1286 |
ret = btrfs_mksubvol(&file->f_path, name, namelen, BTRFS_I(src_inode)->root, |
b83cc9693 Btrfs: Add readon... |
1287 |
transid, readonly); |
3de4586c5 Btrfs: Allow subv... |
1288 |
fput(src_file); |
cb8e70901 Btrfs: Fix subvol... |
1289 |
} |
f46b5a66b Btrfs: split out ... |
1290 |
out: |
72fd032e9 Btrfs: add SNAP_C... |
1291 1292 1293 1294 |
return ret; } static noinline int btrfs_ioctl_snap_create(struct file *file, |
fa0d2b9bd Btrfs: Refactor b... |
1295 |
void __user *arg, int subvol) |
72fd032e9 Btrfs: add SNAP_C... |
1296 |
{ |
fa0d2b9bd Btrfs: Refactor b... |
1297 |
struct btrfs_ioctl_vol_args *vol_args; |
72fd032e9 Btrfs: add SNAP_C... |
1298 |
int ret; |
fa0d2b9bd Btrfs: Refactor b... |
1299 1300 1301 1302 |
vol_args = memdup_user(arg, sizeof(*vol_args)); if (IS_ERR(vol_args)) return PTR_ERR(vol_args); vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; |
72fd032e9 Btrfs: add SNAP_C... |
1303 |
|
fa0d2b9bd Btrfs: Refactor b... |
1304 |
ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, |
b83cc9693 Btrfs: Add readon... |
1305 1306 |
vol_args->fd, subvol, NULL, false); |
fdfb1e4f6 Btrfs: Make async... |
1307 |
|
fa0d2b9bd Btrfs: Refactor b... |
1308 1309 1310 |
kfree(vol_args); return ret; } |
fdfb1e4f6 Btrfs: Make async... |
1311 |
|
fa0d2b9bd Btrfs: Refactor b... |
1312 1313 1314 1315 1316 1317 1318 |
static noinline int btrfs_ioctl_snap_create_v2(struct file *file, void __user *arg, int subvol) { struct btrfs_ioctl_vol_args_v2 *vol_args; int ret; u64 transid = 0; u64 *ptr = NULL; |
b83cc9693 Btrfs: Add readon... |
1319 |
bool readonly = false; |
75eaa0e22 Btrfs: fix sync s... |
1320 |
|
fa0d2b9bd Btrfs: Refactor b... |
1321 1322 1323 1324 |
vol_args = memdup_user(arg, sizeof(*vol_args)); if (IS_ERR(vol_args)) return PTR_ERR(vol_args); vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0'; |
75eaa0e22 Btrfs: fix sync s... |
1325 |
|
b83cc9693 Btrfs: Add readon... |
1326 1327 1328 |
if (vol_args->flags & ~(BTRFS_SUBVOL_CREATE_ASYNC | BTRFS_SUBVOL_RDONLY)) { ret = -EOPNOTSUPP; |
fa0d2b9bd Btrfs: Refactor b... |
1329 |
goto out; |
72fd032e9 Btrfs: add SNAP_C... |
1330 |
} |
fa0d2b9bd Btrfs: Refactor b... |
1331 1332 1333 |
if (vol_args->flags & BTRFS_SUBVOL_CREATE_ASYNC) ptr = &transid; |
b83cc9693 Btrfs: Add readon... |
1334 1335 |
if (vol_args->flags & BTRFS_SUBVOL_RDONLY) readonly = true; |
fa0d2b9bd Btrfs: Refactor b... |
1336 1337 |
ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, |
b83cc9693 Btrfs: Add readon... |
1338 1339 |
vol_args->fd, subvol, ptr, readonly); |
fa0d2b9bd Btrfs: Refactor b... |
1340 1341 1342 1343 1344 1345 |
if (ret == 0 && ptr && copy_to_user(arg + offsetof(struct btrfs_ioctl_vol_args_v2, transid), ptr, sizeof(*ptr))) ret = -EFAULT; |
fdfb1e4f6 Btrfs: Make async... |
1346 |
out: |
f46b5a66b Btrfs: split out ... |
1347 1348 1349 |
kfree(vol_args); return ret; } |
0caa102da Btrfs: Add BTRFS_... |
1350 1351 1352 1353 1354 1355 1356 |
static noinline int btrfs_ioctl_subvol_getflags(struct file *file, void __user *arg) { struct inode *inode = fdentry(file)->d_inode; struct btrfs_root *root = BTRFS_I(inode)->root; int ret = 0; u64 flags = 0; |
33345d015 Btrfs: Always use... |
1357 |
if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) |
0caa102da Btrfs: Add BTRFS_... |
1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 |
return -EINVAL; down_read(&root->fs_info->subvol_sem); if (btrfs_root_readonly(root)) flags |= BTRFS_SUBVOL_RDONLY; up_read(&root->fs_info->subvol_sem); if (copy_to_user(arg, &flags, sizeof(flags))) ret = -EFAULT; return ret; } static noinline int btrfs_ioctl_subvol_setflags(struct file *file, void __user *arg) { struct inode *inode = fdentry(file)->d_inode; struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_trans_handle *trans; u64 root_flags; u64 flags; int ret = 0; if (root->fs_info->sb->s_flags & MS_RDONLY) return -EROFS; |
33345d015 Btrfs: Always use... |
1383 |
if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) |
0caa102da Btrfs: Add BTRFS_... |
1384 1385 1386 1387 |
return -EINVAL; if (copy_from_user(&flags, arg, sizeof(flags))) return -EFAULT; |
b4dc2b8c6 Btrfs: Fix BTRFS_... |
1388 |
if (flags & BTRFS_SUBVOL_CREATE_ASYNC) |
0caa102da Btrfs: Add BTRFS_... |
1389 1390 1391 1392 |
return -EINVAL; if (flags & ~BTRFS_SUBVOL_RDONLY) return -EOPNOTSUPP; |
2e1496707 userns: rename is... |
1393 |
if (!inode_owner_or_capable(inode)) |
b4dc2b8c6 Btrfs: Fix BTRFS_... |
1394 |
return -EACCES; |
0caa102da Btrfs: Add BTRFS_... |
1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 |
down_write(&root->fs_info->subvol_sem); /* nothing to do */ if (!!(flags & BTRFS_SUBVOL_RDONLY) == btrfs_root_readonly(root)) goto out; root_flags = btrfs_root_flags(&root->root_item); if (flags & BTRFS_SUBVOL_RDONLY) btrfs_set_root_flags(&root->root_item, root_flags | BTRFS_ROOT_SUBVOL_RDONLY); else btrfs_set_root_flags(&root->root_item, root_flags & ~BTRFS_ROOT_SUBVOL_RDONLY); trans = btrfs_start_transaction(root, 1); if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto out_reset; } |
b4dc2b8c6 Btrfs: Fix BTRFS_... |
1414 |
ret = btrfs_update_root(trans, root->fs_info->tree_root, |
0caa102da Btrfs: Add BTRFS_... |
1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 |
&root->root_key, &root->root_item); btrfs_commit_transaction(trans, root); out_reset: if (ret) btrfs_set_root_flags(&root->root_item, root_flags); out: up_write(&root->fs_info->subvol_sem); return ret; } |
76dda93c6 Btrfs: add snapsh... |
1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 |
/* * helper to check if the subvolume references other subvolumes */ static noinline int may_destroy_subvol(struct btrfs_root *root) { struct btrfs_path *path; struct btrfs_key key; int ret; path = btrfs_alloc_path(); if (!path) return -ENOMEM; key.objectid = root->root_key.objectid; key.type = BTRFS_ROOT_REF_KEY; key.offset = (u64)-1; ret = btrfs_search_slot(NULL, root->fs_info->tree_root, &key, path, 0, 0); if (ret < 0) goto out; BUG_ON(ret == 0); ret = 0; if (path->slots[0] > 0) { path->slots[0]--; btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); if (key.objectid == root->root_key.objectid && key.type == BTRFS_ROOT_REF_KEY) ret = -ENOTEMPTY; } out: btrfs_free_path(path); return ret; } |
ac8e9819d Btrfs: add search... |
1460 1461 1462 |
static noinline int key_in_sk(struct btrfs_key *key, struct btrfs_ioctl_search_key *sk) { |
abc6e1341 Btrfs: fix key ch... |
1463 1464 1465 1466 1467 1468 1469 1470 1471 |
struct btrfs_key test; int ret; test.objectid = sk->min_objectid; test.type = sk->min_type; test.offset = sk->min_offset; ret = btrfs_comp_cpu_keys(key, &test); if (ret < 0) |
ac8e9819d Btrfs: add search... |
1472 |
return 0; |
abc6e1341 Btrfs: fix key ch... |
1473 1474 1475 1476 1477 1478 1479 |
test.objectid = sk->max_objectid; test.type = sk->max_type; test.offset = sk->max_offset; ret = btrfs_comp_cpu_keys(key, &test); if (ret > 0) |
ac8e9819d Btrfs: add search... |
1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 |
return 0; return 1; } static noinline int copy_to_sk(struct btrfs_root *root, struct btrfs_path *path, struct btrfs_key *key, struct btrfs_ioctl_search_key *sk, char *buf, unsigned long *sk_offset, int *num_found) { u64 found_transid; struct extent_buffer *leaf; struct btrfs_ioctl_search_header sh; unsigned long item_off; unsigned long item_len; int nritems; int i; int slot; |
ac8e9819d Btrfs: add search... |
1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 |
int ret = 0; leaf = path->nodes[0]; slot = path->slots[0]; nritems = btrfs_header_nritems(leaf); if (btrfs_header_generation(leaf) > sk->max_transid) { i = nritems; goto advance_key; } found_transid = btrfs_header_generation(leaf); for (i = slot; i < nritems; i++) { item_off = btrfs_item_ptr_offset(leaf, i); item_len = btrfs_item_size_nr(leaf, i); if (item_len > BTRFS_SEARCH_ARGS_BUFSIZE) item_len = 0; if (sizeof(sh) + item_len + *sk_offset > BTRFS_SEARCH_ARGS_BUFSIZE) { ret = 1; goto overflow; } btrfs_item_key_to_cpu(leaf, key, i); if (!key_in_sk(key, sk)) continue; sh.objectid = key->objectid; sh.offset = key->offset; sh.type = key->type; sh.len = item_len; sh.transid = found_transid; /* copy search result header */ memcpy(buf + *sk_offset, &sh, sizeof(sh)); *sk_offset += sizeof(sh); if (item_len) { char *p = buf + *sk_offset; /* copy the item */ read_extent_buffer(leaf, p, item_off, item_len); *sk_offset += item_len; |
ac8e9819d Btrfs: add search... |
1545 |
} |
e21568671 btrfs: Ensure the... |
1546 |
(*num_found)++; |
ac8e9819d Btrfs: add search... |
1547 1548 1549 1550 1551 |
if (*num_found >= sk->nr_items) break; } advance_key: |
abc6e1341 Btrfs: fix key ch... |
1552 1553 |
ret = 0; if (key->offset < (u64)-1 && key->offset < sk->max_offset) |
ac8e9819d Btrfs: add search... |
1554 |
key->offset++; |
abc6e1341 Btrfs: fix key ch... |
1555 1556 |
else if (key->type < (u8)-1 && key->type < sk->max_type) { key->offset = 0; |
ac8e9819d Btrfs: add search... |
1557 |
key->type++; |
abc6e1341 Btrfs: fix key ch... |
1558 1559 1560 |
} else if (key->objectid < (u64)-1 && key->objectid < sk->max_objectid) { key->offset = 0; key->type = 0; |
ac8e9819d Btrfs: add search... |
1561 |
key->objectid++; |
abc6e1341 Btrfs: fix key ch... |
1562 1563 |
} else ret = 1; |
ac8e9819d Btrfs: add search... |
1564 |
overflow: |
ac8e9819d Btrfs: add search... |
1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 |
return ret; } static noinline int search_ioctl(struct inode *inode, struct btrfs_ioctl_search_args *args) { struct btrfs_root *root; struct btrfs_key key; struct btrfs_key max_key; struct btrfs_path *path; struct btrfs_ioctl_search_key *sk = &args->key; struct btrfs_fs_info *info = BTRFS_I(inode)->root->fs_info; int ret; int num_found = 0; unsigned long sk_offset = 0; path = btrfs_alloc_path(); if (!path) return -ENOMEM; if (sk->tree_id == 0) { /* search the root of the inode that was passed */ root = BTRFS_I(inode)->root; } else { key.objectid = sk->tree_id; key.type = BTRFS_ROOT_ITEM_KEY; key.offset = (u64)-1; root = btrfs_read_fs_root_no_name(info, &key); if (IS_ERR(root)) { printk(KERN_ERR "could not find root %llu ", sk->tree_id); btrfs_free_path(path); return -ENOENT; } } key.objectid = sk->min_objectid; key.type = sk->min_type; key.offset = sk->min_offset; max_key.objectid = sk->max_objectid; max_key.type = sk->max_type; max_key.offset = sk->max_offset; path->keep_locks = 1; while(1) { ret = btrfs_search_forward(root, &key, &max_key, path, 0, sk->min_transid); if (ret != 0) { if (ret > 0) ret = 0; goto err; } ret = copy_to_sk(root, path, &key, sk, args->buf, &sk_offset, &num_found); |
b3b4aa74b btrfs: drop unuse... |
1622 |
btrfs_release_path(path); |
ac8e9819d Btrfs: add search... |
1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 |
if (ret || num_found >= sk->nr_items) break; } ret = 0; err: sk->nr_items = num_found; btrfs_free_path(path); return ret; } static noinline int btrfs_ioctl_tree_search(struct file *file, void __user *argp) { struct btrfs_ioctl_search_args *args; struct inode *inode; int ret; if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
2354d08fe Btrfs: use memdup... |
1643 1644 1645 |
args = memdup_user(argp, sizeof(*args)); if (IS_ERR(args)) return PTR_ERR(args); |
ac8e9819d Btrfs: add search... |
1646 |
|
ac8e9819d Btrfs: add search... |
1647 1648 1649 1650 1651 1652 1653 |
inode = fdentry(file)->d_inode; ret = search_ioctl(inode, args); if (ret == 0 && copy_to_user(argp, args, sizeof(*args))) ret = -EFAULT; kfree(args); return ret; } |
98d377a08 Btrfs: add a func... |
1654 |
/* |
ac8e9819d Btrfs: add search... |
1655 1656 1657 |
* Search INODE_REFs to identify path name of 'dirid' directory * in a 'tree_id' tree. and sets path name to 'name'. */ |
98d377a08 Btrfs: add a func... |
1658 1659 1660 1661 1662 |
static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info, u64 tree_id, u64 dirid, char *name) { struct btrfs_root *root; struct btrfs_key key; |
ac8e9819d Btrfs: add search... |
1663 |
char *ptr; |
98d377a08 Btrfs: add a func... |
1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 |
int ret = -1; int slot; int len; int total_len = 0; struct btrfs_inode_ref *iref; struct extent_buffer *l; struct btrfs_path *path; if (dirid == BTRFS_FIRST_FREE_OBJECTID) { name[0]='\0'; return 0; } path = btrfs_alloc_path(); if (!path) return -ENOMEM; |
ac8e9819d Btrfs: add search... |
1680 |
ptr = &name[BTRFS_INO_LOOKUP_PATH_MAX]; |
98d377a08 Btrfs: add a func... |
1681 1682 1683 1684 1685 1686 1687 1688 |
key.objectid = tree_id; key.type = BTRFS_ROOT_ITEM_KEY; key.offset = (u64)-1; root = btrfs_read_fs_root_no_name(info, &key); if (IS_ERR(root)) { printk(KERN_ERR "could not find root %llu ", tree_id); |
8ad6fcab5 Btrfs: fix the in... |
1689 1690 |
ret = -ENOENT; goto out; |
98d377a08 Btrfs: add a func... |
1691 1692 1693 1694 |
} key.objectid = dirid; key.type = BTRFS_INODE_REF_KEY; |
8ad6fcab5 Btrfs: fix the in... |
1695 |
key.offset = (u64)-1; |
98d377a08 Btrfs: add a func... |
1696 1697 1698 1699 1700 1701 1702 1703 |
while(1) { ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto out; l = path->nodes[0]; slot = path->slots[0]; |
8ad6fcab5 Btrfs: fix the in... |
1704 1705 |
if (ret > 0 && slot > 0) slot--; |
98d377a08 Btrfs: add a func... |
1706 1707 1708 |
btrfs_item_key_to_cpu(l, &key, slot); if (ret > 0 && (key.objectid != dirid || |
ac8e9819d Btrfs: add search... |
1709 1710 |
key.type != BTRFS_INODE_REF_KEY)) { ret = -ENOENT; |
98d377a08 Btrfs: add a func... |
1711 |
goto out; |
ac8e9819d Btrfs: add search... |
1712 |
} |
98d377a08 Btrfs: add a func... |
1713 1714 1715 1716 1717 |
iref = btrfs_item_ptr(l, slot, struct btrfs_inode_ref); len = btrfs_inode_ref_name_len(l, iref); ptr -= len + 1; total_len += len + 1; |
ac8e9819d Btrfs: add search... |
1718 |
if (ptr < name) |
98d377a08 Btrfs: add a func... |
1719 1720 1721 1722 1723 1724 1725 |
goto out; *(ptr + len) = '/'; read_extent_buffer(l, ptr,(unsigned long)(iref + 1), len); if (key.offset == BTRFS_FIRST_FREE_OBJECTID) break; |
b3b4aa74b btrfs: drop unuse... |
1726 |
btrfs_release_path(path); |
98d377a08 Btrfs: add a func... |
1727 |
key.objectid = key.offset; |
8ad6fcab5 Btrfs: fix the in... |
1728 |
key.offset = (u64)-1; |
98d377a08 Btrfs: add a func... |
1729 |
dirid = key.objectid; |
98d377a08 Btrfs: add a func... |
1730 |
} |
ac8e9819d Btrfs: add search... |
1731 |
if (ptr < name) |
98d377a08 Btrfs: add a func... |
1732 |
goto out; |
77906a507 Btrfs: copy strin... |
1733 |
memmove(name, ptr, total_len); |
98d377a08 Btrfs: add a func... |
1734 1735 1736 1737 |
name[total_len]='\0'; ret = 0; out: btrfs_free_path(path); |
ac8e9819d Btrfs: add search... |
1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 |
return ret; } static noinline int btrfs_ioctl_ino_lookup(struct file *file, void __user *argp) { struct btrfs_ioctl_ino_lookup_args *args; struct inode *inode; int ret; if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
2354d08fe Btrfs: use memdup... |
1750 1751 1752 |
args = memdup_user(argp, sizeof(*args)); if (IS_ERR(args)) return PTR_ERR(args); |
c2b96929e Btrfs: handle kma... |
1753 |
|
ac8e9819d Btrfs: add search... |
1754 |
inode = fdentry(file)->d_inode; |
1b53ac4d1 Btrfs: allow tree... |
1755 1756 |
if (args->treeid == 0) args->treeid = BTRFS_I(inode)->root->root_key.objectid; |
ac8e9819d Btrfs: add search... |
1757 1758 1759 1760 1761 1762 1763 1764 |
ret = btrfs_search_path_in_tree(BTRFS_I(inode)->root->fs_info, args->treeid, args->objectid, args->name); if (ret == 0 && copy_to_user(argp, args, sizeof(*args))) ret = -EFAULT; kfree(args); |
98d377a08 Btrfs: add a func... |
1765 1766 |
return ret; } |
76dda93c6 Btrfs: add snapsh... |
1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 |
static noinline int btrfs_ioctl_snap_destroy(struct file *file, void __user *arg) { struct dentry *parent = fdentry(file); struct dentry *dentry; struct inode *dir = parent->d_inode; struct inode *inode; struct btrfs_root *root = BTRFS_I(dir)->root; struct btrfs_root *dest = NULL; struct btrfs_ioctl_vol_args *vol_args; struct btrfs_trans_handle *trans; int namelen; int ret; int err = 0; |
76dda93c6 Btrfs: add snapsh... |
1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 |
vol_args = memdup_user(arg, sizeof(*vol_args)); if (IS_ERR(vol_args)) return PTR_ERR(vol_args); vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; namelen = strlen(vol_args->name); if (strchr(vol_args->name, '/') || strncmp(vol_args->name, "..", namelen) == 0) { err = -EINVAL; goto out; } |
a561be710 switch a bunch of... |
1792 |
err = mnt_want_write_file(file); |
76dda93c6 Btrfs: add snapsh... |
1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 |
if (err) goto out; mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT); dentry = lookup_one_len(vol_args->name, parent, namelen); if (IS_ERR(dentry)) { err = PTR_ERR(dentry); goto out_unlock_dir; } if (!dentry->d_inode) { err = -ENOENT; goto out_dput; } inode = dentry->d_inode; |
4260f7c75 Btrfs: allow subv... |
1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 |
dest = BTRFS_I(inode)->root; if (!capable(CAP_SYS_ADMIN)){ /* * Regular user. Only allow this with a special mount * option, when the user has write+exec access to the * subvol root, and when rmdir(2) would have been * allowed. * * Note that this is _not_ check that the subvol is * empty or doesn't contain data that we wouldn't * otherwise be able to delete. * * Users who want to delete empty subvols should try * rmdir(2). */ err = -EPERM; if (!btrfs_test_opt(root, USER_SUBVOL_RM_ALLOWED)) goto out_dput; /* * Do not allow deletion if the parent dir is the same * as the dir to be deleted. That means the ioctl * must be called on the dentry referencing the root * of the subvol, not a random directory contained * within it. */ err = -EINVAL; if (root == dest) goto out_dput; err = inode_permission(inode, MAY_WRITE | MAY_EXEC); if (err) goto out_dput; /* check if subvolume may be deleted by a non-root user */ err = btrfs_may_delete(dir, dentry, 1); if (err) goto out_dput; } |
33345d015 Btrfs: Always use... |
1848 |
if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) { |
76dda93c6 Btrfs: add snapsh... |
1849 1850 1851 |
err = -EINVAL; goto out_dput; } |
76dda93c6 Btrfs: add snapsh... |
1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 |
mutex_lock(&inode->i_mutex); err = d_invalidate(dentry); if (err) goto out_unlock; down_write(&root->fs_info->subvol_sem); err = may_destroy_subvol(dest); if (err) goto out_up_write; |
a22285a6a Btrfs: Integrate ... |
1862 1863 1864 |
trans = btrfs_start_transaction(root, 0); if (IS_ERR(trans)) { err = PTR_ERR(trans); |
d327099a2 Btrfs: unwind aft... |
1865 |
goto out_up_write; |
a22285a6a Btrfs: Integrate ... |
1866 1867 |
} trans->block_rsv = &root->fs_info->global_block_rsv; |
76dda93c6 Btrfs: add snapsh... |
1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 |
ret = btrfs_unlink_subvol(trans, root, dir, dest->root_key.objectid, dentry->d_name.name, dentry->d_name.len); BUG_ON(ret); btrfs_record_root_in_trans(trans, dest); memset(&dest->root_item.drop_progress, 0, sizeof(dest->root_item.drop_progress)); dest->root_item.drop_level = 0; btrfs_set_root_refs(&dest->root_item, 0); |
d68fc57b7 Btrfs: Metadata r... |
1880 1881 1882 1883 1884 1885 |
if (!xchg(&dest->orphan_item_inserted, 1)) { ret = btrfs_insert_orphan_item(trans, root->fs_info->tree_root, dest->root_key.objectid); BUG_ON(ret); } |
76dda93c6 Btrfs: add snapsh... |
1886 |
|
531cb13f1 Btrfs: make SNAP_... |
1887 |
ret = btrfs_end_transaction(trans, root); |
76dda93c6 Btrfs: add snapsh... |
1888 1889 1890 1891 1892 1893 1894 |
BUG_ON(ret); inode->i_flags |= S_DEAD; out_up_write: up_write(&root->fs_info->subvol_sem); out_unlock: mutex_unlock(&inode->i_mutex); if (!err) { |
efefb1438 Btrfs: remove neg... |
1895 |
shrink_dcache_sb(root->fs_info->sb); |
76dda93c6 Btrfs: add snapsh... |
1896 1897 1898 1899 1900 1901 1902 |
btrfs_invalidate_inodes(dest); d_delete(dentry); } out_dput: dput(dentry); out_unlock_dir: mutex_unlock(&dir->i_mutex); |
2a79f17e4 vfs: mnt_drop_wri... |
1903 |
mnt_drop_write_file(file); |
76dda93c6 Btrfs: add snapsh... |
1904 1905 1906 1907 |
out: kfree(vol_args); return err; } |
1e701a329 Btrfs: add new de... |
1908 |
static int btrfs_ioctl_defrag(struct file *file, void __user *argp) |
f46b5a66b Btrfs: split out ... |
1909 1910 1911 |
{ struct inode *inode = fdentry(file)->d_inode; struct btrfs_root *root = BTRFS_I(inode)->root; |
1e701a329 Btrfs: add new de... |
1912 |
struct btrfs_ioctl_defrag_range_args *range; |
c146afad2 Btrfs: mount ro a... |
1913 |
int ret; |
b83cc9693 Btrfs: Add readon... |
1914 1915 |
if (btrfs_root_readonly(root)) return -EROFS; |
a561be710 switch a bunch of... |
1916 |
ret = mnt_want_write_file(file); |
c146afad2 Btrfs: mount ro a... |
1917 1918 |
if (ret) return ret; |
f46b5a66b Btrfs: split out ... |
1919 1920 1921 |
switch (inode->i_mode & S_IFMT) { case S_IFDIR: |
e441d54de Btrfs: add permis... |
1922 1923 1924 1925 |
if (!capable(CAP_SYS_ADMIN)) { ret = -EPERM; goto out; } |
8929ecfa5 Btrfs: Introduce ... |
1926 1927 1928 1929 |
ret = btrfs_defrag_root(root, 0); if (ret) goto out; ret = btrfs_defrag_root(root->fs_info->extent_root, 0); |
f46b5a66b Btrfs: split out ... |
1930 1931 |
break; case S_IFREG: |
e441d54de Btrfs: add permis... |
1932 1933 1934 1935 |
if (!(file->f_mode & FMODE_WRITE)) { ret = -EINVAL; goto out; } |
1e701a329 Btrfs: add new de... |
1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 |
range = kzalloc(sizeof(*range), GFP_KERNEL); if (!range) { ret = -ENOMEM; goto out; } if (argp) { if (copy_from_user(range, argp, sizeof(*range))) { ret = -EFAULT; kfree(range); |
683be16eb Btrfs: dereferenc... |
1948 |
goto out; |
1e701a329 Btrfs: add new de... |
1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 |
} /* compression requires us to start the IO */ if ((range->flags & BTRFS_DEFRAG_RANGE_COMPRESS)) { range->flags |= BTRFS_DEFRAG_RANGE_START_IO; range->extent_thresh = (u32)-1; } } else { /* the rest are all set to zero by kzalloc */ range->len = (u64)-1; } |
4cb5300bc Btrfs: add mount ... |
1959 1960 1961 1962 |
ret = btrfs_defrag_file(fdentry(file)->d_inode, file, range, 0, 0); if (ret > 0) ret = 0; |
1e701a329 Btrfs: add new de... |
1963 |
kfree(range); |
f46b5a66b Btrfs: split out ... |
1964 |
break; |
8929ecfa5 Btrfs: Introduce ... |
1965 1966 |
default: ret = -EINVAL; |
f46b5a66b Btrfs: split out ... |
1967 |
} |
e441d54de Btrfs: add permis... |
1968 |
out: |
2a79f17e4 vfs: mnt_drop_wri... |
1969 |
mnt_drop_write_file(file); |
e441d54de Btrfs: add permis... |
1970 |
return ret; |
f46b5a66b Btrfs: split out ... |
1971 |
} |
b2950863c Btrfs: make thing... |
1972 |
static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg) |
f46b5a66b Btrfs: split out ... |
1973 1974 1975 |
{ struct btrfs_ioctl_vol_args *vol_args; int ret; |
e441d54de Btrfs: add permis... |
1976 1977 |
if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
dae7b665c btrfs: use memdup... |
1978 1979 1980 |
vol_args = memdup_user(arg, sizeof(*vol_args)); if (IS_ERR(vol_args)) return PTR_ERR(vol_args); |
f46b5a66b Btrfs: split out ... |
1981 |
|
5516e5957 Btrfs: Null termi... |
1982 |
vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; |
f46b5a66b Btrfs: split out ... |
1983 |
ret = btrfs_init_new_device(root, vol_args->name); |
f46b5a66b Btrfs: split out ... |
1984 1985 1986 |
kfree(vol_args); return ret; } |
b2950863c Btrfs: make thing... |
1987 |
static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg) |
f46b5a66b Btrfs: split out ... |
1988 1989 1990 |
{ struct btrfs_ioctl_vol_args *vol_args; int ret; |
e441d54de Btrfs: add permis... |
1991 1992 |
if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
c146afad2 Btrfs: mount ro a... |
1993 1994 |
if (root->fs_info->sb->s_flags & MS_RDONLY) return -EROFS; |
dae7b665c btrfs: use memdup... |
1995 1996 1997 |
vol_args = memdup_user(arg, sizeof(*vol_args)); if (IS_ERR(vol_args)) return PTR_ERR(vol_args); |
f46b5a66b Btrfs: split out ... |
1998 |
|
5516e5957 Btrfs: Null termi... |
1999 |
vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; |
f46b5a66b Btrfs: split out ... |
2000 |
ret = btrfs_rm_device(root, vol_args->name); |
f46b5a66b Btrfs: split out ... |
2001 2002 2003 |
kfree(vol_args); return ret; } |
475f63874 btrfs: new ioctls... |
2004 2005 |
static long btrfs_ioctl_fs_info(struct btrfs_root *root, void __user *arg) { |
027ed2f00 Btrfs: avoid stac... |
2006 |
struct btrfs_ioctl_fs_info_args *fi_args; |
475f63874 btrfs: new ioctls... |
2007 2008 2009 |
struct btrfs_device *device; struct btrfs_device *next; struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices; |
027ed2f00 Btrfs: avoid stac... |
2010 |
int ret = 0; |
475f63874 btrfs: new ioctls... |
2011 2012 2013 |
if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
027ed2f00 Btrfs: avoid stac... |
2014 2015 2016 2017 2018 2019 |
fi_args = kzalloc(sizeof(*fi_args), GFP_KERNEL); if (!fi_args) return -ENOMEM; fi_args->num_devices = fs_devices->num_devices; memcpy(&fi_args->fsid, root->fs_info->fsid, sizeof(fi_args->fsid)); |
475f63874 btrfs: new ioctls... |
2020 2021 2022 |
mutex_lock(&fs_devices->device_list_mutex); list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) { |
027ed2f00 Btrfs: avoid stac... |
2023 2024 |
if (device->devid > fi_args->max_id) fi_args->max_id = device->devid; |
475f63874 btrfs: new ioctls... |
2025 2026 |
} mutex_unlock(&fs_devices->device_list_mutex); |
027ed2f00 Btrfs: avoid stac... |
2027 2028 |
if (copy_to_user(arg, fi_args, sizeof(*fi_args))) ret = -EFAULT; |
475f63874 btrfs: new ioctls... |
2029 |
|
027ed2f00 Btrfs: avoid stac... |
2030 2031 |
kfree(fi_args); return ret; |
475f63874 btrfs: new ioctls... |
2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 |
} static long btrfs_ioctl_dev_info(struct btrfs_root *root, void __user *arg) { struct btrfs_ioctl_dev_info_args *di_args; struct btrfs_device *dev; struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices; int ret = 0; char *s_uuid = NULL; char empty_uuid[BTRFS_UUID_SIZE] = {0}; if (!capable(CAP_SYS_ADMIN)) return -EPERM; di_args = memdup_user(arg, sizeof(*di_args)); if (IS_ERR(di_args)) return PTR_ERR(di_args); if (memcmp(empty_uuid, di_args->uuid, BTRFS_UUID_SIZE) != 0) s_uuid = di_args->uuid; mutex_lock(&fs_devices->device_list_mutex); dev = btrfs_find_device(root, di_args->devid, s_uuid, NULL); mutex_unlock(&fs_devices->device_list_mutex); if (!dev) { ret = -ENODEV; goto out; } di_args->devid = dev->devid; di_args->bytes_used = dev->bytes_used; di_args->total_bytes = dev->total_bytes; memcpy(di_args->uuid, dev->uuid, sizeof(di_args->uuid)); strncpy(di_args->path, dev->name, sizeof(di_args->path)); out: if (ret == 0 && copy_to_user(arg, di_args, sizeof(*di_args))) ret = -EFAULT; kfree(di_args); return ret; } |
76dda93c6 Btrfs: add snapsh... |
2075 2076 |
static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, u64 off, u64 olen, u64 destoff) |
f46b5a66b Btrfs: split out ... |
2077 2078 2079 2080 2081 2082 |
{ struct inode *inode = fdentry(file)->d_inode; struct btrfs_root *root = BTRFS_I(inode)->root; struct file *src_file; struct inode *src; struct btrfs_trans_handle *trans; |
f46b5a66b Btrfs: split out ... |
2083 |
struct btrfs_path *path; |
f46b5a66b Btrfs: split out ... |
2084 |
struct extent_buffer *leaf; |
ae01a0abf Btrfs: Update clo... |
2085 2086 |
char *buf; struct btrfs_key key; |
f46b5a66b Btrfs: split out ... |
2087 2088 |
u32 nritems; int slot; |
ae01a0abf Btrfs: Update clo... |
2089 |
int ret; |
c5c9cd4d1 Btrfs: allow clon... |
2090 2091 2092 |
u64 len = olen; u64 bs = root->fs_info->sb->s_blocksize; u64 hint_byte; |
d20f7043f Btrfs: move data ... |
2093 |
|
c5c9cd4d1 Btrfs: allow clon... |
2094 2095 2096 2097 2098 2099 2100 2101 2102 |
/* * TODO: * - split compressed inline extents. annoying: we need to * decompress into destination's address_space (the file offset * may change, so source mapping won't do), then recompress (or * otherwise reinsert) a subrange. * - allow ranges within the same file to be cloned (provided * they don't overlap)? */ |
e441d54de Btrfs: add permis... |
2103 |
/* the destination must be opened for writing */ |
2ebc34647 Btrfs: fix checks... |
2104 |
if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND)) |
e441d54de Btrfs: add permis... |
2105 |
return -EINVAL; |
b83cc9693 Btrfs: Add readon... |
2106 2107 |
if (btrfs_root_readonly(root)) return -EROFS; |
a561be710 switch a bunch of... |
2108 |
ret = mnt_want_write_file(file); |
c146afad2 Btrfs: mount ro a... |
2109 2110 |
if (ret) return ret; |
c5c9cd4d1 Btrfs: allow clon... |
2111 |
src_file = fget(srcfd); |
ab67b7c1f Btrfs: Add missin... |
2112 2113 2114 2115 |
if (!src_file) { ret = -EBADF; goto out_drop_write; } |
5dc641641 Btrfs: check for ... |
2116 |
|
f46b5a66b Btrfs: split out ... |
2117 |
src = src_file->f_dentry->d_inode; |
c5c9cd4d1 Btrfs: allow clon... |
2118 2119 2120 |
ret = -EINVAL; if (src == inode) goto out_fput; |
5dc641641 Btrfs: check for ... |
2121 2122 2123 |
/* the src must be open for reading */ if (!(src_file->f_mode & FMODE_READ)) goto out_fput; |
0e7b824c4 Btrfs: don't make... |
2124 2125 2126 2127 |
/* don't make the dst file partly checksummed */ if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) != (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) goto out_fput; |
ae01a0abf Btrfs: Update clo... |
2128 2129 2130 |
ret = -EISDIR; if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode)) goto out_fput; |
f46b5a66b Btrfs: split out ... |
2131 |
ret = -EXDEV; |
ae01a0abf Btrfs: Update clo... |
2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 |
if (src->i_sb != inode->i_sb || BTRFS_I(src)->root != root) goto out_fput; ret = -ENOMEM; buf = vmalloc(btrfs_level_size(root, 0)); if (!buf) goto out_fput; path = btrfs_alloc_path(); if (!path) { vfree(buf); |
f46b5a66b Btrfs: split out ... |
2143 |
goto out_fput; |
ae01a0abf Btrfs: Update clo... |
2144 2145 |
} path->reada = 2; |
f46b5a66b Btrfs: split out ... |
2146 2147 |
if (inode < src) { |
fccdae435 Btrfs: fix lockde... |
2148 2149 |
mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT); mutex_lock_nested(&src->i_mutex, I_MUTEX_CHILD); |
f46b5a66b Btrfs: split out ... |
2150 |
} else { |
fccdae435 Btrfs: fix lockde... |
2151 2152 |
mutex_lock_nested(&src->i_mutex, I_MUTEX_PARENT); mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD); |
f46b5a66b Btrfs: split out ... |
2153 |
} |
c5c9cd4d1 Btrfs: allow clon... |
2154 2155 |
/* determine range to clone */ ret = -EINVAL; |
2ebc34647 Btrfs: fix checks... |
2156 |
if (off + len > src->i_size || off + len < off) |
f46b5a66b Btrfs: split out ... |
2157 |
goto out_unlock; |
c5c9cd4d1 Btrfs: allow clon... |
2158 2159 2160 2161 |
if (len == 0) olen = len = src->i_size - off; /* if we extend to eof, continue to block boundary */ if (off + len == src->i_size) |
2a6b8daed btrfs: Check if d... |
2162 |
len = ALIGN(src->i_size, bs) - off; |
c5c9cd4d1 Btrfs: allow clon... |
2163 2164 |
/* verify the end result is block aligned */ |
2a6b8daed btrfs: Check if d... |
2165 2166 |
if (!IS_ALIGNED(off, bs) || !IS_ALIGNED(off + len, bs) || !IS_ALIGNED(destoff, bs)) |
c5c9cd4d1 Btrfs: allow clon... |
2167 |
goto out_unlock; |
d525e8ab0 Btrfs: add dummy ... |
2168 2169 2170 2171 2172 |
if (destoff > inode->i_size) { ret = btrfs_cont_expand(inode, inode->i_size, destoff); if (ret) goto out_unlock; } |
71ef07861 Btrfs: fix pages ... |
2173 2174 2175 |
/* truncate page cache pages from target inode range */ truncate_inode_pages_range(&inode->i_data, destoff, PAGE_CACHE_ALIGN(destoff + len) - 1); |
f46b5a66b Btrfs: split out ... |
2176 2177 2178 |
/* do any pending delalloc/csum calc on src, one way or another, and lock file content */ while (1) { |
31840ae1a Btrfs: Full back ... |
2179 |
struct btrfs_ordered_extent *ordered; |
c5c9cd4d1 Btrfs: allow clon... |
2180 |
lock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS); |
9a019196e Btrfs: fix delall... |
2181 2182 2183 2184 |
ordered = btrfs_lookup_first_ordered_extent(src, off+len); if (!ordered && !test_range_bit(&BTRFS_I(src)->io_tree, off, off+len, EXTENT_DELALLOC, 0, NULL)) |
f46b5a66b Btrfs: split out ... |
2185 |
break; |
c5c9cd4d1 Btrfs: allow clon... |
2186 |
unlock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS); |
ae01a0abf Btrfs: Update clo... |
2187 2188 |
if (ordered) btrfs_put_ordered_extent(ordered); |
9a019196e Btrfs: fix delall... |
2189 |
btrfs_wait_ordered_range(src, off, len); |
f46b5a66b Btrfs: split out ... |
2190 |
} |
c5c9cd4d1 Btrfs: allow clon... |
2191 |
/* clone data */ |
33345d015 Btrfs: Always use... |
2192 |
key.objectid = btrfs_ino(src); |
ae01a0abf Btrfs: Update clo... |
2193 2194 |
key.type = BTRFS_EXTENT_DATA_KEY; key.offset = 0; |
f46b5a66b Btrfs: split out ... |
2195 2196 2197 2198 2199 2200 |
while (1) { /* * note the key will change type as we walk through the * tree. */ |
a22285a6a Btrfs: Integrate ... |
2201 |
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); |
f46b5a66b Btrfs: split out ... |
2202 2203 |
if (ret < 0) goto out; |
ae01a0abf Btrfs: Update clo... |
2204 2205 |
nritems = btrfs_header_nritems(path->nodes[0]); if (path->slots[0] >= nritems) { |
f46b5a66b Btrfs: split out ... |
2206 2207 2208 2209 2210 |
ret = btrfs_next_leaf(root, path); if (ret < 0) goto out; if (ret > 0) break; |
ae01a0abf Btrfs: Update clo... |
2211 |
nritems = btrfs_header_nritems(path->nodes[0]); |
f46b5a66b Btrfs: split out ... |
2212 2213 2214 |
} leaf = path->nodes[0]; slot = path->slots[0]; |
f46b5a66b Btrfs: split out ... |
2215 |
|
ae01a0abf Btrfs: Update clo... |
2216 |
btrfs_item_key_to_cpu(leaf, &key, slot); |
d20f7043f Btrfs: move data ... |
2217 |
if (btrfs_key_type(&key) > BTRFS_EXTENT_DATA_KEY || |
33345d015 Btrfs: Always use... |
2218 |
key.objectid != btrfs_ino(src)) |
f46b5a66b Btrfs: split out ... |
2219 |
break; |
c5c9cd4d1 Btrfs: allow clon... |
2220 2221 2222 |
if (btrfs_key_type(&key) == BTRFS_EXTENT_DATA_KEY) { struct btrfs_file_extent_item *extent; int type; |
31840ae1a Btrfs: Full back ... |
2223 2224 |
u32 size; struct btrfs_key new_key; |
c5c9cd4d1 Btrfs: allow clon... |
2225 2226 2227 |
u64 disko = 0, diskl = 0; u64 datao = 0, datal = 0; u8 comp; |
b5384d48f Btrfs: fix CLONE ... |
2228 |
u64 endoff; |
31840ae1a Btrfs: Full back ... |
2229 2230 2231 2232 2233 |
size = btrfs_item_size_nr(leaf, slot); read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf, slot), size); |
c5c9cd4d1 Btrfs: allow clon... |
2234 2235 2236 2237 2238 |
extent = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); comp = btrfs_file_extent_compression(leaf, extent); type = btrfs_file_extent_type(leaf, extent); |
c8a894d77 Btrfs: fix the fi... |
2239 2240 |
if (type == BTRFS_FILE_EXTENT_REG || type == BTRFS_FILE_EXTENT_PREALLOC) { |
d397712bc Btrfs: Fix checkp... |
2241 2242 2243 2244 |
disko = btrfs_file_extent_disk_bytenr(leaf, extent); diskl = btrfs_file_extent_disk_num_bytes(leaf, extent); |
c5c9cd4d1 Btrfs: allow clon... |
2245 |
datao = btrfs_file_extent_offset(leaf, extent); |
d397712bc Btrfs: Fix checkp... |
2246 2247 |
datal = btrfs_file_extent_num_bytes(leaf, extent); |
c5c9cd4d1 Btrfs: allow clon... |
2248 2249 2250 2251 2252 |
} else if (type == BTRFS_FILE_EXTENT_INLINE) { /* take upper bound, may be compressed */ datal = btrfs_file_extent_ram_bytes(leaf, extent); } |
b3b4aa74b btrfs: drop unuse... |
2253 |
btrfs_release_path(path); |
31840ae1a Btrfs: Full back ... |
2254 |
|
050006a75 Btrfs: fix clone ... |
2255 |
if (key.offset + datal <= off || |
c5c9cd4d1 Btrfs: allow clon... |
2256 2257 |
key.offset >= off+len) goto next; |
31840ae1a Btrfs: Full back ... |
2258 |
memcpy(&new_key, &key, sizeof(new_key)); |
33345d015 Btrfs: Always use... |
2259 |
new_key.objectid = btrfs_ino(inode); |
4d728ec7a Btrfs: Fix file c... |
2260 2261 2262 2263 |
if (off <= key.offset) new_key.offset = key.offset + destoff - off; else new_key.offset = destoff; |
31840ae1a Btrfs: Full back ... |
2264 |
|
b6f3409b2 Btrfs: reserve su... |
2265 2266 2267 2268 2269 2270 |
/* * 1 - adjusting old extent (we may have to split it) * 1 - add new extent * 1 - inode update */ trans = btrfs_start_transaction(root, 3); |
a22285a6a Btrfs: Integrate ... |
2271 2272 2273 2274 |
if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto out; } |
c8a894d77 Btrfs: fix the fi... |
2275 2276 |
if (type == BTRFS_FILE_EXTENT_REG || type == BTRFS_FILE_EXTENT_PREALLOC) { |
d72c0842f Btrfs: calc file ... |
2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 |
/* * a | --- range to clone ---| b * | ------------- extent ------------- | */ /* substract range b */ if (key.offset + datal > off + len) datal = off + len - key.offset; /* substract range a */ |
a22285a6a Btrfs: Integrate ... |
2287 2288 2289 2290 |
if (off > key.offset) { datao += off - key.offset; datal -= off - key.offset; } |
a22285a6a Btrfs: Integrate ... |
2291 2292 2293 2294 2295 |
ret = btrfs_drop_extents(trans, inode, new_key.offset, new_key.offset + datal, &hint_byte, 1); BUG_ON(ret); |
c5c9cd4d1 Btrfs: allow clon... |
2296 2297 |
ret = btrfs_insert_empty_item(trans, root, path, &new_key, size); |
a22285a6a Btrfs: Integrate ... |
2298 |
BUG_ON(ret); |
c5c9cd4d1 Btrfs: allow clon... |
2299 2300 2301 2302 |
leaf = path->nodes[0]; slot = path->slots[0]; write_extent_buffer(leaf, buf, |
31840ae1a Btrfs: Full back ... |
2303 2304 |
btrfs_item_ptr_offset(leaf, slot), size); |
ae01a0abf Btrfs: Update clo... |
2305 |
|
c5c9cd4d1 Btrfs: allow clon... |
2306 |
extent = btrfs_item_ptr(leaf, slot, |
f46b5a66b Btrfs: split out ... |
2307 |
struct btrfs_file_extent_item); |
c5c9cd4d1 Btrfs: allow clon... |
2308 |
|
c5c9cd4d1 Btrfs: allow clon... |
2309 2310 2311 |
/* disko == 0 means it's a hole */ if (!disko) datao = 0; |
c5c9cd4d1 Btrfs: allow clon... |
2312 2313 2314 2315 2316 2317 2318 |
btrfs_set_file_extent_offset(leaf, extent, datao); btrfs_set_file_extent_num_bytes(leaf, extent, datal); if (disko) { inode_add_bytes(inode, datal); |
ae01a0abf Btrfs: Update clo... |
2319 |
ret = btrfs_inc_extent_ref(trans, root, |
5d4f98a28 Btrfs: Mixed back... |
2320 2321 |
disko, diskl, 0, root->root_key.objectid, |
33345d015 Btrfs: Always use... |
2322 |
btrfs_ino(inode), |
5d4f98a28 Btrfs: Mixed back... |
2323 |
new_key.offset - datao); |
31840ae1a Btrfs: Full back ... |
2324 |
BUG_ON(ret); |
f46b5a66b Btrfs: split out ... |
2325 |
} |
c5c9cd4d1 Btrfs: allow clon... |
2326 2327 2328 2329 2330 2331 2332 |
} else if (type == BTRFS_FILE_EXTENT_INLINE) { u64 skip = 0; u64 trim = 0; if (off > key.offset) { skip = off - key.offset; new_key.offset += skip; } |
d397712bc Btrfs: Fix checkp... |
2333 |
|
c5c9cd4d1 Btrfs: allow clon... |
2334 2335 |
if (key.offset + datal > off+len) trim = key.offset + datal - (off+len); |
d397712bc Btrfs: Fix checkp... |
2336 |
|
c5c9cd4d1 Btrfs: allow clon... |
2337 |
if (comp && (skip || trim)) { |
c5c9cd4d1 Btrfs: allow clon... |
2338 |
ret = -EINVAL; |
a22285a6a Btrfs: Integrate ... |
2339 |
btrfs_end_transaction(trans, root); |
c5c9cd4d1 Btrfs: allow clon... |
2340 2341 2342 2343 |
goto out; } size -= skip + trim; datal -= skip + trim; |
a22285a6a Btrfs: Integrate ... |
2344 2345 2346 2347 2348 2349 |
ret = btrfs_drop_extents(trans, inode, new_key.offset, new_key.offset + datal, &hint_byte, 1); BUG_ON(ret); |
c5c9cd4d1 Btrfs: allow clon... |
2350 2351 |
ret = btrfs_insert_empty_item(trans, root, path, &new_key, size); |
a22285a6a Btrfs: Integrate ... |
2352 |
BUG_ON(ret); |
c5c9cd4d1 Btrfs: allow clon... |
2353 2354 |
if (skip) { |
d397712bc Btrfs: Fix checkp... |
2355 2356 |
u32 start = btrfs_file_extent_calc_inline_size(0); |
c5c9cd4d1 Btrfs: allow clon... |
2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 |
memmove(buf+start, buf+start+skip, datal); } leaf = path->nodes[0]; slot = path->slots[0]; write_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf, slot), size); inode_add_bytes(inode, datal); |
f46b5a66b Btrfs: split out ... |
2367 |
} |
c5c9cd4d1 Btrfs: allow clon... |
2368 2369 |
btrfs_mark_buffer_dirty(leaf); |
b3b4aa74b btrfs: drop unuse... |
2370 |
btrfs_release_path(path); |
c5c9cd4d1 Btrfs: allow clon... |
2371 |
|
a22285a6a Btrfs: Integrate ... |
2372 |
inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
b5384d48f Btrfs: fix CLONE ... |
2373 2374 2375 2376 2377 2378 2379 |
/* * we round up to the block size at eof when * determining which extents to clone above, * but shouldn't round up the file size */ endoff = new_key.offset + datal; |
5f3888ff6 btrfs: Set file s... |
2380 2381 |
if (endoff > destoff+olen) endoff = destoff+olen; |
b5384d48f Btrfs: fix CLONE ... |
2382 2383 |
if (endoff > inode->i_size) btrfs_i_size_write(inode, endoff); |
a22285a6a Btrfs: Integrate ... |
2384 2385 2386 2387 |
ret = btrfs_update_inode(trans, root, inode); BUG_ON(ret); btrfs_end_transaction(trans, root); } |
d397712bc Btrfs: Fix checkp... |
2388 |
next: |
b3b4aa74b btrfs: drop unuse... |
2389 |
btrfs_release_path(path); |
f46b5a66b Btrfs: split out ... |
2390 |
key.offset++; |
f46b5a66b Btrfs: split out ... |
2391 |
} |
f46b5a66b Btrfs: split out ... |
2392 2393 |
ret = 0; out: |
b3b4aa74b btrfs: drop unuse... |
2394 |
btrfs_release_path(path); |
c5c9cd4d1 Btrfs: allow clon... |
2395 |
unlock_extent(&BTRFS_I(src)->io_tree, off, off+len, GFP_NOFS); |
f46b5a66b Btrfs: split out ... |
2396 2397 2398 |
out_unlock: mutex_unlock(&src->i_mutex); mutex_unlock(&inode->i_mutex); |
ae01a0abf Btrfs: Update clo... |
2399 2400 |
vfree(buf); btrfs_free_path(path); |
f46b5a66b Btrfs: split out ... |
2401 2402 |
out_fput: fput(src_file); |
ab67b7c1f Btrfs: Add missin... |
2403 |
out_drop_write: |
2a79f17e4 vfs: mnt_drop_wri... |
2404 |
mnt_drop_write_file(file); |
f46b5a66b Btrfs: split out ... |
2405 2406 |
return ret; } |
7a865e8ac Btrfs: btrfs: pas... |
2407 |
static long btrfs_ioctl_clone_range(struct file *file, void __user *argp) |
c5c9cd4d1 Btrfs: allow clon... |
2408 2409 |
{ struct btrfs_ioctl_clone_range_args args; |
7a865e8ac Btrfs: btrfs: pas... |
2410 |
if (copy_from_user(&args, argp, sizeof(args))) |
c5c9cd4d1 Btrfs: allow clon... |
2411 2412 2413 2414 |
return -EFAULT; return btrfs_ioctl_clone(file, args.src_fd, args.src_offset, args.src_length, args.dest_offset); } |
f46b5a66b Btrfs: split out ... |
2415 2416 2417 2418 2419 2420 |
/* * there are many ways the trans_start and trans_end ioctls can lead * to deadlocks. They should only be used by applications that * basically own the machine, and have a very in depth understanding * of all the possible deadlocks and enospc problems. */ |
b2950863c Btrfs: make thing... |
2421 |
static long btrfs_ioctl_trans_start(struct file *file) |
f46b5a66b Btrfs: split out ... |
2422 2423 2424 2425 |
{ struct inode *inode = fdentry(file)->d_inode; struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_trans_handle *trans; |
1ab86aedb Btrfs: fix error ... |
2426 |
int ret; |
f46b5a66b Btrfs: split out ... |
2427 |
|
1ab86aedb Btrfs: fix error ... |
2428 |
ret = -EPERM; |
df5b5520b BTRFS_IOC_TRANS_S... |
2429 |
if (!capable(CAP_SYS_ADMIN)) |
1ab86aedb Btrfs: fix error ... |
2430 |
goto out; |
df5b5520b BTRFS_IOC_TRANS_S... |
2431 |
|
1ab86aedb Btrfs: fix error ... |
2432 2433 |
ret = -EINPROGRESS; if (file->private_data) |
f46b5a66b Btrfs: split out ... |
2434 |
goto out; |
9ca9ee09c Btrfs: fix ioctl-... |
2435 |
|
b83cc9693 Btrfs: Add readon... |
2436 2437 2438 |
ret = -EROFS; if (btrfs_root_readonly(root)) goto out; |
a561be710 switch a bunch of... |
2439 |
ret = mnt_want_write_file(file); |
c146afad2 Btrfs: mount ro a... |
2440 2441 |
if (ret) goto out; |
a4abeea41 Btrfs: kill trans... |
2442 |
atomic_inc(&root->fs_info->open_ioctl_trans); |
9ca9ee09c Btrfs: fix ioctl-... |
2443 |
|
1ab86aedb Btrfs: fix error ... |
2444 |
ret = -ENOMEM; |
7a7eaa40a Btrfs: take away ... |
2445 |
trans = btrfs_start_ioctl_transaction(root); |
abd30bb0a btrfs: check retu... |
2446 |
if (IS_ERR(trans)) |
1ab86aedb Btrfs: fix error ... |
2447 2448 2449 2450 2451 2452 |
goto out_drop; file->private_data = trans; return 0; out_drop: |
a4abeea41 Btrfs: kill trans... |
2453 |
atomic_dec(&root->fs_info->open_ioctl_trans); |
2a79f17e4 vfs: mnt_drop_wri... |
2454 |
mnt_drop_write_file(file); |
f46b5a66b Btrfs: split out ... |
2455 |
out: |
f46b5a66b Btrfs: split out ... |
2456 2457 |
return ret; } |
6ef5ed0d3 Btrfs: add ioctl ... |
2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 |
static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) { struct inode *inode = fdentry(file)->d_inode; struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *new_root; struct btrfs_dir_item *di; struct btrfs_trans_handle *trans; struct btrfs_path *path; struct btrfs_key location; struct btrfs_disk_key disk_key; struct btrfs_super_block *disk_super; u64 features; u64 objectid = 0; u64 dir_id; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user(&objectid, argp, sizeof(objectid))) return -EFAULT; if (!objectid) objectid = root->root_key.objectid; location.objectid = objectid; location.type = BTRFS_ROOT_ITEM_KEY; location.offset = (u64)-1; new_root = btrfs_read_fs_root_no_name(root->fs_info, &location); if (IS_ERR(new_root)) return PTR_ERR(new_root); if (btrfs_root_refs(&new_root->root_item) == 0) return -ENOENT; path = btrfs_alloc_path(); if (!path) return -ENOMEM; path->leave_spinning = 1; trans = btrfs_start_transaction(root, 1); |
98d5dc13e btrfs: fix return... |
2499 |
if (IS_ERR(trans)) { |
6ef5ed0d3 Btrfs: add ioctl ... |
2500 |
btrfs_free_path(path); |
98d5dc13e btrfs: fix return... |
2501 |
return PTR_ERR(trans); |
6ef5ed0d3 Btrfs: add ioctl ... |
2502 |
} |
6c41761fc btrfs: separate s... |
2503 |
dir_id = btrfs_super_root_dir(root->fs_info->super_copy); |
6ef5ed0d3 Btrfs: add ioctl ... |
2504 2505 |
di = btrfs_lookup_dir_item(trans, root->fs_info->tree_root, path, dir_id, "default", 7, 1); |
cf1e99a4e Btrfs: btrfs_look... |
2506 |
if (IS_ERR_OR_NULL(di)) { |
6ef5ed0d3 Btrfs: add ioctl ... |
2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 |
btrfs_free_path(path); btrfs_end_transaction(trans, root); printk(KERN_ERR "Umm, you don't have the default dir item, " "this isn't going to work "); return -ENOENT; } btrfs_cpu_key_to_disk(&disk_key, &new_root->root_key); btrfs_set_dir_item_key(path->nodes[0], di, &disk_key); btrfs_mark_buffer_dirty(path->nodes[0]); btrfs_free_path(path); |
6c41761fc btrfs: separate s... |
2519 |
disk_super = root->fs_info->super_copy; |
6ef5ed0d3 Btrfs: add ioctl ... |
2520 2521 2522 2523 2524 2525 2526 2527 2528 |
features = btrfs_super_incompat_flags(disk_super); if (!(features & BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL)) { features |= BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL; btrfs_set_super_incompat_flags(disk_super, features); } btrfs_end_transaction(trans, root); return 0; } |
bf5fc093c Btrfs: fix the df... |
2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 |
static void get_block_group_info(struct list_head *groups_list, struct btrfs_ioctl_space_info *space) { struct btrfs_block_group_cache *block_group; space->total_bytes = 0; space->used_bytes = 0; space->flags = 0; list_for_each_entry(block_group, groups_list, list) { space->flags = block_group->flags; space->total_bytes += block_group->key.offset; space->used_bytes += btrfs_block_group_used(&block_group->item); } } |
1406e4327 Btrfs: add a "df"... |
2544 2545 2546 2547 2548 |
long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg) { struct btrfs_ioctl_space_args space_args; struct btrfs_ioctl_space_info space; struct btrfs_ioctl_space_info *dest; |
7fde62bff Btrfs: buffer res... |
2549 |
struct btrfs_ioctl_space_info *dest_orig; |
13f2696f1 fix user annotati... |
2550 |
struct btrfs_ioctl_space_info __user *user_dest; |
1406e4327 Btrfs: add a "df"... |
2551 |
struct btrfs_space_info *info; |
bf5fc093c Btrfs: fix the df... |
2552 2553 2554 2555 2556 |
u64 types[] = {BTRFS_BLOCK_GROUP_DATA, BTRFS_BLOCK_GROUP_SYSTEM, BTRFS_BLOCK_GROUP_METADATA, BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA}; int num_types = 4; |
7fde62bff Btrfs: buffer res... |
2557 |
int alloc_size; |
1406e4327 Btrfs: add a "df"... |
2558 |
int ret = 0; |
51788b1bd btrfs: prevent he... |
2559 |
u64 slot_count = 0; |
bf5fc093c Btrfs: fix the df... |
2560 |
int i, c; |
1406e4327 Btrfs: add a "df"... |
2561 2562 2563 2564 2565 |
if (copy_from_user(&space_args, (struct btrfs_ioctl_space_args __user *)arg, sizeof(space_args))) return -EFAULT; |
bf5fc093c Btrfs: fix the df... |
2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 |
for (i = 0; i < num_types; i++) { struct btrfs_space_info *tmp; info = NULL; rcu_read_lock(); list_for_each_entry_rcu(tmp, &root->fs_info->space_info, list) { if (tmp->flags == types[i]) { info = tmp; break; } } rcu_read_unlock(); if (!info) continue; down_read(&info->groups_sem); for (c = 0; c < BTRFS_NR_RAID_TYPES; c++) { if (!list_empty(&info->block_groups[c])) slot_count++; } up_read(&info->groups_sem); } |
7fde62bff Btrfs: buffer res... |
2590 2591 2592 2593 2594 2595 |
/* space_slots == 0 means they are asking for a count */ if (space_args.space_slots == 0) { space_args.total_spaces = slot_count; goto out; } |
bf5fc093c Btrfs: fix the df... |
2596 |
|
51788b1bd btrfs: prevent he... |
2597 |
slot_count = min_t(u64, space_args.space_slots, slot_count); |
bf5fc093c Btrfs: fix the df... |
2598 |
|
7fde62bff Btrfs: buffer res... |
2599 |
alloc_size = sizeof(*dest) * slot_count; |
bf5fc093c Btrfs: fix the df... |
2600 |
|
7fde62bff Btrfs: buffer res... |
2601 2602 2603 2604 2605 |
/* we generally have at most 6 or so space infos, one for each raid * level. So, a whole page should be more than enough for everyone */ if (alloc_size > PAGE_CACHE_SIZE) return -ENOMEM; |
1406e4327 Btrfs: add a "df"... |
2606 |
space_args.total_spaces = 0; |
7fde62bff Btrfs: buffer res... |
2607 2608 2609 2610 |
dest = kmalloc(alloc_size, GFP_NOFS); if (!dest) return -ENOMEM; dest_orig = dest; |
1406e4327 Btrfs: add a "df"... |
2611 |
|
7fde62bff Btrfs: buffer res... |
2612 |
/* now we have a buffer to copy into */ |
bf5fc093c Btrfs: fix the df... |
2613 2614 |
for (i = 0; i < num_types; i++) { struct btrfs_space_info *tmp; |
51788b1bd btrfs: prevent he... |
2615 2616 |
if (!slot_count) break; |
bf5fc093c Btrfs: fix the df... |
2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 |
info = NULL; rcu_read_lock(); list_for_each_entry_rcu(tmp, &root->fs_info->space_info, list) { if (tmp->flags == types[i]) { info = tmp; break; } } rcu_read_unlock(); |
7fde62bff Btrfs: buffer res... |
2627 |
|
bf5fc093c Btrfs: fix the df... |
2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 |
if (!info) continue; down_read(&info->groups_sem); for (c = 0; c < BTRFS_NR_RAID_TYPES; c++) { if (!list_empty(&info->block_groups[c])) { get_block_group_info(&info->block_groups[c], &space); memcpy(dest, &space, sizeof(space)); dest++; space_args.total_spaces++; |
51788b1bd btrfs: prevent he... |
2638 |
slot_count--; |
bf5fc093c Btrfs: fix the df... |
2639 |
} |
51788b1bd btrfs: prevent he... |
2640 2641 |
if (!slot_count) break; |
bf5fc093c Btrfs: fix the df... |
2642 2643 |
} up_read(&info->groups_sem); |
1406e4327 Btrfs: add a "df"... |
2644 |
} |
1406e4327 Btrfs: add a "df"... |
2645 |
|
7fde62bff Btrfs: buffer res... |
2646 2647 2648 2649 2650 2651 2652 2653 2654 |
user_dest = (struct btrfs_ioctl_space_info *) (arg + sizeof(struct btrfs_ioctl_space_args)); if (copy_to_user(user_dest, dest_orig, alloc_size)) ret = -EFAULT; kfree(dest_orig); out: if (ret == 0 && copy_to_user(arg, &space_args, sizeof(space_args))) |
1406e4327 Btrfs: add a "df"... |
2655 2656 2657 2658 |
ret = -EFAULT; return ret; } |
f46b5a66b Btrfs: split out ... |
2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 |
/* * there are many ways the trans_start and trans_end ioctls can lead * to deadlocks. They should only be used by applications that * basically own the machine, and have a very in depth understanding * of all the possible deadlocks and enospc problems. */ long btrfs_ioctl_trans_end(struct file *file) { struct inode *inode = fdentry(file)->d_inode; struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_trans_handle *trans; |
f46b5a66b Btrfs: split out ... |
2670 |
|
f46b5a66b Btrfs: split out ... |
2671 |
trans = file->private_data; |
1ab86aedb Btrfs: fix error ... |
2672 2673 |
if (!trans) return -EINVAL; |
b214107ed Btrfs: trivial sp... |
2674 |
file->private_data = NULL; |
9ca9ee09c Btrfs: fix ioctl-... |
2675 |
|
1ab86aedb Btrfs: fix error ... |
2676 |
btrfs_end_transaction(trans, root); |
a4abeea41 Btrfs: kill trans... |
2677 |
atomic_dec(&root->fs_info->open_ioctl_trans); |
9ca9ee09c Btrfs: fix ioctl-... |
2678 |
|
2a79f17e4 vfs: mnt_drop_wri... |
2679 |
mnt_drop_write_file(file); |
1ab86aedb Btrfs: fix error ... |
2680 |
return 0; |
f46b5a66b Btrfs: split out ... |
2681 |
} |
462045928 Btrfs: add START_... |
2682 2683 2684 2685 2686 |
static noinline long btrfs_ioctl_start_sync(struct file *file, void __user *argp) { struct btrfs_root *root = BTRFS_I(file->f_dentry->d_inode)->root; struct btrfs_trans_handle *trans; u64 transid; |
db5b493ac Btrfs: cleanup so... |
2687 |
int ret; |
462045928 Btrfs: add START_... |
2688 2689 |
trans = btrfs_start_transaction(root, 0); |
98d5dc13e btrfs: fix return... |
2690 2691 |
if (IS_ERR(trans)) return PTR_ERR(trans); |
462045928 Btrfs: add START_... |
2692 |
transid = trans->transid; |
db5b493ac Btrfs: cleanup so... |
2693 |
ret = btrfs_commit_transaction_async(trans, root, 0); |
8b2b2d3cb Btrfs: fix memory... |
2694 2695 |
if (ret) { btrfs_end_transaction(trans, root); |
db5b493ac Btrfs: cleanup so... |
2696 |
return ret; |
8b2b2d3cb Btrfs: fix memory... |
2697 |
} |
462045928 Btrfs: add START_... |
2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 |
if (argp) if (copy_to_user(argp, &transid, sizeof(transid))) return -EFAULT; return 0; } static noinline long btrfs_ioctl_wait_sync(struct file *file, void __user *argp) { struct btrfs_root *root = BTRFS_I(file->f_dentry->d_inode)->root; u64 transid; if (argp) { if (copy_from_user(&transid, argp, sizeof(transid))) return -EFAULT; } else { transid = 0; /* current trans */ } return btrfs_wait_for_commit(root, transid); } |
475f63874 btrfs: new ioctls... |
2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 |
static long btrfs_ioctl_scrub(struct btrfs_root *root, void __user *arg) { int ret; struct btrfs_ioctl_scrub_args *sa; if (!capable(CAP_SYS_ADMIN)) return -EPERM; sa = memdup_user(arg, sizeof(*sa)); if (IS_ERR(sa)) return PTR_ERR(sa); ret = btrfs_scrub_dev(root, sa->devid, sa->start, sa->end, |
8628764e1 btrfs: add readon... |
2731 |
&sa->progress, sa->flags & BTRFS_SCRUB_READONLY); |
475f63874 btrfs: new ioctls... |
2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 |
if (copy_to_user(arg, sa, sizeof(*sa))) ret = -EFAULT; kfree(sa); return ret; } static long btrfs_ioctl_scrub_cancel(struct btrfs_root *root, void __user *arg) { if (!capable(CAP_SYS_ADMIN)) return -EPERM; return btrfs_scrub_cancel(root); } static long btrfs_ioctl_scrub_progress(struct btrfs_root *root, void __user *arg) { struct btrfs_ioctl_scrub_args *sa; int ret; if (!capable(CAP_SYS_ADMIN)) return -EPERM; sa = memdup_user(arg, sizeof(*sa)); if (IS_ERR(sa)) return PTR_ERR(sa); ret = btrfs_scrub_progress(root, sa->devid, &sa->progress); if (copy_to_user(arg, sa, sizeof(*sa))) ret = -EFAULT; kfree(sa); return ret; } |
d7728c960 btrfs: new ioctls... |
2769 2770 2771 2772 |
static long btrfs_ioctl_ino_to_path(struct btrfs_root *root, void __user *arg) { int ret = 0; int i; |
740c3d226 Btrfs: fix the ne... |
2773 |
u64 rel_ptr; |
d7728c960 btrfs: new ioctls... |
2774 |
int size; |
806468f8b Merge git://git.j... |
2775 |
struct btrfs_ioctl_ino_path_args *ipa = NULL; |
d7728c960 btrfs: new ioctls... |
2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 |
struct inode_fs_paths *ipath = NULL; struct btrfs_path *path; if (!capable(CAP_SYS_ADMIN)) return -EPERM; path = btrfs_alloc_path(); if (!path) { ret = -ENOMEM; goto out; } ipa = memdup_user(arg, sizeof(*ipa)); if (IS_ERR(ipa)) { ret = PTR_ERR(ipa); ipa = NULL; goto out; } size = min_t(u32, ipa->size, 4096); ipath = init_ipath(size, root, path); if (IS_ERR(ipath)) { ret = PTR_ERR(ipath); ipath = NULL; goto out; } ret = paths_from_inode(ipa->inum, ipath); if (ret < 0) goto out; for (i = 0; i < ipath->fspath->elem_cnt; ++i) { |
745c4d8e1 btrfs: Fix up 32/... |
2808 2809 |
rel_ptr = ipath->fspath->val[i] - (u64)(unsigned long)ipath->fspath->val; |
740c3d226 Btrfs: fix the ne... |
2810 |
ipath->fspath->val[i] = rel_ptr; |
d7728c960 btrfs: new ioctls... |
2811 |
} |
745c4d8e1 btrfs: Fix up 32/... |
2812 2813 |
ret = copy_to_user((void *)(unsigned long)ipa->fspath, (void *)(unsigned long)ipath->fspath, size); |
d7728c960 btrfs: new ioctls... |
2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 |
if (ret) { ret = -EFAULT; goto out; } out: btrfs_free_path(path); free_ipath(ipath); kfree(ipa); return ret; } static int build_ino_list(u64 inum, u64 offset, u64 root, void *ctx) { struct btrfs_data_container *inodes = ctx; const size_t c = 3 * sizeof(u64); if (inodes->bytes_left >= c) { inodes->bytes_left -= c; inodes->val[inodes->elem_cnt] = inum; inodes->val[inodes->elem_cnt + 1] = offset; inodes->val[inodes->elem_cnt + 2] = root; inodes->elem_cnt += 3; } else { inodes->bytes_missing += c - inodes->bytes_left; inodes->bytes_left = 0; inodes->elem_missed += 3; } return 0; } static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root, void __user *arg) { int ret = 0; int size; u64 extent_offset; struct btrfs_ioctl_logical_ino_args *loi; struct btrfs_data_container *inodes = NULL; struct btrfs_path *path = NULL; struct btrfs_key key; if (!capable(CAP_SYS_ADMIN)) return -EPERM; loi = memdup_user(arg, sizeof(*loi)); if (IS_ERR(loi)) { ret = PTR_ERR(loi); loi = NULL; goto out; } path = btrfs_alloc_path(); if (!path) { ret = -ENOMEM; goto out; } size = min_t(u32, loi->size, 4096); inodes = init_data_container(size); if (IS_ERR(inodes)) { ret = PTR_ERR(inodes); inodes = NULL; goto out; } ret = extent_from_logical(root->fs_info, loi->logical, path, &key); if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK) ret = -ENOENT; if (ret < 0) goto out; extent_offset = loi->logical - key.objectid; ret = iterate_extent_inodes(root->fs_info, path, key.objectid, extent_offset, build_ino_list, inodes); if (ret < 0) goto out; |
745c4d8e1 btrfs: Fix up 32/... |
2895 2896 |
ret = copy_to_user((void *)(unsigned long)loi->inodes, (void *)(unsigned long)inodes, size); |
d7728c960 btrfs: new ioctls... |
2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 |
if (ret) ret = -EFAULT; out: btrfs_free_path(path); kfree(inodes); kfree(loi); return ret; } |
f46b5a66b Btrfs: split out ... |
2907 2908 2909 2910 |
long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root; |
4bcabaa30 Btrfs: clean up b... |
2911 |
void __user *argp = (void __user *)arg; |
f46b5a66b Btrfs: split out ... |
2912 2913 |
switch (cmd) { |
6cbff00f4 Btrfs: implement ... |
2914 2915 2916 2917 2918 2919 |
case FS_IOC_GETFLAGS: return btrfs_ioctl_getflags(file, argp); case FS_IOC_SETFLAGS: return btrfs_ioctl_setflags(file, argp); case FS_IOC_GETVERSION: return btrfs_ioctl_getversion(file, argp); |
f7039b1d5 Btrfs: add btrfs_... |
2920 2921 |
case FITRIM: return btrfs_ioctl_fitrim(file, argp); |
f46b5a66b Btrfs: split out ... |
2922 |
case BTRFS_IOC_SNAP_CREATE: |
fa0d2b9bd Btrfs: Refactor b... |
2923 |
return btrfs_ioctl_snap_create(file, argp, 0); |
fdfb1e4f6 Btrfs: Make async... |
2924 |
case BTRFS_IOC_SNAP_CREATE_V2: |
fa0d2b9bd Btrfs: Refactor b... |
2925 |
return btrfs_ioctl_snap_create_v2(file, argp, 0); |
3de4586c5 Btrfs: Allow subv... |
2926 |
case BTRFS_IOC_SUBVOL_CREATE: |
fa0d2b9bd Btrfs: Refactor b... |
2927 |
return btrfs_ioctl_snap_create(file, argp, 1); |
76dda93c6 Btrfs: add snapsh... |
2928 2929 |
case BTRFS_IOC_SNAP_DESTROY: return btrfs_ioctl_snap_destroy(file, argp); |
0caa102da Btrfs: Add BTRFS_... |
2930 2931 2932 2933 |
case BTRFS_IOC_SUBVOL_GETFLAGS: return btrfs_ioctl_subvol_getflags(file, argp); case BTRFS_IOC_SUBVOL_SETFLAGS: return btrfs_ioctl_subvol_setflags(file, argp); |
6ef5ed0d3 Btrfs: add ioctl ... |
2934 2935 |
case BTRFS_IOC_DEFAULT_SUBVOL: return btrfs_ioctl_default_subvol(file, argp); |
f46b5a66b Btrfs: split out ... |
2936 |
case BTRFS_IOC_DEFRAG: |
1e701a329 Btrfs: add new de... |
2937 2938 2939 |
return btrfs_ioctl_defrag(file, NULL); case BTRFS_IOC_DEFRAG_RANGE: return btrfs_ioctl_defrag(file, argp); |
f46b5a66b Btrfs: split out ... |
2940 |
case BTRFS_IOC_RESIZE: |
4bcabaa30 Btrfs: clean up b... |
2941 |
return btrfs_ioctl_resize(root, argp); |
f46b5a66b Btrfs: split out ... |
2942 |
case BTRFS_IOC_ADD_DEV: |
4bcabaa30 Btrfs: clean up b... |
2943 |
return btrfs_ioctl_add_dev(root, argp); |
f46b5a66b Btrfs: split out ... |
2944 |
case BTRFS_IOC_RM_DEV: |
4bcabaa30 Btrfs: clean up b... |
2945 |
return btrfs_ioctl_rm_dev(root, argp); |
475f63874 btrfs: new ioctls... |
2946 2947 2948 2949 |
case BTRFS_IOC_FS_INFO: return btrfs_ioctl_fs_info(root, argp); case BTRFS_IOC_DEV_INFO: return btrfs_ioctl_dev_info(root, argp); |
f46b5a66b Btrfs: split out ... |
2950 2951 2952 |
case BTRFS_IOC_BALANCE: return btrfs_balance(root->fs_info->dev_root); case BTRFS_IOC_CLONE: |
c5c9cd4d1 Btrfs: allow clon... |
2953 2954 |
return btrfs_ioctl_clone(file, arg, 0, 0, 0); case BTRFS_IOC_CLONE_RANGE: |
7a865e8ac Btrfs: btrfs: pas... |
2955 |
return btrfs_ioctl_clone_range(file, argp); |
f46b5a66b Btrfs: split out ... |
2956 2957 2958 2959 |
case BTRFS_IOC_TRANS_START: return btrfs_ioctl_trans_start(file); case BTRFS_IOC_TRANS_END: return btrfs_ioctl_trans_end(file); |
ac8e9819d Btrfs: add search... |
2960 2961 2962 2963 |
case BTRFS_IOC_TREE_SEARCH: return btrfs_ioctl_tree_search(file, argp); case BTRFS_IOC_INO_LOOKUP: return btrfs_ioctl_ino_lookup(file, argp); |
d7728c960 btrfs: new ioctls... |
2964 2965 2966 2967 |
case BTRFS_IOC_INO_PATHS: return btrfs_ioctl_ino_to_path(root, argp); case BTRFS_IOC_LOGICAL_INO: return btrfs_ioctl_logical_to_ino(root, argp); |
1406e4327 Btrfs: add a "df"... |
2968 2969 |
case BTRFS_IOC_SPACE_INFO: return btrfs_ioctl_space_info(root, argp); |
f46b5a66b Btrfs: split out ... |
2970 2971 2972 |
case BTRFS_IOC_SYNC: btrfs_sync_fs(file->f_dentry->d_sb, 1); return 0; |
462045928 Btrfs: add START_... |
2973 2974 2975 2976 |
case BTRFS_IOC_START_SYNC: return btrfs_ioctl_start_sync(file, argp); case BTRFS_IOC_WAIT_SYNC: return btrfs_ioctl_wait_sync(file, argp); |
475f63874 btrfs: new ioctls... |
2977 2978 2979 2980 2981 2982 |
case BTRFS_IOC_SCRUB: return btrfs_ioctl_scrub(root, argp); case BTRFS_IOC_SCRUB_CANCEL: return btrfs_ioctl_scrub_cancel(root, argp); case BTRFS_IOC_SCRUB_PROGRESS: return btrfs_ioctl_scrub_progress(root, argp); |
f46b5a66b Btrfs: split out ... |
2983 2984 2985 2986 |
} return -ENOTTY; } |