Blame view
fs/btrfs/ioctl.c
138 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 |
#include <linux/swap.h> #include <linux/writeback.h> |
f46b5a66b Btrfs: split out ... |
36 37 |
#include <linux/compat.h> #include <linux/bit_spinlock.h> |
cb8e70901 Btrfs: Fix subvol... |
38 |
#include <linux/security.h> |
f46b5a66b Btrfs: split out ... |
39 |
#include <linux/xattr.h> |
f54de068d btrfs: use GFP_KE... |
40 |
#include <linux/mm.h> |
5a0e3ad6a include cleanup: ... |
41 |
#include <linux/slab.h> |
f7039b1d5 Btrfs: add btrfs_... |
42 |
#include <linux/blkdev.h> |
8ea05e3a4 Btrfs: introduce ... |
43 |
#include <linux/uuid.h> |
55e301fd5 Btrfs: move fs/bt... |
44 |
#include <linux/btrfs.h> |
416161db9 btrfs: offline de... |
45 |
#include <linux/uaccess.h> |
f46b5a66b Btrfs: split out ... |
46 47 48 49 |
#include "ctree.h" #include "disk-io.h" #include "transaction.h" #include "btrfs_inode.h" |
f46b5a66b Btrfs: split out ... |
50 51 |
#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" |
606686eea Btrfs: use rcu to... |
55 |
#include "rcu-string.h" |
31db9f7c2 Btrfs: introduce ... |
56 |
#include "send.h" |
3f6bcfbd4 Btrfs: add suppor... |
57 |
#include "dev-replace.h" |
63541927c Btrfs: add suppor... |
58 |
#include "props.h" |
3b02a68a6 btrfs: use featur... |
59 |
#include "sysfs.h" |
fcebe4562 Btrfs: rework qgr... |
60 |
#include "qgroup.h" |
1ec9a1ae1 Btrfs: fix unrepl... |
61 |
#include "tree-log.h" |
ebb8765b2 btrfs: move btrfs... |
62 |
#include "compression.h" |
f46b5a66b Btrfs: split out ... |
63 |
|
abccd00f8 btrfs: Fix 32/64-... |
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
#ifdef CONFIG_64BIT /* If we have a 32-bit userspace and 64-bit kernel, then the UAPI * structures are incorrect, as the timespec structure from userspace * is 4 bytes too small. We define these alternatives here to teach * the kernel about the 32-bit struct packing. */ struct btrfs_ioctl_timespec_32 { __u64 sec; __u32 nsec; } __attribute__ ((__packed__)); struct btrfs_ioctl_received_subvol_args_32 { char uuid[BTRFS_UUID_SIZE]; /* in */ __u64 stransid; /* in */ __u64 rtransid; /* out */ struct btrfs_ioctl_timespec_32 stime; /* in */ struct btrfs_ioctl_timespec_32 rtime; /* out */ __u64 flags; /* in */ __u64 reserved[16]; /* in */ } __attribute__ ((__packed__)); #define BTRFS_IOC_SET_RECEIVED_SUBVOL_32 _IOWR(BTRFS_IOCTL_MAGIC, 37, \ struct btrfs_ioctl_received_subvol_args_32) #endif |
416161db9 btrfs: offline de... |
88 |
static int btrfs_clone(struct inode *src, struct inode *inode, |
1c919a5e1 btrfs: don't upda... |
89 90 |
u64 off, u64 olen, u64 olen_aligned, u64 destoff, int no_time_update); |
416161db9 btrfs: offline de... |
91 |
|
6cbff00f4 Btrfs: implement ... |
92 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 121 |
/* 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... |
122 123 |
if (flags & BTRFS_INODE_NODATACOW) iflags |= FS_NOCOW_FL; |
13f48dc90 btrfs: Simplify c... |
124 |
if (flags & BTRFS_INODE_NOCOMPRESS) |
d0092bdda Btrfs: fix FS_IOC... |
125 |
iflags |= FS_NOCOMP_FL; |
13f48dc90 btrfs: Simplify c... |
126 127 |
else if (flags & BTRFS_INODE_COMPRESS) iflags |= FS_COMPR_FL; |
6cbff00f4 Btrfs: implement ... |
128 129 130 131 132 133 134 135 136 137 |
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); |
3cc793925 Btrfs: atomically... |
138 |
unsigned int new_fl = 0; |
6cbff00f4 Btrfs: implement ... |
139 140 |
if (ip->flags & BTRFS_INODE_SYNC) |
3cc793925 Btrfs: atomically... |
141 |
new_fl |= S_SYNC; |
6cbff00f4 Btrfs: implement ... |
142 |
if (ip->flags & BTRFS_INODE_IMMUTABLE) |
3cc793925 Btrfs: atomically... |
143 |
new_fl |= S_IMMUTABLE; |
6cbff00f4 Btrfs: implement ... |
144 |
if (ip->flags & BTRFS_INODE_APPEND) |
3cc793925 Btrfs: atomically... |
145 |
new_fl |= S_APPEND; |
6cbff00f4 Btrfs: implement ... |
146 |
if (ip->flags & BTRFS_INODE_NOATIME) |
3cc793925 Btrfs: atomically... |
147 |
new_fl |= S_NOATIME; |
6cbff00f4 Btrfs: implement ... |
148 |
if (ip->flags & BTRFS_INODE_DIRSYNC) |
3cc793925 Btrfs: atomically... |
149 150 151 152 153 |
new_fl |= S_DIRSYNC; set_mask_bits(&inode->i_flags, S_SYNC | S_APPEND | S_IMMUTABLE | S_NOATIME | S_DIRSYNC, new_fl); |
6cbff00f4 Btrfs: implement ... |
154 |
} |
6cbff00f4 Btrfs: implement ... |
155 156 |
static int btrfs_ioctl_getflags(struct file *file, void __user *arg) { |
496ad9aa8 new helper: file_... |
157 |
struct btrfs_inode *ip = BTRFS_I(file_inode(file)); |
6cbff00f4 Btrfs: implement ... |
158 159 160 161 162 163 |
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... |
164 165 166 167 168 |
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 |
169 170 |
FS_NOCOMP_FL | FS_COMPR_FL | FS_NOCOW_FL)) |
75e7cb7fe Btrfs: Per file/d... |
171 172 173 174 |
return -EOPNOTSUPP; if ((flags & FS_NOCOMP_FL) && (flags & FS_COMPR_FL)) return -EINVAL; |
75e7cb7fe Btrfs: Per file/d... |
175 176 |
return 0; } |
6cbff00f4 Btrfs: implement ... |
177 178 |
static int btrfs_ioctl_setflags(struct file *file, void __user *arg) { |
496ad9aa8 new helper: file_... |
179 |
struct inode *inode = file_inode(file); |
0b246afa6 btrfs: root->fs_i... |
180 |
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); |
6cbff00f4 Btrfs: implement ... |
181 182 183 184 185 |
struct btrfs_inode *ip = BTRFS_I(inode); struct btrfs_root *root = ip->root; struct btrfs_trans_handle *trans; unsigned int flags, oldflags; int ret; |
f062abf08 Btrfs: remove BUG... |
186 187 |
u64 ip_oldflags; unsigned int i_oldflags; |
7e97b8daf btrfs: allow sett... |
188 |
umode_t mode; |
6cbff00f4 Btrfs: implement ... |
189 |
|
bd60ea0fe btrfs: call permi... |
190 191 |
if (!inode_owner_or_capable(inode)) return -EPERM; |
b83cc9693 Btrfs: Add readon... |
192 193 |
if (btrfs_root_readonly(root)) return -EROFS; |
6cbff00f4 Btrfs: implement ... |
194 195 |
if (copy_from_user(&flags, arg, sizeof(flags))) return -EFAULT; |
75e7cb7fe Btrfs: Per file/d... |
196 197 198 |
ret = check_flags(flags); if (ret) return ret; |
f46b5a66b Btrfs: split out ... |
199 |
|
e7848683a btrfs: Push mnt_w... |
200 201 202 |
ret = mnt_want_write_file(file); if (ret) return ret; |
5955102c9 wrappers for ->i_... |
203 |
inode_lock(inode); |
6cbff00f4 Btrfs: implement ... |
204 |
|
f062abf08 Btrfs: remove BUG... |
205 206 |
ip_oldflags = ip->flags; i_oldflags = inode->i_flags; |
7e97b8daf btrfs: allow sett... |
207 |
mode = inode->i_mode; |
f062abf08 Btrfs: remove BUG... |
208 |
|
6cbff00f4 Btrfs: implement ... |
209 210 211 212 213 214 215 216 |
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; } } |
6cbff00f4 Btrfs: implement ... |
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 |
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; |
7e97b8daf btrfs: allow sett... |
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
if (flags & FS_NOCOW_FL) { if (S_ISREG(mode)) { /* * It's safe to turn csums off here, no extents exist. * Otherwise we want the flag to reflect the real COW * status of the file and will not set it. */ if (inode->i_size == 0) ip->flags |= BTRFS_INODE_NODATACOW | BTRFS_INODE_NODATASUM; } else { ip->flags |= BTRFS_INODE_NODATACOW; } } else { /* |
013276101 btrfs: fix string... |
256 |
* Revert back under same assumptions as above |
7e97b8daf btrfs: allow sett... |
257 258 259 260 261 262 263 264 265 |
*/ if (S_ISREG(mode)) { if (inode->i_size == 0) ip->flags &= ~(BTRFS_INODE_NODATACOW | BTRFS_INODE_NODATASUM); } else { ip->flags &= ~BTRFS_INODE_NODATACOW; } } |
6cbff00f4 Btrfs: implement ... |
266 |
|
75e7cb7fe Btrfs: Per file/d... |
267 268 269 270 271 272 273 274 |
/* * 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; |
63541927c Btrfs: add suppor... |
275 276 277 278 |
ret = btrfs_set_prop(inode, "btrfs.compression", NULL, 0, 0); if (ret && ret != -ENODATA) goto out_drop; |
75e7cb7fe Btrfs: Per file/d... |
279 |
} else if (flags & FS_COMPR_FL) { |
63541927c Btrfs: add suppor... |
280 |
const char *comp; |
75e7cb7fe Btrfs: Per file/d... |
281 282 |
ip->flags |= BTRFS_INODE_COMPRESS; ip->flags &= ~BTRFS_INODE_NOCOMPRESS; |
63541927c Btrfs: add suppor... |
283 |
|
0b246afa6 btrfs: root->fs_i... |
284 |
if (fs_info->compress_type == BTRFS_COMPRESS_LZO) |
63541927c Btrfs: add suppor... |
285 |
comp = "lzo"; |
5c1aab1dd btrfs: Add zstd s... |
286 |
else if (fs_info->compress_type == BTRFS_COMPRESS_ZLIB) |
63541927c Btrfs: add suppor... |
287 |
comp = "zlib"; |
5c1aab1dd btrfs: Add zstd s... |
288 289 |
else comp = "zstd"; |
63541927c Btrfs: add suppor... |
290 291 292 293 |
ret = btrfs_set_prop(inode, "btrfs.compression", comp, strlen(comp), 0); if (ret) goto out_drop; |
ebcb904df Btrfs: fix FS_IOC... |
294 |
} else { |
78a017a2c Btrfs: add missin... |
295 296 297 |
ret = btrfs_set_prop(inode, "btrfs.compression", NULL, 0, 0); if (ret && ret != -ENODATA) goto out_drop; |
ebcb904df Btrfs: fix FS_IOC... |
298 |
ip->flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS); |
75e7cb7fe Btrfs: Per file/d... |
299 |
} |
6cbff00f4 Btrfs: implement ... |
300 |
|
4da6f1a33 Btrfs: reserve me... |
301 |
trans = btrfs_start_transaction(root, 1); |
f062abf08 Btrfs: remove BUG... |
302 303 304 305 |
if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto out_drop; } |
6cbff00f4 Btrfs: implement ... |
306 |
|
306424cc8 Btrfs: fix ctime ... |
307 |
btrfs_update_iflags(inode); |
0c4d2d95d Btrfs: use i_vers... |
308 |
inode_inc_iversion(inode); |
c2050a454 fs: Replace curre... |
309 |
inode->i_ctime = current_time(inode); |
6cbff00f4 Btrfs: implement ... |
310 |
ret = btrfs_update_inode(trans, root, inode); |
6cbff00f4 Btrfs: implement ... |
311 |
|
3a45bb207 btrfs: remove roo... |
312 |
btrfs_end_transaction(trans); |
f062abf08 Btrfs: remove BUG... |
313 314 315 316 317 |
out_drop: if (ret) { ip->flags = ip_oldflags; inode->i_flags = i_oldflags; } |
6cbff00f4 Btrfs: implement ... |
318 |
|
6cbff00f4 Btrfs: implement ... |
319 |
out_unlock: |
5955102c9 wrappers for ->i_... |
320 |
inode_unlock(inode); |
e7848683a btrfs: Push mnt_w... |
321 |
mnt_drop_write_file(file); |
2d4e6f6ad Btrfs: fix return... |
322 |
return ret; |
6cbff00f4 Btrfs: implement ... |
323 324 325 326 |
} static int btrfs_ioctl_getversion(struct file *file, int __user *arg) { |
496ad9aa8 new helper: file_... |
327 |
struct inode *inode = file_inode(file); |
6cbff00f4 Btrfs: implement ... |
328 329 330 |
return put_user(inode->i_generation, arg); } |
f46b5a66b Btrfs: split out ... |
331 |
|
f7039b1d5 Btrfs: add btrfs_... |
332 333 |
static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg) { |
0b246afa6 btrfs: root->fs_i... |
334 335 |
struct inode *inode = file_inode(file); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); |
f7039b1d5 Btrfs: add btrfs_... |
336 337 338 339 340 341 342 343 344 |
struct btrfs_device *device; struct request_queue *q; struct fstrim_range range; u64 minlen = ULLONG_MAX; u64 num_devices = 0; int ret; if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
1f78160ce Btrfs: using rcu ... |
345 346 347 |
rcu_read_lock(); list_for_each_entry_rcu(device, &fs_info->fs_devices->devices, dev_list) { |
f7039b1d5 Btrfs: add btrfs_... |
348 349 350 351 352 |
if (!device->bdev) continue; q = bdev_get_queue(device->bdev); if (blk_queue_discard(q)) { num_devices++; |
50d0446e6 Btrfs: code clean... |
353 |
minlen = min_t(u64, q->limits.discard_granularity, |
f7039b1d5 Btrfs: add btrfs_... |
354 355 356 |
minlen); } } |
1f78160ce Btrfs: using rcu ... |
357 |
rcu_read_unlock(); |
f4c697e64 btrfs: return EIN... |
358 |
|
f7039b1d5 Btrfs: add btrfs_... |
359 360 |
if (!num_devices) return -EOPNOTSUPP; |
f7039b1d5 Btrfs: add btrfs_... |
361 362 |
if (copy_from_user(&range, arg, sizeof(range))) return -EFAULT; |
2fdb337b6 btrfs: Ensure btr... |
363 364 365 366 367 368 369 |
/* * NOTE: Don't truncate the range using super->total_bytes. Bytenr of * block group is in the logical address space, which can be any * sectorsize aligned bytenr in the range [0, U64_MAX]. */ if (range.len < fs_info->sb->s_blocksize) |
f4c697e64 btrfs: return EIN... |
370 |
return -EINVAL; |
f7039b1d5 Btrfs: add btrfs_... |
371 372 |
range.minlen = max(range.minlen, minlen); |
2ff7e61e0 btrfs: take an fs... |
373 |
ret = btrfs_trim_fs(fs_info, &range); |
f7039b1d5 Btrfs: add btrfs_... |
374 375 376 377 378 379 380 381 |
if (ret < 0) return ret; if (copy_to_user(arg, &range, sizeof(range))) return -EFAULT; return 0; } |
dd5f9615f Btrfs: maintain s... |
382 383 |
int btrfs_is_empty_uuid(u8 *uuid) { |
46e0f66a0 btrfs: fix empty_... |
384 385 386 387 388 389 390 |
int i; for (i = 0; i < BTRFS_UUID_SIZE; i++) { if (uuid[i]) return 0; } return 1; |
dd5f9615f Btrfs: maintain s... |
391 |
} |
d5c120701 Btrfs: fix wrong ... |
392 |
static noinline int create_subvol(struct inode *dir, |
cb8e70901 Btrfs: Fix subvol... |
393 |
struct dentry *dentry, |
52f75f4fe btrfs: constify n... |
394 |
const char *name, int namelen, |
6f72c7e20 Btrfs: add qgroup... |
395 |
u64 *async_transid, |
8696c5330 Btrfs: fix memory... |
396 |
struct btrfs_qgroup_inherit *inherit) |
f46b5a66b Btrfs: split out ... |
397 |
{ |
0b246afa6 btrfs: root->fs_i... |
398 |
struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb); |
f46b5a66b Btrfs: split out ... |
399 400 |
struct btrfs_trans_handle *trans; struct btrfs_key key; |
49a3c4d9b btrfs: use dynami... |
401 |
struct btrfs_root_item *root_item; |
f46b5a66b Btrfs: split out ... |
402 403 |
struct btrfs_inode_item *inode_item; struct extent_buffer *leaf; |
d5c120701 Btrfs: fix wrong ... |
404 |
struct btrfs_root *root = BTRFS_I(dir)->root; |
76dda93c6 Btrfs: add snapsh... |
405 |
struct btrfs_root *new_root; |
d5c120701 Btrfs: fix wrong ... |
406 |
struct btrfs_block_rsv block_rsv; |
c2050a454 fs: Replace curre... |
407 |
struct timespec cur_time = current_time(dir); |
5662344b3 Btrfs: fix error ... |
408 |
struct inode *inode; |
f46b5a66b Btrfs: split out ... |
409 410 411 412 |
int ret; int err; u64 objectid; u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID; |
3de4586c5 Btrfs: Allow subv... |
413 |
u64 index = 0; |
d5c120701 Btrfs: fix wrong ... |
414 |
u64 qgroup_reserved; |
8ea05e3a4 Btrfs: introduce ... |
415 |
uuid_le new_uuid; |
f46b5a66b Btrfs: split out ... |
416 |
|
49a3c4d9b btrfs: use dynami... |
417 418 419 |
root_item = kzalloc(sizeof(*root_item), GFP_KERNEL); if (!root_item) return -ENOMEM; |
0b246afa6 btrfs: root->fs_i... |
420 |
ret = btrfs_find_free_objectid(fs_info->tree_root, &objectid); |
2fbe8c8ad get rid of useles... |
421 |
if (ret) |
49a3c4d9b btrfs: use dynami... |
422 |
goto fail_free; |
6a9122130 Btrfs: use dget_p... |
423 |
|
e09fe2d21 btrfs: Don't allo... |
424 425 |
/* * Don't create subvolume whose level is not zero. Or qgroup will be |
013276101 btrfs: fix string... |
426 |
* screwed up since it assumes subvolume qgroup's level to be 0. |
e09fe2d21 btrfs: Don't allo... |
427 |
*/ |
49a3c4d9b btrfs: use dynami... |
428 429 430 431 |
if (btrfs_qgroup_level(objectid)) { ret = -ENOSPC; goto fail_free; } |
e09fe2d21 btrfs: Don't allo... |
432 |
|
d5c120701 Btrfs: fix wrong ... |
433 |
btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP); |
9ed74f2db Btrfs: proper -EN... |
434 |
/* |
d5c120701 Btrfs: fix wrong ... |
435 436 |
* The same as the snapshot creation, please see the comment * of create_snapshot(). |
9ed74f2db Btrfs: proper -EN... |
437 |
*/ |
d5c120701 Btrfs: fix wrong ... |
438 |
ret = btrfs_subvolume_reserve_metadata(root, &block_rsv, |
dd5f9615f Btrfs: maintain s... |
439 |
8, &qgroup_reserved, false); |
d5c120701 Btrfs: fix wrong ... |
440 |
if (ret) |
49a3c4d9b btrfs: use dynami... |
441 |
goto fail_free; |
d5c120701 Btrfs: fix wrong ... |
442 443 444 445 |
trans = btrfs_start_transaction(root, 0); if (IS_ERR(trans)) { ret = PTR_ERR(trans); |
7775c8184 btrfs: remove unu... |
446 |
btrfs_subvolume_release_metadata(fs_info, &block_rsv); |
49a3c4d9b btrfs: use dynami... |
447 |
goto fail_free; |
d5c120701 Btrfs: fix wrong ... |
448 449 450 |
} trans->block_rsv = &block_rsv; trans->bytes_reserved = block_rsv.size; |
f46b5a66b Btrfs: split out ... |
451 |
|
0b246afa6 btrfs: root->fs_i... |
452 |
ret = btrfs_qgroup_inherit(trans, fs_info, 0, objectid, inherit); |
6f72c7e20 Btrfs: add qgroup... |
453 454 |
if (ret) goto fail; |
4d75f8a9c btrfs: remove blo... |
455 |
leaf = btrfs_alloc_tree_block(trans, root, 0, objectid, NULL, 0, 0, 0); |
8e8a1e31f Btrfs: Fix a few ... |
456 457 458 459 |
if (IS_ERR(leaf)) { ret = PTR_ERR(leaf); goto fail; } |
f46b5a66b Btrfs: split out ... |
460 |
|
b159fa280 btrfs: remove con... |
461 |
memzero_extent_buffer(leaf, 0, sizeof(struct btrfs_header)); |
f46b5a66b Btrfs: split out ... |
462 463 |
btrfs_set_header_bytenr(leaf, leaf->start); btrfs_set_header_generation(leaf, trans->transid); |
5d4f98a28 Btrfs: Mixed back... |
464 |
btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV); |
f46b5a66b Btrfs: split out ... |
465 |
btrfs_set_header_owner(leaf, objectid); |
0b246afa6 btrfs: root->fs_i... |
466 467 |
write_extent_buffer_fsid(leaf, fs_info->fsid); write_extent_buffer_chunk_tree_uuid(leaf, fs_info->chunk_tree_uuid); |
f46b5a66b Btrfs: split out ... |
468 |
btrfs_mark_buffer_dirty(leaf); |
49a3c4d9b btrfs: use dynami... |
469 |
inode_item = &root_item->inode; |
3cae210fa btrfs: Cleanup fo... |
470 471 472 |
btrfs_set_stack_inode_generation(inode_item, 1); btrfs_set_stack_inode_size(inode_item, 3); btrfs_set_stack_inode_nlink(inode_item, 1); |
da17066c4 btrfs: pull node/... |
473 |
btrfs_set_stack_inode_nbytes(inode_item, |
0b246afa6 btrfs: root->fs_i... |
474 |
fs_info->nodesize); |
3cae210fa btrfs: Cleanup fo... |
475 |
btrfs_set_stack_inode_mode(inode_item, S_IFDIR | 0755); |
f46b5a66b Btrfs: split out ... |
476 |
|
49a3c4d9b btrfs: use dynami... |
477 478 |
btrfs_set_root_flags(root_item, 0); btrfs_set_root_limit(root_item, 0); |
3cae210fa btrfs: Cleanup fo... |
479 |
btrfs_set_stack_inode_flags(inode_item, BTRFS_INODE_ROOT_ITEM_INIT); |
08fe4db17 Btrfs: Fix uninit... |
480 |
|
49a3c4d9b btrfs: use dynami... |
481 482 483 484 485 486 |
btrfs_set_root_bytenr(root_item, leaf->start); btrfs_set_root_generation(root_item, trans->transid); btrfs_set_root_level(root_item, 0); btrfs_set_root_refs(root_item, 1); btrfs_set_root_used(root_item, leaf->len); btrfs_set_root_last_snapshot(root_item, 0); |
f46b5a66b Btrfs: split out ... |
487 |
|
49a3c4d9b btrfs: use dynami... |
488 489 |
btrfs_set_root_generation_v2(root_item, btrfs_root_generation(root_item)); |
8ea05e3a4 Btrfs: introduce ... |
490 |
uuid_le_gen(&new_uuid); |
49a3c4d9b btrfs: use dynami... |
491 492 493 494 495 496 |
memcpy(root_item->uuid, new_uuid.b, BTRFS_UUID_SIZE); btrfs_set_stack_timespec_sec(&root_item->otime, cur_time.tv_sec); btrfs_set_stack_timespec_nsec(&root_item->otime, cur_time.tv_nsec); root_item->ctime = root_item->otime; btrfs_set_root_ctransid(root_item, trans->transid); btrfs_set_root_otransid(root_item, trans->transid); |
f46b5a66b Btrfs: split out ... |
497 |
|
925baeddc Btrfs: Start btre... |
498 |
btrfs_tree_unlock(leaf); |
f46b5a66b Btrfs: split out ... |
499 500 |
free_extent_buffer(leaf); leaf = NULL; |
49a3c4d9b btrfs: use dynami... |
501 |
btrfs_set_root_dirid(root_item, new_dirid); |
f46b5a66b Btrfs: split out ... |
502 503 |
key.objectid = objectid; |
5d4f98a28 Btrfs: Mixed back... |
504 |
key.offset = 0; |
962a298f3 btrfs: kill the k... |
505 |
key.type = BTRFS_ROOT_ITEM_KEY; |
0b246afa6 btrfs: root->fs_i... |
506 |
ret = btrfs_insert_root(trans, fs_info->tree_root, &key, |
49a3c4d9b btrfs: use dynami... |
507 |
root_item); |
f46b5a66b Btrfs: split out ... |
508 509 |
if (ret) goto fail; |
76dda93c6 Btrfs: add snapsh... |
510 |
key.offset = (u64)-1; |
0b246afa6 btrfs: root->fs_i... |
511 |
new_root = btrfs_read_fs_root_no_name(fs_info, &key); |
79787eaab btrfs: replace ma... |
512 |
if (IS_ERR(new_root)) { |
79787eaab btrfs: replace ma... |
513 |
ret = PTR_ERR(new_root); |
66642832f btrfs: btrfs_abor... |
514 |
btrfs_abort_transaction(trans, ret); |
79787eaab btrfs: replace ma... |
515 516 |
goto fail; } |
76dda93c6 Btrfs: add snapsh... |
517 518 |
btrfs_record_root_in_trans(trans, new_root); |
63541927c Btrfs: add suppor... |
519 |
ret = btrfs_create_subvol_root(trans, new_root, root, new_dirid); |
ce598979b btrfs: Don't BUG_... |
520 521 |
if (ret) { /* We potentially lose an unused inode item here */ |
66642832f btrfs: btrfs_abor... |
522 |
btrfs_abort_transaction(trans, ret); |
ce598979b btrfs: Don't BUG_... |
523 524 |
goto fail; } |
f32e48e92 Btrfs: Initialize... |
525 526 527 |
mutex_lock(&new_root->objectid_mutex); new_root->highest_objectid = new_dirid; mutex_unlock(&new_root->objectid_mutex); |
f46b5a66b Btrfs: split out ... |
528 529 530 |
/* * insert the directory item */ |
877574e25 btrfs: Make btrfs... |
531 |
ret = btrfs_set_inode_index(BTRFS_I(dir), &index); |
79787eaab btrfs: replace ma... |
532 |
if (ret) { |
66642832f btrfs: btrfs_abor... |
533 |
btrfs_abort_transaction(trans, ret); |
79787eaab btrfs: replace ma... |
534 535 |
goto fail; } |
3de4586c5 Btrfs: Allow subv... |
536 537 |
ret = btrfs_insert_dir_item(trans, root, |
8e7611cf3 btrfs: Make btrfs... |
538 |
name, namelen, BTRFS_I(dir), &key, |
3de4586c5 Btrfs: Allow subv... |
539 |
BTRFS_FT_DIR, index); |
79787eaab btrfs: replace ma... |
540 |
if (ret) { |
66642832f btrfs: btrfs_abor... |
541 |
btrfs_abort_transaction(trans, ret); |
f46b5a66b Btrfs: split out ... |
542 |
goto fail; |
79787eaab btrfs: replace ma... |
543 |
} |
0660b5af3 Btrfs: Add backre... |
544 |
|
6ef06d279 btrfs: Make btrfs... |
545 |
btrfs_i_size_write(BTRFS_I(dir), dir->i_size + namelen * 2); |
52c261799 Btrfs: update dir... |
546 547 |
ret = btrfs_update_inode(trans, root, dir); BUG_ON(ret); |
0b246afa6 btrfs: root->fs_i... |
548 |
ret = btrfs_add_root_ref(trans, fs_info, |
4df27c4d5 Btrfs: change how... |
549 |
objectid, root->root_key.objectid, |
4a0cc7ca6 btrfs: Make btrfs... |
550 |
btrfs_ino(BTRFS_I(dir)), index, name, namelen); |
76dda93c6 Btrfs: add snapsh... |
551 |
BUG_ON(ret); |
f46b5a66b Btrfs: split out ... |
552 |
|
0b246afa6 btrfs: root->fs_i... |
553 |
ret = btrfs_uuid_tree_add(trans, fs_info, root_item->uuid, |
6bccf3ab1 btrfs: call funct... |
554 |
BTRFS_UUID_KEY_SUBVOL, objectid); |
dd5f9615f Btrfs: maintain s... |
555 |
if (ret) |
66642832f btrfs: btrfs_abor... |
556 |
btrfs_abort_transaction(trans, ret); |
dd5f9615f Btrfs: maintain s... |
557 |
|
f46b5a66b Btrfs: split out ... |
558 |
fail: |
49a3c4d9b btrfs: use dynami... |
559 |
kfree(root_item); |
d5c120701 Btrfs: fix wrong ... |
560 561 |
trans->block_rsv = NULL; trans->bytes_reserved = 0; |
7775c8184 btrfs: remove unu... |
562 |
btrfs_subvolume_release_metadata(fs_info, &block_rsv); |
de6e82006 Btrfs: release su... |
563 |
|
72fd032e9 Btrfs: add SNAP_C... |
564 565 |
if (async_transid) { *async_transid = trans->transid; |
3a45bb207 btrfs: remove roo... |
566 |
err = btrfs_commit_transaction_async(trans, 1); |
00d71c9c1 Btrfs: fix unclos... |
567 |
if (err) |
3a45bb207 btrfs: remove roo... |
568 |
err = btrfs_commit_transaction(trans); |
72fd032e9 Btrfs: add SNAP_C... |
569 |
} else { |
3a45bb207 btrfs: remove roo... |
570 |
err = btrfs_commit_transaction(trans); |
72fd032e9 Btrfs: add SNAP_C... |
571 |
} |
f46b5a66b Btrfs: split out ... |
572 573 |
if (err && !ret) ret = err; |
1a65e24b0 Btrfs: move d_ins... |
574 |
|
5662344b3 Btrfs: fix error ... |
575 576 |
if (!ret) { inode = btrfs_lookup_dentry(dir, dentry); |
de6e82006 Btrfs: release su... |
577 578 |
if (IS_ERR(inode)) return PTR_ERR(inode); |
5662344b3 Btrfs: fix error ... |
579 580 |
d_instantiate(dentry, inode); } |
f46b5a66b Btrfs: split out ... |
581 |
return ret; |
49a3c4d9b btrfs: use dynami... |
582 583 584 585 |
fail_free: kfree(root_item); return ret; |
f46b5a66b Btrfs: split out ... |
586 |
} |
ea14b57fd btrfs: fix spelli... |
587 |
static void btrfs_wait_for_no_snapshotting_writes(struct btrfs_root *root) |
8257b2dc3 Btrfs: introduce ... |
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 |
{ s64 writers; DEFINE_WAIT(wait); do { prepare_to_wait(&root->subv_writers->wait, &wait, TASK_UNINTERRUPTIBLE); writers = percpu_counter_sum(&root->subv_writers->counter); if (writers) schedule(); finish_wait(&root->subv_writers->wait, &wait); } while (writers); } |
e9662f701 Btrfs: remove unn... |
603 |
static int create_snapshot(struct btrfs_root *root, struct inode *dir, |
61d7e4cb1 btrfs: remove unu... |
604 |
struct dentry *dentry, |
e9662f701 Btrfs: remove unn... |
605 606 |
u64 *async_transid, bool readonly, struct btrfs_qgroup_inherit *inherit) |
f46b5a66b Btrfs: split out ... |
607 |
{ |
0b246afa6 btrfs: root->fs_i... |
608 |
struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb); |
2e4bfab97 Btrfs: Avoid orph... |
609 |
struct inode *inode; |
f46b5a66b Btrfs: split out ... |
610 611 |
struct btrfs_pending_snapshot *pending_snapshot; struct btrfs_trans_handle *trans; |
2e4bfab97 Btrfs: Avoid orph... |
612 |
int ret; |
f46b5a66b Btrfs: split out ... |
613 |
|
27cdeb709 Btrfs: use bitfie... |
614 |
if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state)) |
f46b5a66b Btrfs: split out ... |
615 |
return -EINVAL; |
23269bf5e btrfs: use GFP_KE... |
616 |
pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_KERNEL); |
a1ee73626 btrfs: do an allo... |
617 618 |
if (!pending_snapshot) return -ENOMEM; |
b0c0ea633 btrfs: allocate r... |
619 |
pending_snapshot->root_item = kzalloc(sizeof(struct btrfs_root_item), |
23269bf5e btrfs: use GFP_KE... |
620 |
GFP_KERNEL); |
8546b5705 btrfs: preallocat... |
621 622 |
pending_snapshot->path = btrfs_alloc_path(); if (!pending_snapshot->root_item || !pending_snapshot->path) { |
b0c0ea633 btrfs: allocate r... |
623 624 625 |
ret = -ENOMEM; goto free_pending; } |
ea14b57fd btrfs: fix spelli... |
626 |
atomic_inc(&root->will_be_snapshotted); |
4e857c58e arch: Mass conver... |
627 |
smp_mb__after_atomic(); |
ea14b57fd btrfs: fix spelli... |
628 |
btrfs_wait_for_no_snapshotting_writes(root); |
8257b2dc3 Btrfs: introduce ... |
629 |
|
6a03843df Btrfs: just flush... |
630 631 |
ret = btrfs_start_delalloc_inodes(root, 0); if (ret) |
a1ee73626 btrfs: do an allo... |
632 |
goto dec_and_free; |
6a03843df Btrfs: just flush... |
633 |
|
6374e57ad btrfs: fix intege... |
634 |
btrfs_wait_ordered_extents(root, U64_MAX, 0, (u64)-1); |
6a03843df Btrfs: just flush... |
635 |
|
66d8f3dd1 Btrfs: add a new ... |
636 637 |
btrfs_init_block_rsv(&pending_snapshot->block_rsv, BTRFS_BLOCK_RSV_TEMP); |
d5c120701 Btrfs: fix wrong ... |
638 639 640 641 642 643 |
/* * 1 - parent dir inode * 2 - dir entries * 1 - root item * 2 - root ref/backref * 1 - root of snapshot |
dd5f9615f Btrfs: maintain s... |
644 |
* 1 - UUID item |
d5c120701 Btrfs: fix wrong ... |
645 646 |
*/ ret = btrfs_subvolume_reserve_metadata(BTRFS_I(dir)->root, |
dd5f9615f Btrfs: maintain s... |
647 |
&pending_snapshot->block_rsv, 8, |
ee3441b49 btrfs: fall back ... |
648 649 |
&pending_snapshot->qgroup_reserved, false); |
d5c120701 Btrfs: fix wrong ... |
650 |
if (ret) |
a1ee73626 btrfs: do an allo... |
651 |
goto dec_and_free; |
d5c120701 Btrfs: fix wrong ... |
652 |
|
3de4586c5 Btrfs: Allow subv... |
653 |
pending_snapshot->dentry = dentry; |
f46b5a66b Btrfs: split out ... |
654 |
pending_snapshot->root = root; |
b83cc9693 Btrfs: Add readon... |
655 |
pending_snapshot->readonly = readonly; |
e9662f701 Btrfs: remove unn... |
656 |
pending_snapshot->dir = dir; |
8696c5330 Btrfs: fix memory... |
657 |
pending_snapshot->inherit = inherit; |
a22285a6a Btrfs: Integrate ... |
658 |
|
d5c120701 Btrfs: fix wrong ... |
659 |
trans = btrfs_start_transaction(root, 0); |
a22285a6a Btrfs: Integrate ... |
660 661 662 663 |
if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto fail; } |
0b246afa6 btrfs: root->fs_i... |
664 |
spin_lock(&fs_info->trans_lock); |
f46b5a66b Btrfs: split out ... |
665 666 |
list_add(&pending_snapshot->list, &trans->transaction->pending_snapshots); |
0b246afa6 btrfs: root->fs_i... |
667 |
spin_unlock(&fs_info->trans_lock); |
72fd032e9 Btrfs: add SNAP_C... |
668 669 |
if (async_transid) { *async_transid = trans->transid; |
3a45bb207 btrfs: remove roo... |
670 |
ret = btrfs_commit_transaction_async(trans, 1); |
00d71c9c1 Btrfs: fix unclos... |
671 |
if (ret) |
3a45bb207 btrfs: remove roo... |
672 |
ret = btrfs_commit_transaction(trans); |
72fd032e9 Btrfs: add SNAP_C... |
673 |
} else { |
3a45bb207 btrfs: remove roo... |
674 |
ret = btrfs_commit_transaction(trans); |
72fd032e9 Btrfs: add SNAP_C... |
675 |
} |
aec8030a8 Btrfs: fix wrong ... |
676 |
if (ret) |
c37b2b626 Btrfs: do not bug... |
677 |
goto fail; |
a22285a6a Btrfs: Integrate ... |
678 679 680 681 |
ret = pending_snapshot->error; if (ret) goto fail; |
d37973082 Revert "Btrfs: ra... |
682 683 684 |
ret = btrfs_orphan_cleanup(pending_snapshot->snap); if (ret) goto fail; |
2b0143b5c VFS: normal files... |
685 |
inode = btrfs_lookup_dentry(d_inode(dentry->d_parent), dentry); |
2e4bfab97 Btrfs: Avoid orph... |
686 687 688 689 |
if (IS_ERR(inode)) { ret = PTR_ERR(inode); goto fail; } |
5662344b3 Btrfs: fix error ... |
690 |
|
2e4bfab97 Btrfs: Avoid orph... |
691 692 693 |
d_instantiate(dentry, inode); ret = 0; fail: |
7775c8184 btrfs: remove unu... |
694 |
btrfs_subvolume_release_metadata(fs_info, &pending_snapshot->block_rsv); |
a1ee73626 btrfs: do an allo... |
695 |
dec_and_free: |
ea14b57fd btrfs: fix spelli... |
696 697 |
if (atomic_dec_and_test(&root->will_be_snapshotted)) wake_up_atomic_t(&root->will_be_snapshotted); |
b0c0ea633 btrfs: allocate r... |
698 699 |
free_pending: kfree(pending_snapshot->root_item); |
8546b5705 btrfs: preallocat... |
700 |
btrfs_free_path(pending_snapshot->path); |
a1ee73626 btrfs: do an allo... |
701 |
kfree(pending_snapshot); |
f46b5a66b Btrfs: split out ... |
702 703 |
return ret; } |
4260f7c75 Btrfs: allow subv... |
704 705 706 707 708 709 710 711 712 713 714 |
/* 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 |
013276101 btrfs: fix string... |
715 |
* 6. If the victim is append-only or immutable we can't do anything with |
4260f7c75 Btrfs: allow subv... |
716 717 718 719 720 721 722 |
* 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(). */ |
678712545 btrfs: Fix checkp... |
723 |
static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir) |
4260f7c75 Btrfs: allow subv... |
724 725 |
{ int error; |
2b0143b5c VFS: normal files... |
726 |
if (d_really_is_negative(victim)) |
4260f7c75 Btrfs: allow subv... |
727 |
return -ENOENT; |
2b0143b5c VFS: normal files... |
728 |
BUG_ON(d_inode(victim->d_parent) != dir); |
4fa6b5ecb audit: overhaul _... |
729 |
audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE); |
4260f7c75 Btrfs: allow subv... |
730 731 732 733 734 735 |
error = inode_permission(dir, MAY_WRITE | MAY_EXEC); if (error) return error; if (IS_APPEND(dir)) return -EPERM; |
2b0143b5c VFS: normal files... |
736 737 |
if (check_sticky(dir, d_inode(victim)) || IS_APPEND(d_inode(victim)) || IS_IMMUTABLE(d_inode(victim)) || IS_SWAPFILE(d_inode(victim))) |
4260f7c75 Btrfs: allow subv... |
738 739 |
return -EPERM; if (isdir) { |
e36cb0b89 VFS: (Scripted) C... |
740 |
if (!d_is_dir(victim)) |
4260f7c75 Btrfs: allow subv... |
741 742 743 |
return -ENOTDIR; if (IS_ROOT(victim)) return -EBUSY; |
e36cb0b89 VFS: (Scripted) C... |
744 |
} else if (d_is_dir(victim)) |
4260f7c75 Btrfs: allow subv... |
745 746 747 748 749 750 751 |
return -EISDIR; if (IS_DEADDIR(dir)) return -ENOENT; if (victim->d_flags & DCACHE_NFSFS_RENAMED) return -EBUSY; return 0; } |
cb8e70901 Btrfs: Fix subvol... |
752 753 754 |
/* copy of may_create in fs/namei.c() */ static inline int btrfs_may_create(struct inode *dir, struct dentry *child) { |
2b0143b5c VFS: normal files... |
755 |
if (d_really_is_positive(child)) |
cb8e70901 Btrfs: Fix subvol... |
756 757 758 759 760 761 762 763 764 765 766 |
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. */ |
92872094a constify btrfs_mk... |
767 |
static noinline int btrfs_mksubvol(const struct path *parent, |
52f75f4fe btrfs: constify n... |
768 |
const char *name, int namelen, |
72fd032e9 Btrfs: add SNAP_C... |
769 |
struct btrfs_root *snap_src, |
6f72c7e20 Btrfs: add qgroup... |
770 |
u64 *async_transid, bool readonly, |
8696c5330 Btrfs: fix memory... |
771 |
struct btrfs_qgroup_inherit *inherit) |
cb8e70901 Btrfs: Fix subvol... |
772 |
{ |
0b246afa6 btrfs: root->fs_i... |
773 774 |
struct inode *dir = d_inode(parent->dentry); struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb); |
cb8e70901 Btrfs: Fix subvol... |
775 776 |
struct dentry *dentry; int error; |
002354112 restore killabili... |
777 778 779 |
error = down_write_killable_nested(&dir->i_rwsem, I_MUTEX_PARENT); if (error == -EINTR) return error; |
cb8e70901 Btrfs: Fix subvol... |
780 781 782 783 784 |
dentry = lookup_one_len(name, parent->dentry, namelen); error = PTR_ERR(dentry); if (IS_ERR(dentry)) goto out_unlock; |
76dda93c6 Btrfs: add snapsh... |
785 |
error = btrfs_may_create(dir, dentry); |
cb8e70901 Btrfs: Fix subvol... |
786 |
if (error) |
a874a63e1 Btrfs: check writ... |
787 |
goto out_dput; |
cb8e70901 Btrfs: Fix subvol... |
788 |
|
9c52057c6 Btrfs: fix hash o... |
789 790 791 792 793 794 795 796 797 |
/* * even if this name doesn't exist, we may get hash collisions. * check for them now when we can safely fail */ error = btrfs_check_dir_item_collision(BTRFS_I(dir)->root, dir->i_ino, name, namelen); if (error) goto out_dput; |
0b246afa6 btrfs: root->fs_i... |
798 |
down_read(&fs_info->subvol_sem); |
76dda93c6 Btrfs: add snapsh... |
799 800 801 |
if (btrfs_root_refs(&BTRFS_I(dir)->root->root_item) == 0) goto out_up_read; |
3de4586c5 Btrfs: Allow subv... |
802 |
if (snap_src) { |
61d7e4cb1 btrfs: remove unu... |
803 |
error = create_snapshot(snap_src, dir, dentry, |
6f72c7e20 Btrfs: add qgroup... |
804 |
async_transid, readonly, inherit); |
3de4586c5 Btrfs: Allow subv... |
805 |
} else { |
d5c120701 Btrfs: fix wrong ... |
806 807 |
error = create_subvol(dir, dentry, name, namelen, async_transid, inherit); |
3de4586c5 Btrfs: Allow subv... |
808 |
} |
76dda93c6 Btrfs: add snapsh... |
809 810 811 |
if (!error) fsnotify_mkdir(dir, dentry); out_up_read: |
0b246afa6 btrfs: root->fs_i... |
812 |
up_read(&fs_info->subvol_sem); |
cb8e70901 Btrfs: Fix subvol... |
813 814 815 |
out_dput: dput(dentry); out_unlock: |
5955102c9 wrappers for ->i_... |
816 |
inode_unlock(dir); |
cb8e70901 Btrfs: Fix subvol... |
817 818 |
return error; } |
4cb5300bc Btrfs: add mount ... |
819 820 821 822 823 824 825 |
/* * 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 */ |
aab110abc btrfs: defrag, us... |
826 |
static int check_defrag_in_cache(struct inode *inode, u64 offset, u32 thresh) |
4cb5300bc Btrfs: add mount ... |
827 828 829 830 831 832 833 |
{ 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); |
09cbfeaf1 mm, fs: get rid o... |
834 |
em = lookup_extent_mapping(em_tree, offset, PAGE_SIZE); |
4cb5300bc Btrfs: add mount ... |
835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 |
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, |
aab110abc btrfs: defrag, us... |
861 |
u64 *off, u32 thresh) |
4cb5300bc Btrfs: add mount ... |
862 863 864 |
{ struct btrfs_path *path; struct btrfs_key min_key; |
4cb5300bc Btrfs: add mount ... |
865 866 867 868 |
struct extent_buffer *leaf; struct btrfs_file_extent_item *extent; int type; int ret; |
4a0cc7ca6 btrfs: Make btrfs... |
869 |
u64 ino = btrfs_ino(BTRFS_I(inode)); |
4cb5300bc Btrfs: add mount ... |
870 871 872 873 |
path = btrfs_alloc_path(); if (!path) return -ENOMEM; |
a4689d2bd btrfs: use btrfs_... |
874 |
min_key.objectid = ino; |
4cb5300bc Btrfs: add mount ... |
875 876 |
min_key.type = BTRFS_EXTENT_DATA_KEY; min_key.offset = *off; |
678712545 btrfs: Fix checkp... |
877 |
while (1) { |
6174d3cb4 Btrfs: remove unu... |
878 |
ret = btrfs_search_forward(root, &min_key, path, newer_than); |
4cb5300bc Btrfs: add mount ... |
879 880 |
if (ret != 0) goto none; |
f094c9bd3 Btrfs: less fs tr... |
881 |
process_slot: |
a4689d2bd btrfs: use btrfs_... |
882 |
if (min_key.objectid != ino) |
4cb5300bc Btrfs: add mount ... |
883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 |
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; } |
f094c9bd3 Btrfs: less fs tr... |
899 900 901 902 903 |
path->slots[0]++; if (path->slots[0] < btrfs_header_nritems(leaf)) { btrfs_item_key_to_cpu(leaf, &min_key, path->slots[0]); goto process_slot; } |
4cb5300bc Btrfs: add mount ... |
904 905 906 907 908 909 910 911 912 913 |
if (min_key.offset == (u64)-1) goto none; min_key.offset++; btrfs_release_path(path); } none: btrfs_free_path(path); return -ENOENT; } |
6c282eb40 Btrfs: fix defrag... |
914 |
static struct extent_map *defrag_lookup_extent(struct inode *inode, u64 start) |
17ce6ef8d Btrfs: add a chec... |
915 916 |
{ struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; |
6c282eb40 Btrfs: fix defrag... |
917 918 |
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; struct extent_map *em; |
09cbfeaf1 mm, fs: get rid o... |
919 |
u64 len = PAGE_SIZE; |
17ce6ef8d Btrfs: add a chec... |
920 |
|
6c282eb40 Btrfs: fix defrag... |
921 922 923 924 |
/* * hopefully we have this extent in the tree already, try without * the full extent lock */ |
17ce6ef8d Btrfs: add a chec... |
925 |
read_lock(&em_tree->lock); |
6c282eb40 Btrfs: fix defrag... |
926 |
em = lookup_extent_mapping(em_tree, start, len); |
17ce6ef8d Btrfs: add a chec... |
927 |
read_unlock(&em_tree->lock); |
6c282eb40 Btrfs: fix defrag... |
928 |
if (!em) { |
308d9800b Btrfs: cache exte... |
929 930 |
struct extent_state *cached = NULL; u64 end = start + len - 1; |
6c282eb40 Btrfs: fix defrag... |
931 |
/* get the big lock and read metadata off disk */ |
ff13db41f btrfs: drop unuse... |
932 |
lock_extent_bits(io_tree, start, end, &cached); |
fc4f21b1d btrfs: Make get_e... |
933 |
em = btrfs_get_extent(BTRFS_I(inode), NULL, 0, start, len, 0); |
308d9800b Btrfs: cache exte... |
934 |
unlock_extent_cached(io_tree, start, end, &cached, GFP_NOFS); |
6c282eb40 Btrfs: fix defrag... |
935 936 937 938 939 940 941 |
if (IS_ERR(em)) return NULL; } return em; } |
17ce6ef8d Btrfs: add a chec... |
942 |
|
6c282eb40 Btrfs: fix defrag... |
943 944 945 946 947 948 949 950 951 952 |
static bool defrag_check_next_extent(struct inode *inode, struct extent_map *em) { struct extent_map *next; bool ret = true; /* this is the last extent */ if (em->start + em->len >= i_size_read(inode)) return false; next = defrag_lookup_extent(inode, em->start + em->len); |
e9512d72e Btrfs: fix autode... |
953 954 955 |
if (!next || next->block_start >= EXTENT_MAP_LAST_BYTE) ret = false; else if ((em->block_start + em->block_len == next->block_start) && |
ee22184b5 Btrfs: use linux/... |
956 |
(em->block_len > SZ_128K && next->block_len > SZ_128K)) |
6c282eb40 Btrfs: fix defrag... |
957 958 959 |
ret = false; free_extent_map(next); |
17ce6ef8d Btrfs: add a chec... |
960 961 |
return ret; } |
aab110abc btrfs: defrag, us... |
962 |
static int should_defrag_range(struct inode *inode, u64 start, u32 thresh, |
a43a21113 btrfs: ignore unf... |
963 964 |
u64 *last_len, u64 *skip, u64 *defrag_end, int compress) |
940100a4a Btrfs: be more se... |
965 |
{ |
6c282eb40 Btrfs: fix defrag... |
966 |
struct extent_map *em; |
940100a4a Btrfs: be more se... |
967 |
int ret = 1; |
6c282eb40 Btrfs: fix defrag... |
968 |
bool next_mergeable = true; |
4a3560c4f Btrfs: fix defrag... |
969 |
bool prev_mergeable = true; |
940100a4a Btrfs: be more se... |
970 971 |
/* |
008873eaf Btrfs: honor exte... |
972 |
* make sure that once we start defragging an extent, we keep on |
940100a4a Btrfs: be more se... |
973 974 975 976 977 978 |
* defragging it */ if (start < *defrag_end) return 1; *skip = 0; |
6c282eb40 Btrfs: fix defrag... |
979 980 981 |
em = defrag_lookup_extent(inode, start); if (!em) return 0; |
940100a4a Btrfs: be more se... |
982 983 |
/* this will cover holes, and inline extents */ |
17ce6ef8d Btrfs: add a chec... |
984 |
if (em->block_start >= EXTENT_MAP_LAST_BYTE) { |
940100a4a Btrfs: be more se... |
985 |
ret = 0; |
17ce6ef8d Btrfs: add a chec... |
986 987 |
goto out; } |
4a3560c4f Btrfs: fix defrag... |
988 989 |
if (!*defrag_end) prev_mergeable = false; |
6c282eb40 Btrfs: fix defrag... |
990 |
next_mergeable = defrag_check_next_extent(inode, em); |
940100a4a Btrfs: be more se... |
991 |
/* |
6c282eb40 Btrfs: fix defrag... |
992 993 |
* we hit a real extent, if it is big or the next extent is not a * real extent, don't bother defragging it |
940100a4a Btrfs: be more se... |
994 |
*/ |
a43a21113 btrfs: ignore unf... |
995 |
if (!compress && (*last_len == 0 || *last_len >= thresh) && |
4a3560c4f Btrfs: fix defrag... |
996 |
(em->len >= thresh || (!next_mergeable && !prev_mergeable))) |
940100a4a Btrfs: be more se... |
997 |
ret = 0; |
17ce6ef8d Btrfs: add a chec... |
998 |
out: |
940100a4a Btrfs: be more se... |
999 1000 1001 1002 1003 1004 1005 1006 1007 |
/* * 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... |
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 |
*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 ... |
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 |
/* * 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, |
c41570c9d btrfs: fix defrag... |
1033 |
unsigned long num_pages) |
f46b5a66b Btrfs: split out ... |
1034 |
{ |
4cb5300bc Btrfs: add mount ... |
1035 1036 1037 1038 |
unsigned long file_end; u64 isize = i_size_read(inode); u64 page_start; u64 page_end; |
1f12bd063 Btrfs: fix the mi... |
1039 |
u64 page_cnt; |
4cb5300bc Btrfs: add mount ... |
1040 1041 1042 |
int ret; int i; int i_done; |
3eaa28852 Btrfs: Fix the de... |
1043 |
struct btrfs_ordered_extent *ordered; |
4cb5300bc Btrfs: add mount ... |
1044 |
struct extent_state *cached_state = NULL; |
600a45e1d Btrfs: fix deadlo... |
1045 |
struct extent_io_tree *tree; |
364ecf365 btrfs: qgroup: In... |
1046 |
struct extent_changeset *data_reserved = NULL; |
3b16a4e3c Btrfs: use the in... |
1047 |
gfp_t mask = btrfs_alloc_write_mask(inode->i_mapping); |
4cb5300bc Btrfs: add mount ... |
1048 |
|
09cbfeaf1 mm, fs: get rid o... |
1049 |
file_end = (isize - 1) >> PAGE_SHIFT; |
1f12bd063 Btrfs: fix the mi... |
1050 1051 1052 1053 |
if (!isize || start_index > file_end) return 0; page_cnt = min_t(u64, (u64)num_pages, (u64)file_end - start_index + 1); |
4cb5300bc Btrfs: add mount ... |
1054 |
|
364ecf365 btrfs: qgroup: In... |
1055 |
ret = btrfs_delalloc_reserve_space(inode, &data_reserved, |
09cbfeaf1 mm, fs: get rid o... |
1056 1057 |
start_index << PAGE_SHIFT, page_cnt << PAGE_SHIFT); |
4cb5300bc Btrfs: add mount ... |
1058 1059 |
if (ret) return ret; |
4cb5300bc Btrfs: add mount ... |
1060 |
i_done = 0; |
600a45e1d Btrfs: fix deadlo... |
1061 |
tree = &BTRFS_I(inode)->io_tree; |
4cb5300bc Btrfs: add mount ... |
1062 1063 |
/* step one, lock all the pages */ |
1f12bd063 Btrfs: fix the mi... |
1064 |
for (i = 0; i < page_cnt; i++) { |
4cb5300bc Btrfs: add mount ... |
1065 |
struct page *page; |
600a45e1d Btrfs: fix deadlo... |
1066 |
again: |
a94733d0b Btrfs: use find_o... |
1067 |
page = find_or_create_page(inode->i_mapping, |
600a45e1d Btrfs: fix deadlo... |
1068 |
start_index + i, mask); |
4cb5300bc Btrfs: add mount ... |
1069 1070 |
if (!page) break; |
600a45e1d Btrfs: fix deadlo... |
1071 |
page_start = page_offset(page); |
09cbfeaf1 mm, fs: get rid o... |
1072 |
page_end = page_start + PAGE_SIZE - 1; |
600a45e1d Btrfs: fix deadlo... |
1073 |
while (1) { |
308d9800b Btrfs: cache exte... |
1074 |
lock_extent_bits(tree, page_start, page_end, |
ff13db41f btrfs: drop unuse... |
1075 |
&cached_state); |
600a45e1d Btrfs: fix deadlo... |
1076 1077 |
ordered = btrfs_lookup_ordered_extent(inode, page_start); |
308d9800b Btrfs: cache exte... |
1078 1079 |
unlock_extent_cached(tree, page_start, page_end, &cached_state, GFP_NOFS); |
600a45e1d Btrfs: fix deadlo... |
1080 1081 1082 1083 1084 1085 1086 |
if (!ordered) break; unlock_page(page); btrfs_start_ordered_extent(inode, ordered, 1); btrfs_put_ordered_extent(ordered); lock_page(page); |
1f12bd063 Btrfs: fix the mi... |
1087 1088 1089 1090 1091 1092 |
/* * we unlocked the page above, so we need check if * it was released or not. */ if (page->mapping != inode->i_mapping) { unlock_page(page); |
09cbfeaf1 mm, fs: get rid o... |
1093 |
put_page(page); |
1f12bd063 Btrfs: fix the mi... |
1094 1095 |
goto again; } |
600a45e1d Btrfs: fix deadlo... |
1096 |
} |
4cb5300bc Btrfs: add mount ... |
1097 1098 1099 1100 1101 |
if (!PageUptodate(page)) { btrfs_readpage(NULL, page); lock_page(page); if (!PageUptodate(page)) { unlock_page(page); |
09cbfeaf1 mm, fs: get rid o... |
1102 |
put_page(page); |
4cb5300bc Btrfs: add mount ... |
1103 1104 1105 1106 |
ret = -EIO; break; } } |
600a45e1d Btrfs: fix deadlo... |
1107 |
|
600a45e1d Btrfs: fix deadlo... |
1108 1109 |
if (page->mapping != inode->i_mapping) { unlock_page(page); |
09cbfeaf1 mm, fs: get rid o... |
1110 |
put_page(page); |
600a45e1d Btrfs: fix deadlo... |
1111 1112 |
goto again; } |
4cb5300bc Btrfs: add mount ... |
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 |
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]); |
09cbfeaf1 mm, fs: get rid o... |
1130 |
page_end = page_offset(pages[i_done - 1]) + PAGE_SIZE; |
4cb5300bc Btrfs: add mount ... |
1131 1132 |
lock_extent_bits(&BTRFS_I(inode)->io_tree, |
ff13db41f btrfs: drop unuse... |
1133 |
page_start, page_end - 1, &cached_state); |
4cb5300bc Btrfs: add mount ... |
1134 1135 |
clear_extent_bit(&BTRFS_I(inode)->io_tree, page_start, page_end - 1, EXTENT_DIRTY | EXTENT_DELALLOC | |
9e8a4a8b0 Btrfs: use flag E... |
1136 1137 |
EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, 0, 0, &cached_state, GFP_NOFS); |
4cb5300bc Btrfs: add mount ... |
1138 |
|
1f12bd063 Btrfs: fix the mi... |
1139 |
if (i_done != page_cnt) { |
9e0baf60d Btrfs: fix enospc... |
1140 1141 1142 |
spin_lock(&BTRFS_I(inode)->lock); BTRFS_I(inode)->outstanding_extents++; spin_unlock(&BTRFS_I(inode)->lock); |
bc42bda22 btrfs: qgroup: Fi... |
1143 |
btrfs_delalloc_release_space(inode, data_reserved, |
09cbfeaf1 mm, fs: get rid o... |
1144 1145 |
start_index << PAGE_SHIFT, (page_cnt - i_done) << PAGE_SHIFT); |
4cb5300bc Btrfs: add mount ... |
1146 |
} |
9e8a4a8b0 Btrfs: use flag E... |
1147 |
set_extent_defrag(&BTRFS_I(inode)->io_tree, page_start, page_end - 1, |
018ed4f78 btrfs: sink gfp p... |
1148 |
&cached_state); |
4cb5300bc Btrfs: add mount ... |
1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 |
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]); |
09cbfeaf1 mm, fs: get rid o... |
1160 |
put_page(pages[i]); |
4cb5300bc Btrfs: add mount ... |
1161 |
} |
364ecf365 btrfs: qgroup: In... |
1162 |
extent_changeset_free(data_reserved); |
4cb5300bc Btrfs: add mount ... |
1163 1164 1165 1166 |
return i_done; out: for (i = 0; i < i_done; i++) { unlock_page(pages[i]); |
09cbfeaf1 mm, fs: get rid o... |
1167 |
put_page(pages[i]); |
4cb5300bc Btrfs: add mount ... |
1168 |
} |
bc42bda22 btrfs: qgroup: Fi... |
1169 |
btrfs_delalloc_release_space(inode, data_reserved, |
09cbfeaf1 mm, fs: get rid o... |
1170 1171 |
start_index << PAGE_SHIFT, page_cnt << PAGE_SHIFT); |
364ecf365 btrfs: qgroup: In... |
1172 |
extent_changeset_free(data_reserved); |
4cb5300bc Btrfs: add mount ... |
1173 1174 1175 1176 1177 1178 1179 1180 |
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) { |
0b246afa6 btrfs: root->fs_i... |
1181 |
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); |
4cb5300bc Btrfs: add mount ... |
1182 |
struct btrfs_root *root = BTRFS_I(inode)->root; |
4cb5300bc Btrfs: add mount ... |
1183 |
struct file_ra_state *ra = NULL; |
f46b5a66b Btrfs: split out ... |
1184 |
unsigned long last_index; |
151a31b25 Btrfs: use i_size... |
1185 |
u64 isize = i_size_read(inode); |
940100a4a Btrfs: be more se... |
1186 1187 1188 |
u64 last_len = 0; u64 skip = 0; u64 defrag_end = 0; |
4cb5300bc Btrfs: add mount ... |
1189 |
u64 newer_off = range->start; |
f46b5a66b Btrfs: split out ... |
1190 |
unsigned long i; |
008873eaf Btrfs: honor exte... |
1191 |
unsigned long ra_index = 0; |
f46b5a66b Btrfs: split out ... |
1192 |
int ret; |
4cb5300bc Btrfs: add mount ... |
1193 |
int defrag_count = 0; |
1a419d85a btrfs: Allow to s... |
1194 |
int compress_type = BTRFS_COMPRESS_ZLIB; |
aab110abc btrfs: defrag, us... |
1195 |
u32 extent_thresh = range->extent_thresh; |
09cbfeaf1 mm, fs: get rid o... |
1196 |
unsigned long max_cluster = SZ_256K >> PAGE_SHIFT; |
c41570c9d btrfs: fix defrag... |
1197 |
unsigned long cluster = max_cluster; |
ee22184b5 Btrfs: use linux/... |
1198 |
u64 new_align = ~((u64)SZ_128K - 1); |
4cb5300bc Btrfs: add mount ... |
1199 |
struct page **pages = NULL; |
1e2ef46d8 btrfs: defrag: cl... |
1200 |
bool do_compress = range->flags & BTRFS_DEFRAG_RANGE_COMPRESS; |
4cb5300bc Btrfs: add mount ... |
1201 |
|
0abd5b172 Btrfs: return err... |
1202 1203 1204 1205 1206 |
if (isize == 0) return 0; if (range->start >= isize) return -EINVAL; |
1a419d85a btrfs: Allow to s... |
1207 |
|
1e2ef46d8 btrfs: defrag: cl... |
1208 |
if (do_compress) { |
1a419d85a btrfs: Allow to s... |
1209 1210 1211 1212 1213 |
if (range->compress_type > BTRFS_COMPRESS_TYPES) return -EINVAL; if (range->compress_type) compress_type = range->compress_type; } |
f46b5a66b Btrfs: split out ... |
1214 |
|
0abd5b172 Btrfs: return err... |
1215 |
if (extent_thresh == 0) |
ee22184b5 Btrfs: use linux/... |
1216 |
extent_thresh = SZ_256K; |
940100a4a Btrfs: be more se... |
1217 |
|
4cb5300bc Btrfs: add mount ... |
1218 |
/* |
0a52d1080 btrfs: defrag: ma... |
1219 1220 1221 |
* If we were not given a file, allocate a readahead context. As * readahead is just an optimization, defrag will work without it so * we don't error out. |
4cb5300bc Btrfs: add mount ... |
1222 1223 |
*/ if (!file) { |
63e727ecd btrfs: use GFP_KE... |
1224 |
ra = kzalloc(sizeof(*ra), GFP_KERNEL); |
0a52d1080 btrfs: defrag: ma... |
1225 1226 |
if (ra) file_ra_state_init(ra, inode->i_mapping); |
4cb5300bc Btrfs: add mount ... |
1227 1228 1229 |
} else { ra = &file->f_ra; } |
63e727ecd btrfs: use GFP_KE... |
1230 |
pages = kmalloc_array(max_cluster, sizeof(struct page *), GFP_KERNEL); |
4cb5300bc Btrfs: add mount ... |
1231 1232 1233 1234 1235 1236 |
if (!pages) { ret = -ENOMEM; goto out_ra; } /* find the last page to defrag */ |
1e701a329 Btrfs: add new de... |
1237 |
if (range->start + range->len > range->start) { |
151a31b25 Btrfs: use i_size... |
1238 |
last_index = min_t(u64, isize - 1, |
09cbfeaf1 mm, fs: get rid o... |
1239 |
range->start + range->len - 1) >> PAGE_SHIFT; |
1e701a329 Btrfs: add new de... |
1240 |
} else { |
09cbfeaf1 mm, fs: get rid o... |
1241 |
last_index = (isize - 1) >> PAGE_SHIFT; |
1e701a329 Btrfs: add new de... |
1242 |
} |
4cb5300bc Btrfs: add mount ... |
1243 1244 |
if (newer_than) { ret = find_new_extents(root, inode, newer_than, |
ee22184b5 Btrfs: use linux/... |
1245 |
&newer_off, SZ_64K); |
4cb5300bc Btrfs: add mount ... |
1246 1247 1248 1249 1250 1251 |
if (!ret) { range->start = newer_off; /* * we always align our defrag to help keep * the extents in the file evenly spaced */ |
09cbfeaf1 mm, fs: get rid o... |
1252 |
i = (newer_off & new_align) >> PAGE_SHIFT; |
4cb5300bc Btrfs: add mount ... |
1253 1254 1255 |
} else goto out_ra; } else { |
09cbfeaf1 mm, fs: get rid o... |
1256 |
i = range->start >> PAGE_SHIFT; |
4cb5300bc Btrfs: add mount ... |
1257 1258 |
} if (!max_to_defrag) |
070034bdf Btrfs: btrfs_defr... |
1259 |
max_to_defrag = last_index - i + 1; |
4cb5300bc Btrfs: add mount ... |
1260 |
|
2a0f7f576 Btrfs: fix recurs... |
1261 1262 1263 1264 1265 1266 |
/* * 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 ... |
1267 |
while (i <= last_index && defrag_count < max_to_defrag && |
09cbfeaf1 mm, fs: get rid o... |
1268 |
(i < DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE))) { |
4cb5300bc Btrfs: add mount ... |
1269 1270 1271 1272 1273 1274 |
/* * make sure we stop running if someone unmounts * the FS */ if (!(inode->i_sb->s_flags & MS_ACTIVE)) break; |
0b246afa6 btrfs: root->fs_i... |
1275 1276 |
if (btrfs_defrag_cancelled(fs_info)) { btrfs_debug(fs_info, "defrag_file cancelled"); |
210549ebe btrfs: add cancel... |
1277 1278 1279 |
ret = -EAGAIN; break; } |
09cbfeaf1 mm, fs: get rid o... |
1280 |
if (!should_defrag_range(inode, (u64)i << PAGE_SHIFT, |
6c282eb40 Btrfs: fix defrag... |
1281 |
extent_thresh, &last_len, &skip, |
1e2ef46d8 btrfs: defrag: cl... |
1282 |
&defrag_end, do_compress)){ |
940100a4a Btrfs: be more se... |
1283 1284 1285 1286 1287 |
unsigned long next; /* * the should_defrag function tells us how much to skip * bump our counter by the suggested amount */ |
09cbfeaf1 mm, fs: get rid o... |
1288 |
next = DIV_ROUND_UP(skip, PAGE_SIZE); |
940100a4a Btrfs: be more se... |
1289 1290 1291 |
i = max(i + 1, next); continue; } |
008873eaf Btrfs: honor exte... |
1292 1293 |
if (!newer_than) { |
09cbfeaf1 mm, fs: get rid o... |
1294 1295 |
cluster = (PAGE_ALIGN(defrag_end) >> PAGE_SHIFT) - i; |
008873eaf Btrfs: honor exte... |
1296 1297 1298 1299 |
cluster = min(cluster, max_cluster); } else { cluster = max_cluster; } |
008873eaf Btrfs: honor exte... |
1300 1301 |
if (i + cluster > ra_index) { ra_index = max(i, ra_index); |
0a52d1080 btrfs: defrag: ma... |
1302 |
if (ra) |
d3c0bab56 btrfs: remove tri... |
1303 1304 |
page_cache_sync_readahead(inode->i_mapping, ra, file, ra_index, cluster); |
e4826a5b2 Btrfs: btrfs_defr... |
1305 |
ra_index += cluster; |
008873eaf Btrfs: honor exte... |
1306 |
} |
940100a4a Btrfs: be more se... |
1307 |
|
5955102c9 wrappers for ->i_... |
1308 |
inode_lock(inode); |
1e2ef46d8 btrfs: defrag: cl... |
1309 |
if (do_compress) |
eec63c65d btrfs: separate d... |
1310 |
BTRFS_I(inode)->defrag_compress = compress_type; |
008873eaf Btrfs: honor exte... |
1311 |
ret = cluster_pages_for_defrag(inode, pages, i, cluster); |
ecb8bea87 Btrfs: fix race b... |
1312 |
if (ret < 0) { |
5955102c9 wrappers for ->i_... |
1313 |
inode_unlock(inode); |
4cb5300bc Btrfs: add mount ... |
1314 |
goto out_ra; |
ecb8bea87 Btrfs: fix race b... |
1315 |
} |
4cb5300bc Btrfs: add mount ... |
1316 1317 |
defrag_count += ret; |
d0e1d66b5 writeback: remove... |
1318 |
balance_dirty_pages_ratelimited(inode->i_mapping); |
5955102c9 wrappers for ->i_... |
1319 |
inode_unlock(inode); |
4cb5300bc Btrfs: add mount ... |
1320 1321 1322 1323 |
if (newer_than) { if (newer_off == (u64)-1) break; |
e1f041e14 Btrfs: update to ... |
1324 1325 |
if (ret > 0) i += ret; |
4cb5300bc Btrfs: add mount ... |
1326 |
newer_off = max(newer_off + 1, |
09cbfeaf1 mm, fs: get rid o... |
1327 |
(u64)i << PAGE_SHIFT); |
4cb5300bc Btrfs: add mount ... |
1328 |
|
ee22184b5 Btrfs: use linux/... |
1329 1330 |
ret = find_new_extents(root, inode, newer_than, &newer_off, SZ_64K); |
4cb5300bc Btrfs: add mount ... |
1331 1332 |
if (!ret) { range->start = newer_off; |
09cbfeaf1 mm, fs: get rid o... |
1333 |
i = (newer_off & new_align) >> PAGE_SHIFT; |
4cb5300bc Btrfs: add mount ... |
1334 1335 |
} else { break; |
f46b5a66b Btrfs: split out ... |
1336 |
} |
4cb5300bc Btrfs: add mount ... |
1337 |
} else { |
008873eaf Btrfs: honor exte... |
1338 |
if (ret > 0) { |
cbcc83265 Btrfs: fix defrag... |
1339 |
i += ret; |
09cbfeaf1 mm, fs: get rid o... |
1340 |
last_len += ret << PAGE_SHIFT; |
008873eaf Btrfs: honor exte... |
1341 |
} else { |
cbcc83265 Btrfs: fix defrag... |
1342 |
i++; |
008873eaf Btrfs: honor exte... |
1343 1344 |
last_len = 0; } |
f46b5a66b Btrfs: split out ... |
1345 |
} |
f46b5a66b Btrfs: split out ... |
1346 |
} |
dec8ef905 Btrfs: correctly ... |
1347 |
if ((range->flags & BTRFS_DEFRAG_RANGE_START_IO)) { |
1e701a329 Btrfs: add new de... |
1348 |
filemap_flush(inode->i_mapping); |
dec8ef905 Btrfs: correctly ... |
1349 1350 1351 1352 |
if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT, &BTRFS_I(inode)->runtime_flags)) filemap_flush(inode->i_mapping); } |
1e701a329 Btrfs: add new de... |
1353 |
|
1e2ef46d8 btrfs: defrag: cl... |
1354 |
if (do_compress) { |
1e701a329 Btrfs: add new de... |
1355 1356 1357 1358 |
/* 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 */ |
0b246afa6 btrfs: root->fs_i... |
1359 1360 1361 1362 1363 1364 |
atomic_inc(&fs_info->async_submit_draining); while (atomic_read(&fs_info->nr_async_submits) || atomic_read(&fs_info->async_delalloc_pages)) { wait_event(fs_info->async_submit_wait, (atomic_read(&fs_info->nr_async_submits) == 0 && atomic_read(&fs_info->async_delalloc_pages) == 0)); |
1e701a329 Btrfs: add new de... |
1365 |
} |
0b246afa6 btrfs: root->fs_i... |
1366 |
atomic_dec(&fs_info->async_submit_draining); |
1e701a329 Btrfs: add new de... |
1367 |
} |
1a419d85a btrfs: Allow to s... |
1368 |
if (range->compress_type == BTRFS_COMPRESS_LZO) { |
0b246afa6 btrfs: root->fs_i... |
1369 |
btrfs_set_fs_incompat(fs_info, COMPRESS_LZO); |
5c1aab1dd btrfs: Add zstd s... |
1370 1371 |
} else if (range->compress_type == BTRFS_COMPRESS_ZSTD) { btrfs_set_fs_incompat(fs_info, COMPRESS_ZSTD); |
1a419d85a btrfs: Allow to s... |
1372 |
} |
60ccf82f5 btrfs: fix memory... |
1373 |
ret = defrag_count; |
940100a4a Btrfs: be more se... |
1374 |
|
4cb5300bc Btrfs: add mount ... |
1375 |
out_ra: |
1e2ef46d8 btrfs: defrag: cl... |
1376 |
if (do_compress) { |
5955102c9 wrappers for ->i_... |
1377 |
inode_lock(inode); |
eec63c65d btrfs: separate d... |
1378 |
BTRFS_I(inode)->defrag_compress = BTRFS_COMPRESS_NONE; |
5955102c9 wrappers for ->i_... |
1379 |
inode_unlock(inode); |
633085c79 Btrfs: reset forc... |
1380 |
} |
4cb5300bc Btrfs: add mount ... |
1381 1382 1383 |
if (!file) kfree(ra); kfree(pages); |
940100a4a Btrfs: be more se... |
1384 |
return ret; |
f46b5a66b Btrfs: split out ... |
1385 |
} |
198605a8e Btrfs: get write ... |
1386 |
static noinline int btrfs_ioctl_resize(struct file *file, |
76dda93c6 Btrfs: add snapsh... |
1387 |
void __user *arg) |
f46b5a66b Btrfs: split out ... |
1388 |
{ |
0b246afa6 btrfs: root->fs_i... |
1389 1390 |
struct inode *inode = file_inode(file); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); |
f46b5a66b Btrfs: split out ... |
1391 1392 1393 |
u64 new_size; u64 old_size; u64 devid = 1; |
0b246afa6 btrfs: root->fs_i... |
1394 |
struct btrfs_root *root = BTRFS_I(inode)->root; |
f46b5a66b Btrfs: split out ... |
1395 1396 1397 1398 |
struct btrfs_ioctl_vol_args *vol_args; struct btrfs_trans_handle *trans; struct btrfs_device *device = NULL; char *sizestr; |
9a40f1222 btrfs: filter inv... |
1399 |
char *retptr; |
f46b5a66b Btrfs: split out ... |
1400 1401 |
char *devstr = NULL; int ret = 0; |
f46b5a66b Btrfs: split out ... |
1402 |
int mod = 0; |
e441d54de Btrfs: add permis... |
1403 1404 |
if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
198605a8e Btrfs: get write ... |
1405 1406 1407 |
ret = mnt_want_write_file(file); if (ret) return ret; |
171938e52 btrfs: track excl... |
1408 |
if (test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)) { |
975476765 Btrfs: fix missin... |
1409 |
mnt_drop_write_file(file); |
e57138b3e btrfs: return btr... |
1410 |
return BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; |
c9e9f97bd Btrfs: add basic ... |
1411 |
} |
0b246afa6 btrfs: root->fs_i... |
1412 |
mutex_lock(&fs_info->volume_mutex); |
dae7b665c btrfs: use memdup... |
1413 |
vol_args = memdup_user(arg, sizeof(*vol_args)); |
c9e9f97bd Btrfs: add basic ... |
1414 1415 1416 1417 |
if (IS_ERR(vol_args)) { ret = PTR_ERR(vol_args); goto out; } |
5516e5957 Btrfs: Null termi... |
1418 1419 |
vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; |
f46b5a66b Btrfs: split out ... |
1420 |
|
f46b5a66b Btrfs: split out ... |
1421 1422 1423 |
sizestr = vol_args->name; devstr = strchr(sizestr, ':'); if (devstr) { |
f46b5a66b Btrfs: split out ... |
1424 1425 1426 |
sizestr = devstr + 1; *devstr = '\0'; devstr = vol_args->name; |
58dfae636 btrfs: replace si... |
1427 1428 1429 |
ret = kstrtoull(devstr, 10, &devid); if (ret) goto out_free; |
dfd79829b Btrfs: fix trivia... |
1430 1431 1432 1433 |
if (!devid) { ret = -EINVAL; goto out_free; } |
0b246afa6 btrfs: root->fs_i... |
1434 |
btrfs_info(fs_info, "resizing devid %llu", devid); |
f46b5a66b Btrfs: split out ... |
1435 |
} |
dba60f3f5 Btrfs: fix resize... |
1436 |
|
0b246afa6 btrfs: root->fs_i... |
1437 |
device = btrfs_find_device(fs_info, devid, NULL, NULL); |
f46b5a66b Btrfs: split out ... |
1438 |
if (!device) { |
0b246afa6 btrfs: root->fs_i... |
1439 1440 |
btrfs_info(fs_info, "resizer unable to find device %llu", devid); |
dfd79829b Btrfs: fix trivia... |
1441 |
ret = -ENODEV; |
c9e9f97bd Btrfs: add basic ... |
1442 |
goto out_free; |
f46b5a66b Btrfs: split out ... |
1443 |
} |
dba60f3f5 Btrfs: fix resize... |
1444 1445 |
if (!device->writeable) { |
0b246afa6 btrfs: root->fs_i... |
1446 |
btrfs_info(fs_info, |
efe120a06 Btrfs: convert pr... |
1447 |
"resizer unable to apply on readonly device %llu", |
c1c9ff7c9 Btrfs: Remove sup... |
1448 |
devid); |
dfd79829b Btrfs: fix trivia... |
1449 |
ret = -EPERM; |
4e42ae1bd Btrfs: do not res... |
1450 1451 |
goto out_free; } |
f46b5a66b Btrfs: split out ... |
1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 |
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++; } |
9a40f1222 btrfs: filter inv... |
1462 1463 |
new_size = memparse(sizestr, &retptr); if (*retptr != '\0' || new_size == 0) { |
f46b5a66b Btrfs: split out ... |
1464 |
ret = -EINVAL; |
c9e9f97bd Btrfs: add basic ... |
1465 |
goto out_free; |
f46b5a66b Btrfs: split out ... |
1466 1467 |
} } |
63a212abc Btrfs: disallow s... |
1468 |
if (device->is_tgtdev_for_dev_replace) { |
dfd79829b Btrfs: fix trivia... |
1469 |
ret = -EPERM; |
63a212abc Btrfs: disallow s... |
1470 1471 |
goto out_free; } |
7cc8e58d5 Btrfs: fix unprot... |
1472 |
old_size = btrfs_device_get_total_bytes(device); |
f46b5a66b Btrfs: split out ... |
1473 1474 1475 1476 |
if (mod < 0) { if (new_size > old_size) { ret = -EINVAL; |
c9e9f97bd Btrfs: add basic ... |
1477 |
goto out_free; |
f46b5a66b Btrfs: split out ... |
1478 1479 1480 |
} new_size = old_size - new_size; } else if (mod > 0) { |
eb8052e01 fs/btrfs: Integer... |
1481 |
if (new_size > ULLONG_MAX - old_size) { |
902c68a4d btrfs: replace EI... |
1482 |
ret = -ERANGE; |
eb8052e01 fs/btrfs: Integer... |
1483 1484 |
goto out_free; } |
f46b5a66b Btrfs: split out ... |
1485 1486 |
new_size = old_size + new_size; } |
ee22184b5 Btrfs: use linux/... |
1487 |
if (new_size < SZ_256M) { |
f46b5a66b Btrfs: split out ... |
1488 |
ret = -EINVAL; |
c9e9f97bd Btrfs: add basic ... |
1489 |
goto out_free; |
f46b5a66b Btrfs: split out ... |
1490 1491 1492 |
} if (new_size > device->bdev->bd_inode->i_size) { ret = -EFBIG; |
c9e9f97bd Btrfs: add basic ... |
1493 |
goto out_free; |
f46b5a66b Btrfs: split out ... |
1494 |
} |
47f08b969 btrfs: Use explic... |
1495 |
new_size = round_down(new_size, fs_info->sectorsize); |
f46b5a66b Btrfs: split out ... |
1496 |
|
0b246afa6 btrfs: root->fs_i... |
1497 1498 |
btrfs_info_in_rcu(fs_info, "new size for %s is %llu", rcu_str_deref(device->name), new_size); |
f46b5a66b Btrfs: split out ... |
1499 1500 |
if (new_size > old_size) { |
a22285a6a Btrfs: Integrate ... |
1501 |
trans = btrfs_start_transaction(root, 0); |
98d5dc13e btrfs: fix return... |
1502 1503 |
if (IS_ERR(trans)) { ret = PTR_ERR(trans); |
c9e9f97bd Btrfs: add basic ... |
1504 |
goto out_free; |
98d5dc13e btrfs: fix return... |
1505 |
} |
f46b5a66b Btrfs: split out ... |
1506 |
ret = btrfs_grow_device(trans, device, new_size); |
3a45bb207 btrfs: remove roo... |
1507 |
btrfs_commit_transaction(trans); |
ece7d20e8 Btrfs: Don't erro... |
1508 |
} else if (new_size < old_size) { |
f46b5a66b Btrfs: split out ... |
1509 |
ret = btrfs_shrink_device(device, new_size); |
0253f40ef Btrfs: Remove the... |
1510 |
} /* equal, nothing need to do */ |
f46b5a66b Btrfs: split out ... |
1511 |
|
c9e9f97bd Btrfs: add basic ... |
1512 |
out_free: |
f46b5a66b Btrfs: split out ... |
1513 |
kfree(vol_args); |
c9e9f97bd Btrfs: add basic ... |
1514 |
out: |
0b246afa6 btrfs: root->fs_i... |
1515 |
mutex_unlock(&fs_info->volume_mutex); |
171938e52 btrfs: track excl... |
1516 |
clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags); |
18f39c416 Btrfs: fix unlock... |
1517 |
mnt_drop_write_file(file); |
f46b5a66b Btrfs: split out ... |
1518 1519 |
return ret; } |
72fd032e9 Btrfs: add SNAP_C... |
1520 |
static noinline int btrfs_ioctl_snap_create_transid(struct file *file, |
52f75f4fe btrfs: constify n... |
1521 |
const char *name, unsigned long fd, int subvol, |
6f72c7e20 Btrfs: add qgroup... |
1522 |
u64 *transid, bool readonly, |
8696c5330 Btrfs: fix memory... |
1523 |
struct btrfs_qgroup_inherit *inherit) |
f46b5a66b Btrfs: split out ... |
1524 |
{ |
f46b5a66b Btrfs: split out ... |
1525 |
int namelen; |
3de4586c5 Btrfs: Allow subv... |
1526 |
int ret = 0; |
f46b5a66b Btrfs: split out ... |
1527 |
|
325c50e3c btrfs: ensure tha... |
1528 1529 |
if (!S_ISDIR(file_inode(file)->i_mode)) return -ENOTDIR; |
a874a63e1 Btrfs: check writ... |
1530 1531 1532 |
ret = mnt_want_write_file(file); if (ret) goto out; |
72fd032e9 Btrfs: add SNAP_C... |
1533 1534 |
namelen = strlen(name); if (strchr(name, '/')) { |
f46b5a66b Btrfs: split out ... |
1535 |
ret = -EINVAL; |
a874a63e1 Btrfs: check writ... |
1536 |
goto out_drop_write; |
f46b5a66b Btrfs: split out ... |
1537 |
} |
16780cabb Btrfs: add extra ... |
1538 1539 1540 |
if (name[0] == '.' && (namelen == 1 || (name[1] == '.' && namelen == 2))) { ret = -EEXIST; |
a874a63e1 Btrfs: check writ... |
1541 |
goto out_drop_write; |
16780cabb Btrfs: add extra ... |
1542 |
} |
3de4586c5 Btrfs: Allow subv... |
1543 |
if (subvol) { |
72fd032e9 Btrfs: add SNAP_C... |
1544 |
ret = btrfs_mksubvol(&file->f_path, name, namelen, |
6f72c7e20 Btrfs: add qgroup... |
1545 |
NULL, transid, readonly, inherit); |
cb8e70901 Btrfs: Fix subvol... |
1546 |
} else { |
2903ff019 switch simple cas... |
1547 |
struct fd src = fdget(fd); |
3de4586c5 Btrfs: Allow subv... |
1548 |
struct inode *src_inode; |
2903ff019 switch simple cas... |
1549 |
if (!src.file) { |
3de4586c5 Btrfs: Allow subv... |
1550 |
ret = -EINVAL; |
a874a63e1 Btrfs: check writ... |
1551 |
goto out_drop_write; |
3de4586c5 Btrfs: Allow subv... |
1552 |
} |
496ad9aa8 new helper: file_... |
1553 1554 |
src_inode = file_inode(src.file); if (src_inode->i_sb != file_inode(file)->i_sb) { |
c79b47133 Btrfs: don't use ... |
1555 |
btrfs_info(BTRFS_I(file_inode(file))->root->fs_info, |
efe120a06 Btrfs: convert pr... |
1556 |
"Snapshot src from another FS"); |
23ad5b17d btrfs: Return EXD... |
1557 |
ret = -EXDEV; |
d02420613 btrfs: restrict s... |
1558 1559 1560 1561 1562 1563 |
} else if (!inode_owner_or_capable(src_inode)) { /* * Subvolume creation is not restricted, but snapshots * are limited to own subvolumes only */ ret = -EPERM; |
ecd188159 switch btrfs_ioct... |
1564 1565 1566 1567 |
} else { ret = btrfs_mksubvol(&file->f_path, name, namelen, BTRFS_I(src_inode)->root, transid, readonly, inherit); |
3de4586c5 Btrfs: Allow subv... |
1568 |
} |
2903ff019 switch simple cas... |
1569 |
fdput(src); |
cb8e70901 Btrfs: Fix subvol... |
1570 |
} |
a874a63e1 Btrfs: check writ... |
1571 1572 |
out_drop_write: mnt_drop_write_file(file); |
f46b5a66b Btrfs: split out ... |
1573 |
out: |
72fd032e9 Btrfs: add SNAP_C... |
1574 1575 1576 1577 |
return ret; } static noinline int btrfs_ioctl_snap_create(struct file *file, |
fa0d2b9bd Btrfs: Refactor b... |
1578 |
void __user *arg, int subvol) |
72fd032e9 Btrfs: add SNAP_C... |
1579 |
{ |
fa0d2b9bd Btrfs: Refactor b... |
1580 |
struct btrfs_ioctl_vol_args *vol_args; |
72fd032e9 Btrfs: add SNAP_C... |
1581 |
int ret; |
325c50e3c btrfs: ensure tha... |
1582 1583 |
if (!S_ISDIR(file_inode(file)->i_mode)) return -ENOTDIR; |
fa0d2b9bd Btrfs: Refactor b... |
1584 1585 1586 1587 |
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... |
1588 |
|
fa0d2b9bd Btrfs: Refactor b... |
1589 |
ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, |
b83cc9693 Btrfs: Add readon... |
1590 |
vol_args->fd, subvol, |
6f72c7e20 Btrfs: add qgroup... |
1591 |
NULL, false, NULL); |
fdfb1e4f6 Btrfs: Make async... |
1592 |
|
fa0d2b9bd Btrfs: Refactor b... |
1593 1594 1595 |
kfree(vol_args); return ret; } |
fdfb1e4f6 Btrfs: Make async... |
1596 |
|
fa0d2b9bd Btrfs: Refactor b... |
1597 1598 1599 1600 1601 1602 1603 |
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... |
1604 |
bool readonly = false; |
6f72c7e20 Btrfs: add qgroup... |
1605 |
struct btrfs_qgroup_inherit *inherit = NULL; |
75eaa0e22 Btrfs: fix sync s... |
1606 |
|
325c50e3c btrfs: ensure tha... |
1607 1608 |
if (!S_ISDIR(file_inode(file)->i_mode)) return -ENOTDIR; |
fa0d2b9bd Btrfs: Refactor b... |
1609 1610 1611 1612 |
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... |
1613 |
|
b83cc9693 Btrfs: Add readon... |
1614 |
if (vol_args->flags & |
6f72c7e20 Btrfs: add qgroup... |
1615 1616 |
~(BTRFS_SUBVOL_CREATE_ASYNC | BTRFS_SUBVOL_RDONLY | BTRFS_SUBVOL_QGROUP_INHERIT)) { |
b83cc9693 Btrfs: Add readon... |
1617 |
ret = -EOPNOTSUPP; |
c47ca32d3 Btrfs: kfree()ing... |
1618 |
goto free_args; |
72fd032e9 Btrfs: add SNAP_C... |
1619 |
} |
fa0d2b9bd Btrfs: Refactor b... |
1620 1621 1622 |
if (vol_args->flags & BTRFS_SUBVOL_CREATE_ASYNC) ptr = &transid; |
b83cc9693 Btrfs: Add readon... |
1623 1624 |
if (vol_args->flags & BTRFS_SUBVOL_RDONLY) readonly = true; |
6f72c7e20 Btrfs: add qgroup... |
1625 |
if (vol_args->flags & BTRFS_SUBVOL_QGROUP_INHERIT) { |
09cbfeaf1 mm, fs: get rid o... |
1626 |
if (vol_args->size > PAGE_SIZE) { |
6f72c7e20 Btrfs: add qgroup... |
1627 |
ret = -EINVAL; |
c47ca32d3 Btrfs: kfree()ing... |
1628 |
goto free_args; |
6f72c7e20 Btrfs: add qgroup... |
1629 1630 1631 1632 |
} inherit = memdup_user(vol_args->qgroup_inherit, vol_args->size); if (IS_ERR(inherit)) { ret = PTR_ERR(inherit); |
c47ca32d3 Btrfs: kfree()ing... |
1633 |
goto free_args; |
6f72c7e20 Btrfs: add qgroup... |
1634 1635 |
} } |
fa0d2b9bd Btrfs: Refactor b... |
1636 1637 |
ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, |
6f72c7e20 Btrfs: add qgroup... |
1638 |
vol_args->fd, subvol, ptr, |
8696c5330 Btrfs: fix memory... |
1639 |
readonly, inherit); |
c47ca32d3 Btrfs: kfree()ing... |
1640 1641 |
if (ret) goto free_inherit; |
fa0d2b9bd Btrfs: Refactor b... |
1642 |
|
c47ca32d3 Btrfs: kfree()ing... |
1643 1644 1645 1646 |
if (ptr && copy_to_user(arg + offsetof(struct btrfs_ioctl_vol_args_v2, transid), ptr, sizeof(*ptr))) |
fa0d2b9bd Btrfs: Refactor b... |
1647 |
ret = -EFAULT; |
c47ca32d3 Btrfs: kfree()ing... |
1648 1649 |
free_inherit: |
6f72c7e20 Btrfs: add qgroup... |
1650 |
kfree(inherit); |
c47ca32d3 Btrfs: kfree()ing... |
1651 1652 |
free_args: kfree(vol_args); |
f46b5a66b Btrfs: split out ... |
1653 1654 |
return ret; } |
0caa102da Btrfs: Add BTRFS_... |
1655 1656 1657 |
static noinline int btrfs_ioctl_subvol_getflags(struct file *file, void __user *arg) { |
496ad9aa8 new helper: file_... |
1658 |
struct inode *inode = file_inode(file); |
0b246afa6 btrfs: root->fs_i... |
1659 |
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); |
0caa102da Btrfs: Add BTRFS_... |
1660 1661 1662 |
struct btrfs_root *root = BTRFS_I(inode)->root; int ret = 0; u64 flags = 0; |
4a0cc7ca6 btrfs: Make btrfs... |
1663 |
if (btrfs_ino(BTRFS_I(inode)) != BTRFS_FIRST_FREE_OBJECTID) |
0caa102da Btrfs: Add BTRFS_... |
1664 |
return -EINVAL; |
0b246afa6 btrfs: root->fs_i... |
1665 |
down_read(&fs_info->subvol_sem); |
0caa102da Btrfs: Add BTRFS_... |
1666 1667 |
if (btrfs_root_readonly(root)) flags |= BTRFS_SUBVOL_RDONLY; |
0b246afa6 btrfs: root->fs_i... |
1668 |
up_read(&fs_info->subvol_sem); |
0caa102da Btrfs: Add BTRFS_... |
1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 |
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) { |
496ad9aa8 new helper: file_... |
1679 |
struct inode *inode = file_inode(file); |
0b246afa6 btrfs: root->fs_i... |
1680 |
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); |
0caa102da Btrfs: Add BTRFS_... |
1681 1682 1683 1684 1685 |
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_trans_handle *trans; u64 root_flags; u64 flags; int ret = 0; |
bd60ea0fe btrfs: call permi... |
1686 1687 |
if (!inode_owner_or_capable(inode)) return -EPERM; |
b9ca0664d Btrfs: do not set... |
1688 1689 1690 |
ret = mnt_want_write_file(file); if (ret) goto out; |
0caa102da Btrfs: Add BTRFS_... |
1691 |
|
4a0cc7ca6 btrfs: Make btrfs... |
1692 |
if (btrfs_ino(BTRFS_I(inode)) != BTRFS_FIRST_FREE_OBJECTID) { |
b9ca0664d Btrfs: do not set... |
1693 1694 1695 |
ret = -EINVAL; goto out_drop_write; } |
0caa102da Btrfs: Add BTRFS_... |
1696 |
|
b9ca0664d Btrfs: do not set... |
1697 1698 1699 1700 |
if (copy_from_user(&flags, arg, sizeof(flags))) { ret = -EFAULT; goto out_drop_write; } |
0caa102da Btrfs: Add BTRFS_... |
1701 |
|
b9ca0664d Btrfs: do not set... |
1702 1703 1704 1705 |
if (flags & BTRFS_SUBVOL_CREATE_ASYNC) { ret = -EINVAL; goto out_drop_write; } |
0caa102da Btrfs: Add BTRFS_... |
1706 |
|
b9ca0664d Btrfs: do not set... |
1707 1708 1709 1710 |
if (flags & ~BTRFS_SUBVOL_RDONLY) { ret = -EOPNOTSUPP; goto out_drop_write; } |
0caa102da Btrfs: Add BTRFS_... |
1711 |
|
0b246afa6 btrfs: root->fs_i... |
1712 |
down_write(&fs_info->subvol_sem); |
0caa102da Btrfs: Add BTRFS_... |
1713 1714 1715 |
/* nothing to do */ if (!!(flags & BTRFS_SUBVOL_RDONLY) == btrfs_root_readonly(root)) |
b9ca0664d Btrfs: do not set... |
1716 |
goto out_drop_sem; |
0caa102da Btrfs: Add BTRFS_... |
1717 1718 |
root_flags = btrfs_root_flags(&root->root_item); |
2c6865378 btrfs: Check read... |
1719 |
if (flags & BTRFS_SUBVOL_RDONLY) { |
0caa102da Btrfs: Add BTRFS_... |
1720 1721 |
btrfs_set_root_flags(&root->root_item, root_flags | BTRFS_ROOT_SUBVOL_RDONLY); |
2c6865378 btrfs: Check read... |
1722 1723 1724 1725 1726 1727 1728 1729 |
} else { /* * Block RO -> RW transition if this subvolume is involved in * send */ spin_lock(&root->root_item_lock); if (root->send_in_progress == 0) { btrfs_set_root_flags(&root->root_item, |
0caa102da Btrfs: Add BTRFS_... |
1730 |
root_flags & ~BTRFS_ROOT_SUBVOL_RDONLY); |
2c6865378 btrfs: Check read... |
1731 1732 1733 |
spin_unlock(&root->root_item_lock); } else { spin_unlock(&root->root_item_lock); |
0b246afa6 btrfs: root->fs_i... |
1734 1735 1736 |
btrfs_warn(fs_info, "Attempt to set subvolume %llu read-write during send", root->root_key.objectid); |
2c6865378 btrfs: Check read... |
1737 1738 1739 1740 |
ret = -EPERM; goto out_drop_sem; } } |
0caa102da Btrfs: Add BTRFS_... |
1741 1742 1743 1744 1745 1746 |
trans = btrfs_start_transaction(root, 1); if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto out_reset; } |
0b246afa6 btrfs: root->fs_i... |
1747 |
ret = btrfs_update_root(trans, fs_info->tree_root, |
0caa102da Btrfs: Add BTRFS_... |
1748 |
&root->root_key, &root->root_item); |
9e87c49d6 btrfs: Explicitly... |
1749 1750 1751 1752 1753 1754 |
if (ret < 0) { btrfs_end_transaction(trans); goto out_reset; } ret = btrfs_commit_transaction(trans); |
0caa102da Btrfs: Add BTRFS_... |
1755 |
|
0caa102da Btrfs: Add BTRFS_... |
1756 1757 1758 |
out_reset: if (ret) btrfs_set_root_flags(&root->root_item, root_flags); |
b9ca0664d Btrfs: do not set... |
1759 |
out_drop_sem: |
0b246afa6 btrfs: root->fs_i... |
1760 |
up_write(&fs_info->subvol_sem); |
b9ca0664d Btrfs: do not set... |
1761 1762 1763 |
out_drop_write: mnt_drop_write_file(file); out: |
0caa102da Btrfs: Add BTRFS_... |
1764 1765 |
return ret; } |
76dda93c6 Btrfs: add snapsh... |
1766 1767 1768 1769 1770 |
/* * helper to check if the subvolume references other subvolumes */ static noinline int may_destroy_subvol(struct btrfs_root *root) { |
0b246afa6 btrfs: root->fs_i... |
1771 |
struct btrfs_fs_info *fs_info = root->fs_info; |
76dda93c6 Btrfs: add snapsh... |
1772 |
struct btrfs_path *path; |
175a2b871 Btrfs: don't allo... |
1773 |
struct btrfs_dir_item *di; |
76dda93c6 Btrfs: add snapsh... |
1774 |
struct btrfs_key key; |
175a2b871 Btrfs: don't allo... |
1775 |
u64 dir_id; |
76dda93c6 Btrfs: add snapsh... |
1776 1777 1778 1779 1780 |
int ret; path = btrfs_alloc_path(); if (!path) return -ENOMEM; |
175a2b871 Btrfs: don't allo... |
1781 |
/* Make sure this root isn't set as the default subvol */ |
0b246afa6 btrfs: root->fs_i... |
1782 1783 |
dir_id = btrfs_super_root_dir(fs_info->super_copy); di = btrfs_lookup_dir_item(NULL, fs_info->tree_root, path, |
175a2b871 Btrfs: don't allo... |
1784 1785 1786 1787 |
dir_id, "default", 7, 0); if (di && !IS_ERR(di)) { btrfs_dir_item_key_to_cpu(path->nodes[0], di, &key); if (key.objectid == root->root_key.objectid) { |
72de6b539 Btrfs: return EPE... |
1788 |
ret = -EPERM; |
0b246afa6 btrfs: root->fs_i... |
1789 |
btrfs_err(fs_info, |
5d163e0e6 btrfs: unsplit pr... |
1790 1791 |
"deleting default subvolume %llu is not allowed", key.objectid); |
175a2b871 Btrfs: don't allo... |
1792 1793 1794 1795 |
goto out; } btrfs_release_path(path); } |
76dda93c6 Btrfs: add snapsh... |
1796 1797 1798 |
key.objectid = root->root_key.objectid; key.type = BTRFS_ROOT_REF_KEY; key.offset = (u64)-1; |
0b246afa6 btrfs: root->fs_i... |
1799 |
ret = btrfs_search_slot(NULL, fs_info->tree_root, &key, path, 0, 0); |
76dda93c6 Btrfs: add snapsh... |
1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 |
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... |
1816 1817 1818 |
static noinline int key_in_sk(struct btrfs_key *key, struct btrfs_ioctl_search_key *sk) { |
abc6e1341 Btrfs: fix key ch... |
1819 1820 1821 1822 1823 1824 1825 1826 1827 |
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... |
1828 |
return 0; |
abc6e1341 Btrfs: fix key ch... |
1829 1830 1831 1832 1833 1834 1835 |
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... |
1836 1837 1838 |
return 0; return 1; } |
df3975652 btrfs: copy_to_sk... |
1839 |
static noinline int copy_to_sk(struct btrfs_path *path, |
ac8e9819d Btrfs: add search... |
1840 1841 |
struct btrfs_key *key, struct btrfs_ioctl_search_key *sk, |
9b6e817d0 btrfs: tree_searc... |
1842 |
size_t *buf_size, |
ba346b357 btrfs: tree_searc... |
1843 |
char __user *ubuf, |
ac8e9819d Btrfs: add search... |
1844 1845 1846 1847 1848 1849 |
unsigned long *sk_offset, int *num_found) { u64 found_transid; struct extent_buffer *leaf; struct btrfs_ioctl_search_header sh; |
dd81d459a btrfs: fix search... |
1850 |
struct btrfs_key test; |
ac8e9819d Btrfs: add search... |
1851 1852 1853 1854 1855 |
unsigned long item_off; unsigned long item_len; int nritems; int i; int slot; |
ac8e9819d Btrfs: add search... |
1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 |
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); |
03b71c6ca btrfs: don't stop... |
1871 1872 1873 |
btrfs_item_key_to_cpu(leaf, key, i); if (!key_in_sk(key, sk)) continue; |
9b6e817d0 btrfs: tree_searc... |
1874 |
if (sizeof(sh) + item_len > *buf_size) { |
8f5f6178f btrfs: tree_searc... |
1875 1876 1877 1878 1879 1880 1881 1882 1883 |
if (*num_found) { ret = 1; goto out; } /* * return one empty item back for v1, which does not * handle -EOVERFLOW */ |
9b6e817d0 btrfs: tree_searc... |
1884 |
*buf_size = sizeof(sh) + item_len; |
ac8e9819d Btrfs: add search... |
1885 |
item_len = 0; |
8f5f6178f btrfs: tree_searc... |
1886 1887 |
ret = -EOVERFLOW; } |
ac8e9819d Btrfs: add search... |
1888 |
|
9b6e817d0 btrfs: tree_searc... |
1889 |
if (sizeof(sh) + item_len + *sk_offset > *buf_size) { |
ac8e9819d Btrfs: add search... |
1890 |
ret = 1; |
25c9bc2e2 btrfs: tree_searc... |
1891 |
goto out; |
ac8e9819d Btrfs: add search... |
1892 |
} |
ac8e9819d Btrfs: add search... |
1893 1894 1895 1896 1897 1898 1899 |
sh.objectid = key->objectid; sh.offset = key->offset; sh.type = key->type; sh.len = item_len; sh.transid = found_transid; /* copy search result header */ |
ba346b357 btrfs: tree_searc... |
1900 1901 1902 1903 |
if (copy_to_user(ubuf + *sk_offset, &sh, sizeof(sh))) { ret = -EFAULT; goto out; } |
ac8e9819d Btrfs: add search... |
1904 1905 1906 |
*sk_offset += sizeof(sh); if (item_len) { |
ba346b357 btrfs: tree_searc... |
1907 |
char __user *up = ubuf + *sk_offset; |
ac8e9819d Btrfs: add search... |
1908 |
/* copy the item */ |
ba346b357 btrfs: tree_searc... |
1909 1910 1911 1912 1913 |
if (read_extent_buffer_to_user(leaf, up, item_off, item_len)) { ret = -EFAULT; goto out; } |
ac8e9819d Btrfs: add search... |
1914 |
*sk_offset += item_len; |
ac8e9819d Btrfs: add search... |
1915 |
} |
e21568671 btrfs: Ensure the... |
1916 |
(*num_found)++; |
ac8e9819d Btrfs: add search... |
1917 |
|
8f5f6178f btrfs: tree_searc... |
1918 1919 |
if (ret) /* -EOVERFLOW from above */ goto out; |
25c9bc2e2 btrfs: tree_searc... |
1920 1921 1922 1923 |
if (*num_found >= sk->nr_items) { ret = 1; goto out; } |
ac8e9819d Btrfs: add search... |
1924 1925 |
} advance_key: |
abc6e1341 Btrfs: fix key ch... |
1926 |
ret = 0; |
dd81d459a btrfs: fix search... |
1927 1928 1929 1930 1931 1932 |
test.objectid = sk->max_objectid; test.type = sk->max_type; test.offset = sk->max_offset; if (btrfs_comp_cpu_keys(key, &test) >= 0) ret = 1; else if (key->offset < (u64)-1) |
ac8e9819d Btrfs: add search... |
1933 |
key->offset++; |
dd81d459a btrfs: fix search... |
1934 |
else if (key->type < (u8)-1) { |
abc6e1341 Btrfs: fix key ch... |
1935 |
key->offset = 0; |
ac8e9819d Btrfs: add search... |
1936 |
key->type++; |
dd81d459a btrfs: fix search... |
1937 |
} else if (key->objectid < (u64)-1) { |
abc6e1341 Btrfs: fix key ch... |
1938 1939 |
key->offset = 0; key->type = 0; |
ac8e9819d Btrfs: add search... |
1940 |
key->objectid++; |
abc6e1341 Btrfs: fix key ch... |
1941 1942 |
} else ret = 1; |
25c9bc2e2 btrfs: tree_searc... |
1943 |
out: |
ba346b357 btrfs: tree_searc... |
1944 1945 1946 1947 1948 1949 1950 1951 1952 |
/* * 0: all items from this leaf copied, continue with next * 1: * more items can be copied, but unused buffer is too small * * all items were found * Either way, it will stops the loop which iterates to the next * leaf * -EOVERFLOW: item was to large for buffer * -EFAULT: could not copy extent buffer back to userspace */ |
ac8e9819d Btrfs: add search... |
1953 1954 1955 1956 |
return ret; } static noinline int search_ioctl(struct inode *inode, |
125444428 btrfs: tree_searc... |
1957 |
struct btrfs_ioctl_search_key *sk, |
9b6e817d0 btrfs: tree_searc... |
1958 |
size_t *buf_size, |
ba346b357 btrfs: tree_searc... |
1959 |
char __user *ubuf) |
ac8e9819d Btrfs: add search... |
1960 |
{ |
0b246afa6 btrfs: root->fs_i... |
1961 |
struct btrfs_fs_info *info = btrfs_sb(inode->i_sb); |
ac8e9819d Btrfs: add search... |
1962 1963 |
struct btrfs_root *root; struct btrfs_key key; |
ac8e9819d Btrfs: add search... |
1964 |
struct btrfs_path *path; |
ac8e9819d Btrfs: add search... |
1965 1966 1967 |
int ret; int num_found = 0; unsigned long sk_offset = 0; |
9b6e817d0 btrfs: tree_searc... |
1968 1969 |
if (*buf_size < sizeof(struct btrfs_ioctl_search_header)) { *buf_size = sizeof(struct btrfs_ioctl_search_header); |
125444428 btrfs: tree_searc... |
1970 |
return -EOVERFLOW; |
9b6e817d0 btrfs: tree_searc... |
1971 |
} |
125444428 btrfs: tree_searc... |
1972 |
|
ac8e9819d Btrfs: add search... |
1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 |
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)) { |
ac8e9819d Btrfs: add search... |
1986 1987 1988 1989 1990 1991 1992 1993 |
btrfs_free_path(path); return -ENOENT; } } key.objectid = sk->min_objectid; key.type = sk->min_type; key.offset = sk->min_offset; |
678712545 btrfs: Fix checkp... |
1994 |
while (1) { |
6174d3cb4 Btrfs: remove unu... |
1995 |
ret = btrfs_search_forward(root, &key, path, sk->min_transid); |
ac8e9819d Btrfs: add search... |
1996 1997 1998 1999 2000 |
if (ret != 0) { if (ret > 0) ret = 0; goto err; } |
df3975652 btrfs: copy_to_sk... |
2001 |
ret = copy_to_sk(path, &key, sk, buf_size, ubuf, |
ac8e9819d Btrfs: add search... |
2002 |
&sk_offset, &num_found); |
b3b4aa74b btrfs: drop unuse... |
2003 |
btrfs_release_path(path); |
25c9bc2e2 btrfs: tree_searc... |
2004 |
if (ret) |
ac8e9819d Btrfs: add search... |
2005 2006 2007 |
break; } |
8f5f6178f btrfs: tree_searc... |
2008 2009 |
if (ret > 0) ret = 0; |
ac8e9819d Btrfs: add search... |
2010 2011 2012 2013 2014 2015 2016 2017 2018 |
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) { |
ba346b357 btrfs: tree_searc... |
2019 2020 |
struct btrfs_ioctl_search_args __user *uargs; struct btrfs_ioctl_search_key sk; |
9b6e817d0 btrfs: tree_searc... |
2021 2022 2023 |
struct inode *inode; int ret; size_t buf_size; |
ac8e9819d Btrfs: add search... |
2024 2025 2026 |
if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
ba346b357 btrfs: tree_searc... |
2027 2028 2029 2030 |
uargs = (struct btrfs_ioctl_search_args __user *)argp; if (copy_from_user(&sk, &uargs->key, sizeof(sk))) return -EFAULT; |
ac8e9819d Btrfs: add search... |
2031 |
|
ba346b357 btrfs: tree_searc... |
2032 |
buf_size = sizeof(uargs->buf); |
ac8e9819d Btrfs: add search... |
2033 |
|
496ad9aa8 new helper: file_... |
2034 |
inode = file_inode(file); |
ba346b357 btrfs: tree_searc... |
2035 |
ret = search_ioctl(inode, &sk, &buf_size, uargs->buf); |
8f5f6178f btrfs: tree_searc... |
2036 2037 2038 2039 2040 2041 2042 |
/* * In the origin implementation an overflow is handled by returning a * search header with a len of zero, so reset ret. */ if (ret == -EOVERFLOW) ret = 0; |
ba346b357 btrfs: tree_searc... |
2043 |
if (ret == 0 && copy_to_user(&uargs->key, &sk, sizeof(sk))) |
ac8e9819d Btrfs: add search... |
2044 |
ret = -EFAULT; |
ac8e9819d Btrfs: add search... |
2045 2046 |
return ret; } |
cc68a8a5a btrfs: new ioctl ... |
2047 2048 2049 2050 2051 2052 2053 2054 |
static noinline int btrfs_ioctl_tree_search_v2(struct file *file, void __user *argp) { struct btrfs_ioctl_search_args_v2 __user *uarg; struct btrfs_ioctl_search_args_v2 args; struct inode *inode; int ret; size_t buf_size; |
ee22184b5 Btrfs: use linux/... |
2055 |
const size_t buf_limit = SZ_16M; |
cc68a8a5a btrfs: new ioctl ... |
2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 |
if (!capable(CAP_SYS_ADMIN)) return -EPERM; /* copy search header and buffer size */ uarg = (struct btrfs_ioctl_search_args_v2 __user *)argp; if (copy_from_user(&args, uarg, sizeof(args))) return -EFAULT; buf_size = args.buf_size; |
cc68a8a5a btrfs: new ioctl ... |
2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 |
/* limit result size to 16MB */ if (buf_size > buf_limit) buf_size = buf_limit; inode = file_inode(file); ret = search_ioctl(inode, &args.key, &buf_size, (char *)(&uarg->buf[0])); if (ret == 0 && copy_to_user(&uarg->key, &args.key, sizeof(args.key))) ret = -EFAULT; else if (ret == -EOVERFLOW && copy_to_user(&uarg->buf_size, &buf_size, sizeof(buf_size))) ret = -EFAULT; |
ac8e9819d Btrfs: add search... |
2078 2079 |
return ret; } |
98d377a08 Btrfs: add a func... |
2080 |
/* |
ac8e9819d Btrfs: add search... |
2081 2082 2083 |
* 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... |
2084 2085 2086 2087 2088 |
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... |
2089 |
char *ptr; |
98d377a08 Btrfs: add a func... |
2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 |
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; |
90b0805d6 btrfs: Fix possib... |
2106 |
ptr = &name[BTRFS_INO_LOOKUP_PATH_MAX - 1]; |
98d377a08 Btrfs: add a func... |
2107 2108 2109 2110 2111 2112 |
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)) { |
f14d104db btrfs: switch mor... |
2113 |
btrfs_err(info, "could not find root %llu", tree_id); |
8ad6fcab5 Btrfs: fix the in... |
2114 2115 |
ret = -ENOENT; goto out; |
98d377a08 Btrfs: add a func... |
2116 2117 2118 2119 |
} key.objectid = dirid; key.type = BTRFS_INODE_REF_KEY; |
8ad6fcab5 Btrfs: fix the in... |
2120 |
key.offset = (u64)-1; |
98d377a08 Btrfs: add a func... |
2121 |
|
678712545 btrfs: Fix checkp... |
2122 |
while (1) { |
98d377a08 Btrfs: add a func... |
2123 2124 2125 |
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto out; |
18674c6cc Btrfs: don't miss... |
2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 |
else if (ret > 0) { ret = btrfs_previous_item(root, path, dirid, BTRFS_INODE_REF_KEY); if (ret < 0) goto out; else if (ret > 0) { ret = -ENOENT; goto out; } } |
98d377a08 Btrfs: add a func... |
2136 2137 2138 2139 |
l = path->nodes[0]; slot = path->slots[0]; btrfs_item_key_to_cpu(l, &key, slot); |
98d377a08 Btrfs: add a func... |
2140 2141 2142 2143 |
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; |
a696cf352 Btrfs: add missin... |
2144 2145 |
if (ptr < name) { ret = -ENAMETOOLONG; |
98d377a08 Btrfs: add a func... |
2146 |
goto out; |
a696cf352 Btrfs: add missin... |
2147 |
} |
98d377a08 Btrfs: add a func... |
2148 2149 |
*(ptr + len) = '/'; |
678712545 btrfs: Fix checkp... |
2150 |
read_extent_buffer(l, ptr, (unsigned long)(iref + 1), len); |
98d377a08 Btrfs: add a func... |
2151 2152 2153 |
if (key.offset == BTRFS_FIRST_FREE_OBJECTID) break; |
b3b4aa74b btrfs: drop unuse... |
2154 |
btrfs_release_path(path); |
98d377a08 Btrfs: add a func... |
2155 |
key.objectid = key.offset; |
8ad6fcab5 Btrfs: fix the in... |
2156 |
key.offset = (u64)-1; |
98d377a08 Btrfs: add a func... |
2157 |
dirid = key.objectid; |
98d377a08 Btrfs: add a func... |
2158 |
} |
77906a507 Btrfs: copy strin... |
2159 |
memmove(name, ptr, total_len); |
678712545 btrfs: Fix checkp... |
2160 |
name[total_len] = '\0'; |
98d377a08 Btrfs: add a func... |
2161 2162 2163 |
ret = 0; out: btrfs_free_path(path); |
ac8e9819d Btrfs: add search... |
2164 2165 2166 2167 2168 2169 2170 2171 |
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; |
01b810b88 btrfs: make root ... |
2172 |
int ret = 0; |
ac8e9819d Btrfs: add search... |
2173 |
|
2354d08fe Btrfs: use memdup... |
2174 2175 2176 |
args = memdup_user(argp, sizeof(*args)); if (IS_ERR(args)) return PTR_ERR(args); |
c2b96929e Btrfs: handle kma... |
2177 |
|
496ad9aa8 new helper: file_... |
2178 |
inode = file_inode(file); |
ac8e9819d Btrfs: add search... |
2179 |
|
01b810b88 btrfs: make root ... |
2180 2181 2182 2183 |
/* * Unprivileged query to obtain the containing subvolume root id. The * path is reset so it's consistent with btrfs_search_path_in_tree. */ |
1b53ac4d1 Btrfs: allow tree... |
2184 2185 |
if (args->treeid == 0) args->treeid = BTRFS_I(inode)->root->root_key.objectid; |
01b810b88 btrfs: make root ... |
2186 2187 2188 2189 2190 2191 2192 2193 2194 |
if (args->objectid == BTRFS_FIRST_FREE_OBJECTID) { args->name[0] = 0; goto out; } if (!capable(CAP_SYS_ADMIN)) { ret = -EPERM; goto out; } |
ac8e9819d Btrfs: add search... |
2195 2196 2197 |
ret = btrfs_search_path_in_tree(BTRFS_I(inode)->root->fs_info, args->treeid, args->objectid, args->name); |
01b810b88 btrfs: make root ... |
2198 |
out: |
ac8e9819d Btrfs: add search... |
2199 2200 2201 2202 |
if (ret == 0 && copy_to_user(argp, args, sizeof(*args))) ret = -EFAULT; kfree(args); |
98d377a08 Btrfs: add a func... |
2203 2204 |
return ret; } |
76dda93c6 Btrfs: add snapsh... |
2205 2206 2207 |
static noinline int btrfs_ioctl_snap_destroy(struct file *file, void __user *arg) { |
54563d41a btrfs: get rid of... |
2208 |
struct dentry *parent = file->f_path.dentry; |
0b246afa6 btrfs: root->fs_i... |
2209 |
struct btrfs_fs_info *fs_info = btrfs_sb(parent->d_sb); |
76dda93c6 Btrfs: add snapsh... |
2210 |
struct dentry *dentry; |
2b0143b5c VFS: normal files... |
2211 |
struct inode *dir = d_inode(parent); |
76dda93c6 Btrfs: add snapsh... |
2212 2213 2214 2215 2216 |
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; |
c58aaad2a Btrfs: fix wrong ... |
2217 |
struct btrfs_block_rsv block_rsv; |
521e0546c btrfs: protect sn... |
2218 |
u64 root_flags; |
c58aaad2a Btrfs: fix wrong ... |
2219 |
u64 qgroup_reserved; |
76dda93c6 Btrfs: add snapsh... |
2220 2221 2222 |
int namelen; int ret; int err = 0; |
325c50e3c btrfs: ensure tha... |
2223 2224 |
if (!S_ISDIR(dir->i_mode)) return -ENOTDIR; |
76dda93c6 Btrfs: add snapsh... |
2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 |
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... |
2236 |
err = mnt_want_write_file(file); |
76dda93c6 Btrfs: add snapsh... |
2237 2238 |
if (err) goto out; |
521e0546c btrfs: protect sn... |
2239 |
|
002354112 restore killabili... |
2240 2241 2242 |
err = down_write_killable_nested(&dir->i_rwsem, I_MUTEX_PARENT); if (err == -EINTR) goto out_drop_write; |
76dda93c6 Btrfs: add snapsh... |
2243 2244 2245 2246 2247 |
dentry = lookup_one_len(vol_args->name, parent, namelen); if (IS_ERR(dentry)) { err = PTR_ERR(dentry); goto out_unlock_dir; } |
2b0143b5c VFS: normal files... |
2248 |
if (d_really_is_negative(dentry)) { |
76dda93c6 Btrfs: add snapsh... |
2249 2250 2251 |
err = -ENOENT; goto out_dput; } |
2b0143b5c VFS: normal files... |
2252 |
inode = d_inode(dentry); |
4260f7c75 Btrfs: allow subv... |
2253 |
dest = BTRFS_I(inode)->root; |
678712545 btrfs: Fix checkp... |
2254 |
if (!capable(CAP_SYS_ADMIN)) { |
4260f7c75 Btrfs: allow subv... |
2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 |
/* * 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; |
0b246afa6 btrfs: root->fs_i... |
2269 |
if (!btrfs_test_opt(fs_info, USER_SUBVOL_RM_ALLOWED)) |
4260f7c75 Btrfs: allow subv... |
2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 |
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; |
4260f7c75 Btrfs: allow subv... |
2286 |
} |
5c39da5b6 Btrfs: do not del... |
2287 2288 2289 2290 |
/* check if subvolume may be deleted by a user */ err = btrfs_may_delete(dir, dentry, 1); if (err) goto out_dput; |
4a0cc7ca6 btrfs: Make btrfs... |
2291 |
if (btrfs_ino(BTRFS_I(inode)) != BTRFS_FIRST_FREE_OBJECTID) { |
76dda93c6 Btrfs: add snapsh... |
2292 2293 2294 |
err = -EINVAL; goto out_dput; } |
5955102c9 wrappers for ->i_... |
2295 |
inode_lock(inode); |
521e0546c btrfs: protect sn... |
2296 2297 2298 2299 2300 2301 2302 |
/* * Don't allow to delete a subvolume with send in progress. This is * inside the i_mutex so the error handling that has to drop the bit * again is not run concurrently. */ spin_lock(&dest->root_item_lock); |
c55bfa67e Btrfs: set dead f... |
2303 2304 2305 |
root_flags = btrfs_root_flags(&dest->root_item); if (dest->send_in_progress == 0) { btrfs_set_root_flags(&dest->root_item, |
521e0546c btrfs: protect sn... |
2306 2307 2308 2309 |
root_flags | BTRFS_ROOT_SUBVOL_DEAD); spin_unlock(&dest->root_item_lock); } else { spin_unlock(&dest->root_item_lock); |
0b246afa6 btrfs: root->fs_i... |
2310 2311 2312 |
btrfs_warn(fs_info, "Attempt to delete subvolume %llu during send", dest->root_key.objectid); |
521e0546c btrfs: protect sn... |
2313 |
err = -EPERM; |
909e26dce btrfs: unlock i_m... |
2314 |
goto out_unlock_inode; |
521e0546c btrfs: protect sn... |
2315 |
} |
0b246afa6 btrfs: root->fs_i... |
2316 |
down_write(&fs_info->subvol_sem); |
76dda93c6 Btrfs: add snapsh... |
2317 2318 2319 2320 |
err = may_destroy_subvol(dest); if (err) goto out_up_write; |
c58aaad2a Btrfs: fix wrong ... |
2321 2322 2323 2324 2325 2326 |
btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP); /* * One for dir inode, two for dir entries, two for root * ref/backref. */ err = btrfs_subvolume_reserve_metadata(root, &block_rsv, |
ee3441b49 btrfs: fall back ... |
2327 |
5, &qgroup_reserved, true); |
c58aaad2a Btrfs: fix wrong ... |
2328 2329 |
if (err) goto out_up_write; |
a22285a6a Btrfs: Integrate ... |
2330 2331 2332 |
trans = btrfs_start_transaction(root, 0); if (IS_ERR(trans)) { err = PTR_ERR(trans); |
c58aaad2a Btrfs: fix wrong ... |
2333 |
goto out_release; |
a22285a6a Btrfs: Integrate ... |
2334 |
} |
c58aaad2a Btrfs: fix wrong ... |
2335 2336 |
trans->block_rsv = &block_rsv; trans->bytes_reserved = block_rsv.size; |
a22285a6a Btrfs: Integrate ... |
2337 |
|
436635571 btrfs: Make btrfs... |
2338 |
btrfs_record_snapshot_destroy(trans, BTRFS_I(dir)); |
2be63d5ce Btrfs: fix file l... |
2339 |
|
76dda93c6 Btrfs: add snapsh... |
2340 2341 2342 2343 |
ret = btrfs_unlink_subvol(trans, root, dir, dest->root_key.objectid, dentry->d_name.name, dentry->d_name.len); |
79787eaab btrfs: replace ma... |
2344 2345 |
if (ret) { err = ret; |
66642832f btrfs: btrfs_abor... |
2346 |
btrfs_abort_transaction(trans, ret); |
79787eaab btrfs: replace ma... |
2347 2348 |
goto out_end_trans; } |
76dda93c6 Btrfs: add snapsh... |
2349 2350 2351 2352 2353 2354 2355 |
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); |
27cdeb709 Btrfs: use bitfie... |
2356 |
if (!test_and_set_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED, &dest->state)) { |
d68fc57b7 Btrfs: Metadata r... |
2357 |
ret = btrfs_insert_orphan_item(trans, |
0b246afa6 btrfs: root->fs_i... |
2358 |
fs_info->tree_root, |
d68fc57b7 Btrfs: Metadata r... |
2359 |
dest->root_key.objectid); |
79787eaab btrfs: replace ma... |
2360 |
if (ret) { |
66642832f btrfs: btrfs_abor... |
2361 |
btrfs_abort_transaction(trans, ret); |
79787eaab btrfs: replace ma... |
2362 2363 2364 |
err = ret; goto out_end_trans; } |
d68fc57b7 Btrfs: Metadata r... |
2365 |
} |
dd5f9615f Btrfs: maintain s... |
2366 |
|
0b246afa6 btrfs: root->fs_i... |
2367 |
ret = btrfs_uuid_tree_rem(trans, fs_info, dest->root_item.uuid, |
6bccf3ab1 btrfs: call funct... |
2368 |
BTRFS_UUID_KEY_SUBVOL, |
dd5f9615f Btrfs: maintain s... |
2369 2370 |
dest->root_key.objectid); if (ret && ret != -ENOENT) { |
66642832f btrfs: btrfs_abor... |
2371 |
btrfs_abort_transaction(trans, ret); |
dd5f9615f Btrfs: maintain s... |
2372 2373 2374 2375 |
err = ret; goto out_end_trans; } if (!btrfs_is_empty_uuid(dest->root_item.received_uuid)) { |
0b246afa6 btrfs: root->fs_i... |
2376 |
ret = btrfs_uuid_tree_rem(trans, fs_info, |
dd5f9615f Btrfs: maintain s... |
2377 2378 2379 2380 |
dest->root_item.received_uuid, BTRFS_UUID_KEY_RECEIVED_SUBVOL, dest->root_key.objectid); if (ret && ret != -ENOENT) { |
66642832f btrfs: btrfs_abor... |
2381 |
btrfs_abort_transaction(trans, ret); |
dd5f9615f Btrfs: maintain s... |
2382 2383 2384 2385 |
err = ret; goto out_end_trans; } } |
79787eaab btrfs: replace ma... |
2386 |
out_end_trans: |
c58aaad2a Btrfs: fix wrong ... |
2387 2388 |
trans->block_rsv = NULL; trans->bytes_reserved = 0; |
3a45bb207 btrfs: remove roo... |
2389 |
ret = btrfs_end_transaction(trans); |
79787eaab btrfs: replace ma... |
2390 2391 |
if (ret && !err) err = ret; |
76dda93c6 Btrfs: add snapsh... |
2392 |
inode->i_flags |= S_DEAD; |
c58aaad2a Btrfs: fix wrong ... |
2393 |
out_release: |
7775c8184 btrfs: remove unu... |
2394 |
btrfs_subvolume_release_metadata(fs_info, &block_rsv); |
76dda93c6 Btrfs: add snapsh... |
2395 |
out_up_write: |
0b246afa6 btrfs: root->fs_i... |
2396 |
up_write(&fs_info->subvol_sem); |
521e0546c btrfs: protect sn... |
2397 2398 |
if (err) { spin_lock(&dest->root_item_lock); |
c55bfa67e Btrfs: set dead f... |
2399 2400 |
root_flags = btrfs_root_flags(&dest->root_item); btrfs_set_root_flags(&dest->root_item, |
521e0546c btrfs: protect sn... |
2401 2402 2403 |
root_flags & ~BTRFS_ROOT_SUBVOL_DEAD); spin_unlock(&dest->root_item_lock); } |
909e26dce btrfs: unlock i_m... |
2404 |
out_unlock_inode: |
5955102c9 wrappers for ->i_... |
2405 |
inode_unlock(inode); |
76dda93c6 Btrfs: add snapsh... |
2406 |
if (!err) { |
64ad6c488 Btrfs: don't inva... |
2407 |
d_invalidate(dentry); |
76dda93c6 Btrfs: add snapsh... |
2408 2409 |
btrfs_invalidate_inodes(dest); d_delete(dentry); |
61155aa04 btrfs: assert tha... |
2410 |
ASSERT(dest->send_in_progress == 0); |
fa6ac8765 Btrfs: fix cleane... |
2411 2412 |
/* the last ref */ |
57cdc8db2 btrfs: cleanup in... |
2413 2414 2415 |
if (dest->ino_cache_inode) { iput(dest->ino_cache_inode); dest->ino_cache_inode = NULL; |
fa6ac8765 Btrfs: fix cleane... |
2416 |
} |
76dda93c6 Btrfs: add snapsh... |
2417 2418 2419 2420 |
} out_dput: dput(dentry); out_unlock_dir: |
5955102c9 wrappers for ->i_... |
2421 |
inode_unlock(dir); |
002354112 restore killabili... |
2422 |
out_drop_write: |
2a79f17e4 vfs: mnt_drop_wri... |
2423 |
mnt_drop_write_file(file); |
76dda93c6 Btrfs: add snapsh... |
2424 2425 2426 2427 |
out: kfree(vol_args); return err; } |
1e701a329 Btrfs: add new de... |
2428 |
static int btrfs_ioctl_defrag(struct file *file, void __user *argp) |
f46b5a66b Btrfs: split out ... |
2429 |
{ |
496ad9aa8 new helper: file_... |
2430 |
struct inode *inode = file_inode(file); |
f46b5a66b Btrfs: split out ... |
2431 |
struct btrfs_root *root = BTRFS_I(inode)->root; |
1e701a329 Btrfs: add new de... |
2432 |
struct btrfs_ioctl_defrag_range_args *range; |
c146afad2 Btrfs: mount ro a... |
2433 |
int ret; |
25122d15e Btrfs: reorder lo... |
2434 2435 2436 |
ret = mnt_want_write_file(file); if (ret) return ret; |
b83cc9693 Btrfs: Add readon... |
2437 |
|
25122d15e Btrfs: reorder lo... |
2438 2439 2440 |
if (btrfs_root_readonly(root)) { ret = -EROFS; goto out; |
5ac00addc Btrfs: disallow m... |
2441 |
} |
f46b5a66b Btrfs: split out ... |
2442 2443 2444 |
switch (inode->i_mode & S_IFMT) { case S_IFDIR: |
e441d54de Btrfs: add permis... |
2445 2446 2447 2448 |
if (!capable(CAP_SYS_ADMIN)) { ret = -EPERM; goto out; } |
de78b51a2 btrfs: remove cac... |
2449 |
ret = btrfs_defrag_root(root); |
f46b5a66b Btrfs: split out ... |
2450 2451 |
break; case S_IFREG: |
e441d54de Btrfs: add permis... |
2452 2453 2454 2455 |
if (!(file->f_mode & FMODE_WRITE)) { ret = -EINVAL; goto out; } |
1e701a329 Btrfs: add new de... |
2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 |
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... |
2468 |
goto out; |
1e701a329 Btrfs: add new de... |
2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 |
} /* 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; } |
496ad9aa8 new helper: file_... |
2479 |
ret = btrfs_defrag_file(file_inode(file), file, |
4cb5300bc Btrfs: add mount ... |
2480 2481 2482 |
range, 0, 0); if (ret > 0) ret = 0; |
1e701a329 Btrfs: add new de... |
2483 |
kfree(range); |
f46b5a66b Btrfs: split out ... |
2484 |
break; |
8929ecfa5 Btrfs: Introduce ... |
2485 2486 |
default: ret = -EINVAL; |
f46b5a66b Btrfs: split out ... |
2487 |
} |
e441d54de Btrfs: add permis... |
2488 |
out: |
25122d15e Btrfs: reorder lo... |
2489 |
mnt_drop_write_file(file); |
e441d54de Btrfs: add permis... |
2490 |
return ret; |
f46b5a66b Btrfs: split out ... |
2491 |
} |
2ff7e61e0 btrfs: take an fs... |
2492 |
static long btrfs_ioctl_add_dev(struct btrfs_fs_info *fs_info, void __user *arg) |
f46b5a66b Btrfs: split out ... |
2493 2494 2495 |
{ struct btrfs_ioctl_vol_args *vol_args; int ret; |
e441d54de Btrfs: add permis... |
2496 2497 |
if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
171938e52 btrfs: track excl... |
2498 |
if (test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)) |
e57138b3e btrfs: return btr... |
2499 |
return BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; |
c9e9f97bd Btrfs: add basic ... |
2500 |
|
0b246afa6 btrfs: root->fs_i... |
2501 |
mutex_lock(&fs_info->volume_mutex); |
dae7b665c btrfs: use memdup... |
2502 |
vol_args = memdup_user(arg, sizeof(*vol_args)); |
c9e9f97bd Btrfs: add basic ... |
2503 2504 2505 2506 |
if (IS_ERR(vol_args)) { ret = PTR_ERR(vol_args); goto out; } |
f46b5a66b Btrfs: split out ... |
2507 |
|
5516e5957 Btrfs: Null termi... |
2508 |
vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; |
2ff7e61e0 btrfs: take an fs... |
2509 |
ret = btrfs_init_new_device(fs_info, vol_args->name); |
f46b5a66b Btrfs: split out ... |
2510 |
|
43d207616 btrfs: device add... |
2511 |
if (!ret) |
0b246afa6 btrfs: root->fs_i... |
2512 |
btrfs_info(fs_info, "disk added %s", vol_args->name); |
43d207616 btrfs: device add... |
2513 |
|
f46b5a66b Btrfs: split out ... |
2514 |
kfree(vol_args); |
c9e9f97bd Btrfs: add basic ... |
2515 |
out: |
0b246afa6 btrfs: root->fs_i... |
2516 |
mutex_unlock(&fs_info->volume_mutex); |
171938e52 btrfs: track excl... |
2517 |
clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags); |
f46b5a66b Btrfs: split out ... |
2518 2519 |
return ret; } |
6b526ed70 btrfs: introduce ... |
2520 |
static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg) |
f46b5a66b Btrfs: split out ... |
2521 |
{ |
0b246afa6 btrfs: root->fs_i... |
2522 2523 |
struct inode *inode = file_inode(file); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); |
6b526ed70 btrfs: introduce ... |
2524 |
struct btrfs_ioctl_vol_args_v2 *vol_args; |
f46b5a66b Btrfs: split out ... |
2525 |
int ret; |
e441d54de Btrfs: add permis... |
2526 2527 |
if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
da24927b1 Btrfs: get write ... |
2528 2529 2530 |
ret = mnt_want_write_file(file); if (ret) return ret; |
c146afad2 Btrfs: mount ro a... |
2531 |
|
dae7b665c btrfs: use memdup... |
2532 |
vol_args = memdup_user(arg, sizeof(*vol_args)); |
c9e9f97bd Btrfs: add basic ... |
2533 2534 |
if (IS_ERR(vol_args)) { ret = PTR_ERR(vol_args); |
c47ca32d3 Btrfs: kfree()ing... |
2535 |
goto err_drop; |
c9e9f97bd Btrfs: add basic ... |
2536 |
} |
f46b5a66b Btrfs: split out ... |
2537 |
|
6b526ed70 btrfs: introduce ... |
2538 |
/* Check for compatibility reject unknown flags */ |
5f7e3b5b9 Btrfs: fix memory... |
2539 2540 2541 2542 |
if (vol_args->flags & ~BTRFS_VOL_ARG_V2_FLAGS_SUPPORTED) { ret = -EOPNOTSUPP; goto out; } |
f46b5a66b Btrfs: split out ... |
2543 |
|
171938e52 btrfs: track excl... |
2544 |
if (test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)) { |
183860f6a btrfs: device del... |
2545 2546 2547 |
ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; goto out; } |
0b246afa6 btrfs: root->fs_i... |
2548 |
mutex_lock(&fs_info->volume_mutex); |
735654ea9 btrfs: rename fla... |
2549 |
if (vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID) { |
2ff7e61e0 btrfs: take an fs... |
2550 |
ret = btrfs_rm_device(fs_info, NULL, vol_args->devid); |
6b526ed70 btrfs: introduce ... |
2551 2552 |
} else { vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0'; |
2ff7e61e0 btrfs: take an fs... |
2553 |
ret = btrfs_rm_device(fs_info, vol_args->name, 0); |
6b526ed70 btrfs: introduce ... |
2554 |
} |
0b246afa6 btrfs: root->fs_i... |
2555 |
mutex_unlock(&fs_info->volume_mutex); |
171938e52 btrfs: track excl... |
2556 |
clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags); |
183860f6a btrfs: device del... |
2557 |
|
6b526ed70 btrfs: introduce ... |
2558 |
if (!ret) { |
735654ea9 btrfs: rename fla... |
2559 |
if (vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID) |
0b246afa6 btrfs: root->fs_i... |
2560 |
btrfs_info(fs_info, "device deleted: id %llu", |
6b526ed70 btrfs: introduce ... |
2561 2562 |
vol_args->devid); else |
0b246afa6 btrfs: root->fs_i... |
2563 |
btrfs_info(fs_info, "device deleted: %s", |
6b526ed70 btrfs: introduce ... |
2564 2565 |
vol_args->name); } |
183860f6a btrfs: device del... |
2566 2567 |
out: kfree(vol_args); |
c47ca32d3 Btrfs: kfree()ing... |
2568 |
err_drop: |
4ac20c70b Btrfs: fix unlock... |
2569 |
mnt_drop_write_file(file); |
f46b5a66b Btrfs: split out ... |
2570 2571 |
return ret; } |
da24927b1 Btrfs: get write ... |
2572 |
static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg) |
f46b5a66b Btrfs: split out ... |
2573 |
{ |
0b246afa6 btrfs: root->fs_i... |
2574 2575 |
struct inode *inode = file_inode(file); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); |
f46b5a66b Btrfs: split out ... |
2576 2577 |
struct btrfs_ioctl_vol_args *vol_args; int ret; |
e441d54de Btrfs: add permis... |
2578 2579 |
if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
da24927b1 Btrfs: get write ... |
2580 2581 2582 |
ret = mnt_want_write_file(file); if (ret) return ret; |
c146afad2 Btrfs: mount ro a... |
2583 |
|
171938e52 btrfs: track excl... |
2584 |
if (test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)) { |
183860f6a btrfs: device del... |
2585 |
ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; |
58d7bbf81 btrfs: ioctl: reo... |
2586 2587 2588 2589 2590 2591 |
goto out_drop_write; } vol_args = memdup_user(arg, sizeof(*vol_args)); if (IS_ERR(vol_args)) { ret = PTR_ERR(vol_args); |
183860f6a btrfs: device del... |
2592 2593 |
goto out; } |
58d7bbf81 btrfs: ioctl: reo... |
2594 |
vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; |
0b246afa6 btrfs: root->fs_i... |
2595 |
mutex_lock(&fs_info->volume_mutex); |
2ff7e61e0 btrfs: take an fs... |
2596 |
ret = btrfs_rm_device(fs_info, vol_args->name, 0); |
0b246afa6 btrfs: root->fs_i... |
2597 |
mutex_unlock(&fs_info->volume_mutex); |
183860f6a btrfs: device del... |
2598 |
|
ec95d4917 btrfs: device del... |
2599 |
if (!ret) |
0b246afa6 btrfs: root->fs_i... |
2600 |
btrfs_info(fs_info, "disk deleted %s", vol_args->name); |
183860f6a btrfs: device del... |
2601 |
kfree(vol_args); |
58d7bbf81 btrfs: ioctl: reo... |
2602 |
out: |
171938e52 btrfs: track excl... |
2603 |
clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags); |
58d7bbf81 btrfs: ioctl: reo... |
2604 |
out_drop_write: |
4ac20c70b Btrfs: fix unlock... |
2605 |
mnt_drop_write_file(file); |
58d7bbf81 btrfs: ioctl: reo... |
2606 |
|
f46b5a66b Btrfs: split out ... |
2607 2608 |
return ret; } |
2ff7e61e0 btrfs: take an fs... |
2609 2610 |
static long btrfs_ioctl_fs_info(struct btrfs_fs_info *fs_info, void __user *arg) |
475f63874 btrfs: new ioctls... |
2611 |
{ |
027ed2f00 Btrfs: avoid stac... |
2612 |
struct btrfs_ioctl_fs_info_args *fi_args; |
475f63874 btrfs: new ioctls... |
2613 |
struct btrfs_device *device; |
0b246afa6 btrfs: root->fs_i... |
2614 |
struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; |
027ed2f00 Btrfs: avoid stac... |
2615 |
int ret = 0; |
475f63874 btrfs: new ioctls... |
2616 |
|
027ed2f00 Btrfs: avoid stac... |
2617 2618 2619 |
fi_args = kzalloc(sizeof(*fi_args), GFP_KERNEL); if (!fi_args) return -ENOMEM; |
f71717502 Btrfs: fix race c... |
2620 |
mutex_lock(&fs_devices->device_list_mutex); |
027ed2f00 Btrfs: avoid stac... |
2621 |
fi_args->num_devices = fs_devices->num_devices; |
0b246afa6 btrfs: root->fs_i... |
2622 |
memcpy(&fi_args->fsid, fs_info->fsid, sizeof(fi_args->fsid)); |
475f63874 btrfs: new ioctls... |
2623 |
|
d7641a49a btrfs: replace un... |
2624 |
list_for_each_entry(device, &fs_devices->devices, dev_list) { |
027ed2f00 Btrfs: avoid stac... |
2625 2626 |
if (device->devid > fi_args->max_id) fi_args->max_id = device->devid; |
475f63874 btrfs: new ioctls... |
2627 2628 |
} mutex_unlock(&fs_devices->device_list_mutex); |
bea7eafdb Btrfs: fix incorr... |
2629 2630 2631 |
fi_args->nodesize = fs_info->nodesize; fi_args->sectorsize = fs_info->sectorsize; fi_args->clone_alignment = fs_info->sectorsize; |
80a773fbf btrfs: retrieve m... |
2632 |
|
027ed2f00 Btrfs: avoid stac... |
2633 2634 |
if (copy_to_user(arg, fi_args, sizeof(*fi_args))) ret = -EFAULT; |
475f63874 btrfs: new ioctls... |
2635 |
|
027ed2f00 Btrfs: avoid stac... |
2636 2637 |
kfree(fi_args); return ret; |
475f63874 btrfs: new ioctls... |
2638 |
} |
2ff7e61e0 btrfs: take an fs... |
2639 2640 |
static long btrfs_ioctl_dev_info(struct btrfs_fs_info *fs_info, void __user *arg) |
475f63874 btrfs: new ioctls... |
2641 2642 2643 |
{ struct btrfs_ioctl_dev_info_args *di_args; struct btrfs_device *dev; |
0b246afa6 btrfs: root->fs_i... |
2644 |
struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; |
475f63874 btrfs: new ioctls... |
2645 2646 |
int ret = 0; char *s_uuid = NULL; |
475f63874 btrfs: new ioctls... |
2647 |
|
475f63874 btrfs: new ioctls... |
2648 2649 2650 |
di_args = memdup_user(arg, sizeof(*di_args)); if (IS_ERR(di_args)) return PTR_ERR(di_args); |
dd5f9615f Btrfs: maintain s... |
2651 |
if (!btrfs_is_empty_uuid(di_args->uuid)) |
475f63874 btrfs: new ioctls... |
2652 2653 2654 |
s_uuid = di_args->uuid; mutex_lock(&fs_devices->device_list_mutex); |
0b246afa6 btrfs: root->fs_i... |
2655 |
dev = btrfs_find_device(fs_info, di_args->devid, s_uuid, NULL); |
475f63874 btrfs: new ioctls... |
2656 2657 2658 2659 2660 2661 2662 |
if (!dev) { ret = -ENODEV; goto out; } di_args->devid = dev->devid; |
7cc8e58d5 Btrfs: fix unprot... |
2663 2664 |
di_args->bytes_used = btrfs_device_get_bytes_used(dev); di_args->total_bytes = btrfs_device_get_total_bytes(dev); |
475f63874 btrfs: new ioctls... |
2665 |
memcpy(di_args->uuid, dev->uuid, sizeof(di_args->uuid)); |
a27202fbe Btrfs: NUL-termin... |
2666 |
if (dev->name) { |
606686eea Btrfs: use rcu to... |
2667 2668 2669 2670 2671 2672 |
struct rcu_string *name; rcu_read_lock(); name = rcu_dereference(dev->name); strncpy(di_args->path, name->str, sizeof(di_args->path)); rcu_read_unlock(); |
a27202fbe Btrfs: NUL-termin... |
2673 2674 |
di_args->path[sizeof(di_args->path) - 1] = 0; } else { |
99ba55ad6 Btrfs: fix btrfs_... |
2675 |
di_args->path[0] = '\0'; |
a27202fbe Btrfs: NUL-termin... |
2676 |
} |
475f63874 btrfs: new ioctls... |
2677 2678 |
out: |
55793c0d0 btrfs: read entir... |
2679 |
mutex_unlock(&fs_devices->device_list_mutex); |
475f63874 btrfs: new ioctls... |
2680 2681 2682 2683 2684 2685 |
if (ret == 0 && copy_to_user(arg, di_args, sizeof(*di_args))) ret = -EFAULT; kfree(di_args); return ret; } |
f44146020 btrfs: fix deadlo... |
2686 |
static struct page *extent_same_get_page(struct inode *inode, pgoff_t index) |
416161db9 btrfs: offline de... |
2687 2688 |
{ struct page *page; |
416161db9 btrfs: offline de... |
2689 |
|
416161db9 btrfs: offline de... |
2690 2691 |
page = grab_cache_page(inode->i_mapping, index); if (!page) |
313140023 Btrfs: fix page r... |
2692 |
return ERR_PTR(-ENOMEM); |
416161db9 btrfs: offline de... |
2693 2694 |
if (!PageUptodate(page)) { |
313140023 Btrfs: fix page r... |
2695 2696 2697 2698 2699 |
int ret; ret = btrfs_readpage(NULL, page); if (ret) return ERR_PTR(ret); |
416161db9 btrfs: offline de... |
2700 2701 2702 |
lock_page(page); if (!PageUptodate(page)) { unlock_page(page); |
09cbfeaf1 mm, fs: get rid o... |
2703 |
put_page(page); |
313140023 Btrfs: fix page r... |
2704 2705 2706 2707 |
return ERR_PTR(-EIO); } if (page->mapping != inode->i_mapping) { unlock_page(page); |
09cbfeaf1 mm, fs: get rid o... |
2708 |
put_page(page); |
313140023 Btrfs: fix page r... |
2709 |
return ERR_PTR(-EAGAIN); |
416161db9 btrfs: offline de... |
2710 2711 |
} } |
416161db9 btrfs: offline de... |
2712 2713 2714 |
return page; } |
f44146020 btrfs: fix deadlo... |
2715 2716 2717 2718 |
static int gather_extent_pages(struct inode *inode, struct page **pages, int num_pages, u64 off) { int i; |
09cbfeaf1 mm, fs: get rid o... |
2719 |
pgoff_t index = off >> PAGE_SHIFT; |
f44146020 btrfs: fix deadlo... |
2720 2721 |
for (i = 0; i < num_pages; i++) { |
313140023 Btrfs: fix page r... |
2722 |
again: |
f44146020 btrfs: fix deadlo... |
2723 |
pages[i] = extent_same_get_page(inode, index + i); |
313140023 Btrfs: fix page r... |
2724 2725 2726 2727 2728 2729 2730 2731 |
if (IS_ERR(pages[i])) { int err = PTR_ERR(pages[i]); if (err == -EAGAIN) goto again; pages[i] = NULL; return err; } |
f44146020 btrfs: fix deadlo... |
2732 2733 2734 |
} return 0; } |
e0bd70c67 Btrfs: fix invali... |
2735 2736 |
static int lock_extent_range(struct inode *inode, u64 off, u64 len, bool retry_range_locking) |
77fe20dc6 btrfs: abtract ou... |
2737 |
{ |
e0bd70c67 Btrfs: fix invali... |
2738 2739 2740 2741 2742 2743 2744 2745 |
/* * Do any pending delalloc/csum calculations on inode, one way or * another, and lock file content. * The locking order is: * * 1) pages * 2) range in the inode's io tree */ |
77fe20dc6 btrfs: abtract ou... |
2746 2747 2748 2749 2750 |
while (1) { struct btrfs_ordered_extent *ordered; lock_extent(&BTRFS_I(inode)->io_tree, off, off + len - 1); ordered = btrfs_lookup_first_ordered_extent(inode, off + len - 1); |
ff5df9b88 Btrfs: ioctl, don... |
2751 2752 2753 |
if ((!ordered || ordered->file_offset + ordered->len <= off || ordered->file_offset >= off + len) && |
77fe20dc6 btrfs: abtract ou... |
2754 |
!test_range_bit(&BTRFS_I(inode)->io_tree, off, |
ff5df9b88 Btrfs: ioctl, don... |
2755 2756 2757 |
off + len - 1, EXTENT_DELALLOC, 0, NULL)) { if (ordered) btrfs_put_ordered_extent(ordered); |
77fe20dc6 btrfs: abtract ou... |
2758 |
break; |
ff5df9b88 Btrfs: ioctl, don... |
2759 |
} |
77fe20dc6 btrfs: abtract ou... |
2760 2761 2762 |
unlock_extent(&BTRFS_I(inode)->io_tree, off, off + len - 1); if (ordered) btrfs_put_ordered_extent(ordered); |
e0bd70c67 Btrfs: fix invali... |
2763 2764 |
if (!retry_range_locking) return -EAGAIN; |
77fe20dc6 btrfs: abtract ou... |
2765 2766 |
btrfs_wait_ordered_range(inode, off, len); } |
e0bd70c67 Btrfs: fix invali... |
2767 |
return 0; |
77fe20dc6 btrfs: abtract ou... |
2768 |
} |
f44146020 btrfs: fix deadlo... |
2769 |
static void btrfs_double_inode_unlock(struct inode *inode1, struct inode *inode2) |
416161db9 btrfs: offline de... |
2770 |
{ |
5955102c9 wrappers for ->i_... |
2771 2772 |
inode_unlock(inode1); inode_unlock(inode2); |
416161db9 btrfs: offline de... |
2773 |
} |
f44146020 btrfs: fix deadlo... |
2774 2775 2776 2777 |
static void btrfs_double_inode_lock(struct inode *inode1, struct inode *inode2) { if (inode1 < inode2) swap(inode1, inode2); |
5955102c9 wrappers for ->i_... |
2778 2779 |
inode_lock_nested(inode1, I_MUTEX_PARENT); inode_lock_nested(inode2, I_MUTEX_CHILD); |
f44146020 btrfs: fix deadlo... |
2780 2781 2782 2783 2784 2785 2786 2787 |
} static void btrfs_double_extent_unlock(struct inode *inode1, u64 loff1, struct inode *inode2, u64 loff2, u64 len) { unlock_extent(&BTRFS_I(inode1)->io_tree, loff1, loff1 + len - 1); unlock_extent(&BTRFS_I(inode2)->io_tree, loff2, loff2 + len - 1); } |
e0bd70c67 Btrfs: fix invali... |
2788 2789 2790 |
static int btrfs_double_extent_lock(struct inode *inode1, u64 loff1, struct inode *inode2, u64 loff2, u64 len, bool retry_range_locking) |
416161db9 btrfs: offline de... |
2791 |
{ |
e0bd70c67 Btrfs: fix invali... |
2792 |
int ret; |
416161db9 btrfs: offline de... |
2793 2794 2795 2796 |
if (inode1 < inode2) { swap(inode1, inode2); swap(loff1, loff2); } |
e0bd70c67 Btrfs: fix invali... |
2797 2798 2799 2800 2801 2802 2803 2804 |
ret = lock_extent_range(inode1, loff1, len, retry_range_locking); if (ret) return ret; ret = lock_extent_range(inode2, loff2, len, retry_range_locking); if (ret) unlock_extent(&BTRFS_I(inode1)->io_tree, loff1, loff1 + len - 1); return ret; |
f44146020 btrfs: fix deadlo... |
2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 |
} struct cmp_pages { int num_pages; struct page **src_pages; struct page **dst_pages; }; static void btrfs_cmp_data_free(struct cmp_pages *cmp) { int i; struct page *pg; for (i = 0; i < cmp->num_pages; i++) { pg = cmp->src_pages[i]; |
e0bd70c67 Btrfs: fix invali... |
2820 2821 |
if (pg) { unlock_page(pg); |
09cbfeaf1 mm, fs: get rid o... |
2822 |
put_page(pg); |
e0bd70c67 Btrfs: fix invali... |
2823 |
} |
f44146020 btrfs: fix deadlo... |
2824 |
pg = cmp->dst_pages[i]; |
e0bd70c67 Btrfs: fix invali... |
2825 2826 |
if (pg) { unlock_page(pg); |
09cbfeaf1 mm, fs: get rid o... |
2827 |
put_page(pg); |
e0bd70c67 Btrfs: fix invali... |
2828 |
} |
f44146020 btrfs: fix deadlo... |
2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 |
} kfree(cmp->src_pages); kfree(cmp->dst_pages); } static int btrfs_cmp_data_prepare(struct inode *src, u64 loff, struct inode *dst, u64 dst_loff, u64 len, struct cmp_pages *cmp) { int ret; |
09cbfeaf1 mm, fs: get rid o... |
2839 |
int num_pages = PAGE_ALIGN(len) >> PAGE_SHIFT; |
f44146020 btrfs: fix deadlo... |
2840 2841 2842 2843 2844 2845 2846 2847 |
struct page **src_pgarr, **dst_pgarr; /* * We must gather up all the pages before we initiate our * extent locking. We use an array for the page pointers. Size * of the array is bounded by len, which is in turn bounded by * BTRFS_MAX_DEDUPE_LEN. */ |
66722f7c0 btrfs: switch to ... |
2848 2849 |
src_pgarr = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL); dst_pgarr = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL); |
f44146020 btrfs: fix deadlo... |
2850 2851 2852 2853 |
if (!src_pgarr || !dst_pgarr) { kfree(src_pgarr); kfree(dst_pgarr); return -ENOMEM; |
416161db9 btrfs: offline de... |
2854 |
} |
f44146020 btrfs: fix deadlo... |
2855 2856 2857 |
cmp->num_pages = num_pages; cmp->src_pages = src_pgarr; cmp->dst_pages = dst_pgarr; |
b1517622f Btrfs: fix deadlo... |
2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 |
/* * If deduping ranges in the same inode, locking rules make it mandatory * to always lock pages in ascending order to avoid deadlocks with * concurrent tasks (such as starting writeback/delalloc). */ if (src == dst && dst_loff < loff) { swap(src_pgarr, dst_pgarr); swap(loff, dst_loff); } ret = gather_extent_pages(src, src_pgarr, cmp->num_pages, loff); |
f44146020 btrfs: fix deadlo... |
2869 2870 |
if (ret) goto out; |
b1517622f Btrfs: fix deadlo... |
2871 |
ret = gather_extent_pages(dst, dst_pgarr, cmp->num_pages, dst_loff); |
f44146020 btrfs: fix deadlo... |
2872 2873 2874 2875 |
out: if (ret) btrfs_cmp_data_free(cmp); |
78ad4ce01 btrfs: propagate ... |
2876 |
return ret; |
416161db9 btrfs: offline de... |
2877 |
} |
1a287cfea btrfs: remove unu... |
2878 |
static int btrfs_cmp_data(u64 len, struct cmp_pages *cmp) |
416161db9 btrfs: offline de... |
2879 2880 |
{ int ret = 0; |
f44146020 btrfs: fix deadlo... |
2881 |
int i; |
416161db9 btrfs: offline de... |
2882 |
struct page *src_page, *dst_page; |
09cbfeaf1 mm, fs: get rid o... |
2883 |
unsigned int cmp_len = PAGE_SIZE; |
416161db9 btrfs: offline de... |
2884 |
void *addr, *dst_addr; |
f44146020 btrfs: fix deadlo... |
2885 |
i = 0; |
416161db9 btrfs: offline de... |
2886 |
while (len) { |
09cbfeaf1 mm, fs: get rid o... |
2887 |
if (len < PAGE_SIZE) |
416161db9 btrfs: offline de... |
2888 |
cmp_len = len; |
f44146020 btrfs: fix deadlo... |
2889 2890 2891 2892 |
BUG_ON(i >= cmp->num_pages); src_page = cmp->src_pages[i]; dst_page = cmp->dst_pages[i]; |
e0bd70c67 Btrfs: fix invali... |
2893 2894 |
ASSERT(PageLocked(src_page)); ASSERT(PageLocked(dst_page)); |
f44146020 btrfs: fix deadlo... |
2895 |
|
416161db9 btrfs: offline de... |
2896 2897 2898 2899 2900 2901 2902 |
addr = kmap_atomic(src_page); dst_addr = kmap_atomic(dst_page); flush_dcache_page(src_page); flush_dcache_page(dst_page); if (memcmp(addr, dst_addr, cmp_len)) |
2b3909f8a btrfs: use new de... |
2903 |
ret = -EBADE; |
416161db9 btrfs: offline de... |
2904 2905 2906 |
kunmap_atomic(addr); kunmap_atomic(dst_addr); |
416161db9 btrfs: offline de... |
2907 2908 2909 |
if (ret) break; |
416161db9 btrfs: offline de... |
2910 |
len -= cmp_len; |
f44146020 btrfs: fix deadlo... |
2911 |
i++; |
416161db9 btrfs: offline de... |
2912 2913 2914 2915 |
} return ret; } |
e1d227a42 btrfs: Handle una... |
2916 2917 |
static int extent_same_check_offsets(struct inode *inode, u64 off, u64 *plen, u64 olen) |
416161db9 btrfs: offline de... |
2918 |
{ |
e1d227a42 btrfs: Handle una... |
2919 |
u64 len = *plen; |
416161db9 btrfs: offline de... |
2920 |
u64 bs = BTRFS_I(inode)->root->fs_info->sb->s_blocksize; |
e1d227a42 btrfs: Handle una... |
2921 |
if (off + olen > inode->i_size || off + olen < off) |
416161db9 btrfs: offline de... |
2922 |
return -EINVAL; |
e1d227a42 btrfs: Handle una... |
2923 2924 2925 2926 |
/* if we extend to eof, continue to block boundary */ if (off + len == inode->i_size) *plen = len = ALIGN(inode->i_size, bs) - off; |
416161db9 btrfs: offline de... |
2927 2928 2929 2930 2931 2932 |
/* Check that we are block aligned - btrfs_clone() requires this */ if (!IS_ALIGNED(off, bs) || !IS_ALIGNED(off + len, bs)) return -EINVAL; return 0; } |
e1d227a42 btrfs: Handle una... |
2933 |
static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen, |
416161db9 btrfs: offline de... |
2934 2935 2936 |
struct inode *dst, u64 dst_loff) { int ret; |
e1d227a42 btrfs: Handle una... |
2937 |
u64 len = olen; |
f44146020 btrfs: fix deadlo... |
2938 |
struct cmp_pages cmp; |
fc4badd9f Btrfs: refactor b... |
2939 |
bool same_inode = (src == dst); |
0efa9f48c btrfs: allow dedu... |
2940 2941 |
u64 same_lock_start = 0; u64 same_lock_len = 0; |
416161db9 btrfs: offline de... |
2942 |
|
113e82838 Btrfs: fix inode ... |
2943 2944 |
if (len == 0) return 0; |
fc4badd9f Btrfs: refactor b... |
2945 |
if (same_inode) |
5955102c9 wrappers for ->i_... |
2946 |
inode_lock(src); |
fc4badd9f Btrfs: refactor b... |
2947 2948 |
else btrfs_double_inode_lock(src, dst); |
416161db9 btrfs: offline de... |
2949 |
|
fc4badd9f Btrfs: refactor b... |
2950 2951 2952 |
ret = extent_same_check_offsets(src, loff, &len, olen); if (ret) goto out_unlock; |
416161db9 btrfs: offline de... |
2953 |
|
fc4badd9f Btrfs: refactor b... |
2954 2955 2956 2957 2958 |
ret = extent_same_check_offsets(dst, dst_loff, &len, olen); if (ret) goto out_unlock; if (same_inode) { |
0efa9f48c btrfs: allow dedu... |
2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 |
/* * Single inode case wants the same checks, except we * don't want our length pushed out past i_size as * comparing that data range makes no sense. * * extent_same_check_offsets() will do this for an * unaligned length at i_size, so catch it here and * reject the request. * * This effectively means we require aligned extents * for the single-inode case, whereas the other cases * allow an unaligned length so long as it ends at * i_size. */ if (len != olen) { ret = -EINVAL; goto out_unlock; } /* Check for overlapping ranges */ if (dst_loff + len > loff && dst_loff < loff + len) { ret = -EINVAL; goto out_unlock; } same_lock_start = min_t(u64, loff, dst_loff); same_lock_len = max_t(u64, loff, dst_loff) + len - same_lock_start; |
ae3968b41 Btrfs: fix data c... |
2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 |
} else { /* * If the source and destination inodes are different, the * source's range end offset matches the source's i_size, that * i_size is not a multiple of the sector size, and the * destination range does not go past the destination's i_size, * we must round down the length to the nearest sector size * multiple. If we don't do this adjustment we end replacing * with zeroes the bytes in the range that starts at the * deduplication range's end offset and ends at the next sector * size multiple. */ if (loff + olen == i_size_read(src) && dst_loff + len < i_size_read(dst)) { const u64 sz = BTRFS_I(src)->root->fs_info->sectorsize; len = round_down(i_size_read(src), sz) - loff; |
c7a082fb6 Btrfs: fix infini... |
3003 3004 |
if (len == 0) return 0; |
ae3968b41 Btrfs: fix data c... |
3005 3006 |
olen = len; } |
0efa9f48c btrfs: allow dedu... |
3007 |
} |
416161db9 btrfs: offline de... |
3008 3009 3010 3011 3012 3013 3014 |
/* don't make the dst file partly checksummed */ if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) != (BTRFS_I(dst)->flags & BTRFS_INODE_NODATASUM)) { ret = -EINVAL; goto out_unlock; } |
e0bd70c67 Btrfs: fix invali... |
3015 |
again: |
f44146020 btrfs: fix deadlo... |
3016 3017 3018 |
ret = btrfs_cmp_data_prepare(src, loff, dst, dst_loff, olen, &cmp); if (ret) goto out_unlock; |
0efa9f48c btrfs: allow dedu... |
3019 |
if (same_inode) |
e0bd70c67 Btrfs: fix invali... |
3020 3021 |
ret = lock_extent_range(src, same_lock_start, same_lock_len, false); |
0efa9f48c btrfs: allow dedu... |
3022 |
else |
e0bd70c67 Btrfs: fix invali... |
3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 |
ret = btrfs_double_extent_lock(src, loff, dst, dst_loff, len, false); /* * If one of the inodes has dirty pages in the respective range or * ordered extents, we need to flush dellaloc and wait for all ordered * extents in the range. We must unlock the pages and the ranges in the * io trees to avoid deadlocks when flushing delalloc (requires locking * pages) and when waiting for ordered extents to complete (they require * range locking). */ if (ret == -EAGAIN) { /* * Ranges in the io trees already unlocked. Now unlock all * pages before waiting for all IO to complete. */ btrfs_cmp_data_free(&cmp); if (same_inode) { btrfs_wait_ordered_range(src, same_lock_start, same_lock_len); } else { btrfs_wait_ordered_range(src, loff, len); btrfs_wait_ordered_range(dst, dst_loff, len); } goto again; } ASSERT(ret == 0); if (WARN_ON(ret)) { /* ranges in the io trees already unlocked */ btrfs_cmp_data_free(&cmp); return ret; } |
f44146020 btrfs: fix deadlo... |
3054 |
|
207910dde btrfs: pass unali... |
3055 |
/* pass original length for comparison so we stay within i_size */ |
1a287cfea btrfs: remove unu... |
3056 |
ret = btrfs_cmp_data(olen, &cmp); |
416161db9 btrfs: offline de... |
3057 |
if (ret == 0) |
1c919a5e1 btrfs: don't upda... |
3058 |
ret = btrfs_clone(src, dst, loff, olen, len, dst_loff, 1); |
416161db9 btrfs: offline de... |
3059 |
|
0efa9f48c btrfs: allow dedu... |
3060 3061 3062 3063 3064 |
if (same_inode) unlock_extent(&BTRFS_I(src)->io_tree, same_lock_start, same_lock_start + same_lock_len - 1); else btrfs_double_extent_unlock(src, loff, dst, dst_loff, len); |
f44146020 btrfs: fix deadlo... |
3065 3066 |
btrfs_cmp_data_free(&cmp); |
416161db9 btrfs: offline de... |
3067 |
out_unlock: |
0efa9f48c btrfs: allow dedu... |
3068 |
if (same_inode) |
5955102c9 wrappers for ->i_... |
3069 |
inode_unlock(src); |
0efa9f48c btrfs: allow dedu... |
3070 3071 |
else btrfs_double_inode_unlock(src, dst); |
416161db9 btrfs: offline de... |
3072 3073 3074 |
return ret; } |
ee22184b5 Btrfs: use linux/... |
3075 |
#define BTRFS_MAX_DEDUPE_LEN SZ_16M |
416161db9 btrfs: offline de... |
3076 |
|
2b3909f8a btrfs: use new de... |
3077 3078 |
ssize_t btrfs_dedupe_file_range(struct file *src_file, u64 loff, u64 olen, struct file *dst_file, u64 dst_loff) |
416161db9 btrfs: offline de... |
3079 |
{ |
2b3909f8a btrfs: use new de... |
3080 3081 |
struct inode *src = file_inode(src_file); struct inode *dst = file_inode(dst_file); |
416161db9 btrfs: offline de... |
3082 |
u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize; |
2b3909f8a btrfs: use new de... |
3083 |
ssize_t res; |
416161db9 btrfs: offline de... |
3084 |
|
2b3909f8a btrfs: use new de... |
3085 3086 |
if (olen > BTRFS_MAX_DEDUPE_LEN) olen = BTRFS_MAX_DEDUPE_LEN; |
416161db9 btrfs: offline de... |
3087 |
|
09cbfeaf1 mm, fs: get rid o... |
3088 |
if (WARN_ON_ONCE(bs < PAGE_SIZE)) { |
416161db9 btrfs: offline de... |
3089 3090 3091 3092 3093 |
/* * Btrfs does not support blocksize < page_size. As a * result, btrfs_cmp_data() won't correctly handle * this situation without an update. */ |
2b3909f8a btrfs: use new de... |
3094 |
return -EINVAL; |
416161db9 btrfs: offline de... |
3095 |
} |
2b3909f8a btrfs: use new de... |
3096 3097 3098 3099 |
res = btrfs_extent_same(src, loff, olen, dst, dst_loff); if (res) return res; return olen; |
416161db9 btrfs: offline de... |
3100 |
} |
f82a9901b Btrfs: fix clone ... |
3101 3102 3103 3104 |
static int clone_finish_inode_update(struct btrfs_trans_handle *trans, struct inode *inode, u64 endoff, const u64 destoff, |
1c919a5e1 btrfs: don't upda... |
3105 3106 |
const u64 olen, int no_time_update) |
f82a9901b Btrfs: fix clone ... |
3107 3108 3109 3110 3111 |
{ struct btrfs_root *root = BTRFS_I(inode)->root; int ret; inode_inc_iversion(inode); |
1c919a5e1 btrfs: don't upda... |
3112 |
if (!no_time_update) |
c2050a454 fs: Replace curre... |
3113 |
inode->i_mtime = inode->i_ctime = current_time(inode); |
f82a9901b Btrfs: fix clone ... |
3114 3115 3116 3117 3118 3119 3120 |
/* * We round up to the block size at eof when determining which * extents to clone above, but shouldn't round up the file size. */ if (endoff > destoff + olen) endoff = destoff + olen; if (endoff > inode->i_size) |
6ef06d279 btrfs: Make btrfs... |
3121 |
btrfs_i_size_write(BTRFS_I(inode), endoff); |
f82a9901b Btrfs: fix clone ... |
3122 3123 3124 |
ret = btrfs_update_inode(trans, root, inode); if (ret) { |
66642832f btrfs: btrfs_abor... |
3125 |
btrfs_abort_transaction(trans, ret); |
3a45bb207 btrfs: remove roo... |
3126 |
btrfs_end_transaction(trans); |
f82a9901b Btrfs: fix clone ... |
3127 3128 |
goto out; } |
3a45bb207 btrfs: remove roo... |
3129 |
ret = btrfs_end_transaction(trans); |
f82a9901b Btrfs: fix clone ... |
3130 3131 3132 |
out: return ret; } |
a2f392e40 btrfs: Make clone... |
3133 |
static void clone_update_extent_map(struct btrfs_inode *inode, |
7ffbb598a Btrfs: make fsync... |
3134 3135 |
const struct btrfs_trans_handle *trans, const struct btrfs_path *path, |
7ffbb598a Btrfs: make fsync... |
3136 3137 3138 |
const u64 hole_offset, const u64 hole_len) { |
a2f392e40 btrfs: Make clone... |
3139 |
struct extent_map_tree *em_tree = &inode->extent_tree; |
7ffbb598a Btrfs: make fsync... |
3140 3141 3142 3143 3144 |
struct extent_map *em; int ret; em = alloc_extent_map(); if (!em) { |
a2f392e40 btrfs: Make clone... |
3145 |
set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &inode->runtime_flags); |
7ffbb598a Btrfs: make fsync... |
3146 3147 |
return; } |
14f597963 Btrfs: fix use-af... |
3148 3149 3150 3151 3152 |
if (path) { struct btrfs_file_extent_item *fi; fi = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_file_extent_item); |
a2f392e40 btrfs: Make clone... |
3153 |
btrfs_extent_item_to_extent_map(inode, path, fi, false, em); |
7ffbb598a Btrfs: make fsync... |
3154 3155 3156 3157 |
em->generation = -1; if (btrfs_file_extent_type(path->nodes[0], fi) == BTRFS_FILE_EXTENT_INLINE) set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, |
a2f392e40 btrfs: Make clone... |
3158 |
&inode->runtime_flags); |
7ffbb598a Btrfs: make fsync... |
3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 |
} else { em->start = hole_offset; em->len = hole_len; em->ram_bytes = em->len; em->orig_start = hole_offset; em->block_start = EXTENT_MAP_HOLE; em->block_len = 0; em->orig_block_len = 0; em->compress_type = BTRFS_COMPRESS_NONE; em->generation = trans->transid; } while (1) { write_lock(&em_tree->lock); ret = add_extent_mapping(em_tree, em, 1); write_unlock(&em_tree->lock); if (ret != -EEXIST) { free_extent_map(em); break; } |
a2f392e40 btrfs: Make clone... |
3179 |
btrfs_drop_extent_cache(inode, em->start, |
7ffbb598a Btrfs: make fsync... |
3180 3181 |
em->start + em->len - 1, 0); } |
ee39b432b btrfs: remove unl... |
3182 |
if (ret) |
a2f392e40 btrfs: Make clone... |
3183 |
set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &inode->runtime_flags); |
7ffbb598a Btrfs: make fsync... |
3184 |
} |
8039d87d9 Btrfs: fix file c... |
3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 |
/* * Make sure we do not end up inserting an inline extent into a file that has * already other (non-inline) extents. If a file has an inline extent it can * not have any other extents and the (single) inline extent must start at the * file offset 0. Failing to respect these rules will lead to file corruption, * resulting in EIO errors on read/write operations, hitting BUG_ON's in mm, etc * * We can have extents that have been already written to disk or we can have * dirty ranges still in delalloc, in which case the extent maps and items are * created only when we run delalloc, and the delalloc ranges might fall outside * the range we are currently locking in the inode's io tree. So we check the * inode's i_size because of that (i_size updates are done while holding the * i_mutex, which we are holding here). * We also check to see if the inode has a size not greater than "datal" but has * extents beyond it, due to an fallocate with FALLOC_FL_KEEP_SIZE (and we are * protected against such concurrent fallocate calls by the i_mutex). * * If the file has no extents but a size greater than datal, do not allow the * copy because we would need turn the inline extent into a non-inline one (even * with NO_HOLES enabled). If we find our destination inode only has one inline * extent, just overwrite it with the source inline extent if its size is less * than the source extent's size, or we could copy the source inline extent's * data into the destination inode's inline extent if the later is greater then * the former. */ |
4a0ab9d71 btrfs: remove unu... |
3210 |
static int clone_copy_inline_extent(struct inode *dst, |
8039d87d9 Btrfs: fix file c... |
3211 3212 3213 3214 3215 3216 3217 3218 3219 |
struct btrfs_trans_handle *trans, struct btrfs_path *path, struct btrfs_key *new_key, const u64 drop_start, const u64 datal, const u64 skip, const u64 size, char *inline_data) { |
0b246afa6 btrfs: root->fs_i... |
3220 |
struct btrfs_fs_info *fs_info = btrfs_sb(dst->i_sb); |
8039d87d9 Btrfs: fix file c... |
3221 3222 |
struct btrfs_root *root = BTRFS_I(dst)->root; const u64 aligned_end = ALIGN(new_key->offset + datal, |
0b246afa6 btrfs: root->fs_i... |
3223 |
fs_info->sectorsize); |
8039d87d9 Btrfs: fix file c... |
3224 3225 3226 3227 3228 |
int ret; struct btrfs_key key; if (new_key->offset > 0) return -EOPNOTSUPP; |
4a0cc7ca6 btrfs: Make btrfs... |
3229 |
key.objectid = btrfs_ino(BTRFS_I(dst)); |
8039d87d9 Btrfs: fix file c... |
3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 |
key.type = BTRFS_EXTENT_DATA_KEY; key.offset = 0; ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) { return ret; } else if (ret > 0) { if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { ret = btrfs_next_leaf(root, path); if (ret < 0) return ret; else if (ret > 0) goto copy_inline_extent; } btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); |
4a0cc7ca6 btrfs: Make btrfs... |
3244 |
if (key.objectid == btrfs_ino(BTRFS_I(dst)) && |
8039d87d9 Btrfs: fix file c... |
3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 |
key.type == BTRFS_EXTENT_DATA_KEY) { ASSERT(key.offset > 0); return -EOPNOTSUPP; } } else if (i_size_read(dst) <= datal) { struct btrfs_file_extent_item *ei; u64 ext_len; /* * If the file size is <= datal, make sure there are no other * extents following (can happen do to an fallocate call with * the flag FALLOC_FL_KEEP_SIZE). */ ei = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_file_extent_item); /* * If it's an inline extent, it can not have other extents * following it. */ if (btrfs_file_extent_type(path->nodes[0], ei) == BTRFS_FILE_EXTENT_INLINE) goto copy_inline_extent; ext_len = btrfs_file_extent_num_bytes(path->nodes[0], ei); if (ext_len > aligned_end) return -EOPNOTSUPP; ret = btrfs_next_item(root, path); if (ret < 0) { return ret; } else if (ret == 0) { btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); |
4a0cc7ca6 btrfs: Make btrfs... |
3278 |
if (key.objectid == btrfs_ino(BTRFS_I(dst)) && |
8039d87d9 Btrfs: fix file c... |
3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 |
key.type == BTRFS_EXTENT_DATA_KEY) return -EOPNOTSUPP; } } copy_inline_extent: /* * We have no extent items, or we have an extent at offset 0 which may * or may not be inlined. All these cases are dealt the same way. */ if (i_size_read(dst) > datal) { /* * If the destination inode has an inline extent... * This would require copying the data from the source inline * extent into the beginning of the destination's inline extent. * But this is really complex, both extents can be compressed * or just one of them, which would require decompressing and * re-compressing data (which could increase the new compressed * size, not allowing the compressed data to fit anymore in an * inline extent). * So just don't support this case for now (it should be rare, * we are not really saving space when cloning inline extents). */ return -EOPNOTSUPP; } btrfs_release_path(path); ret = btrfs_drop_extents(trans, root, dst, drop_start, aligned_end, 1); if (ret) return ret; ret = btrfs_insert_empty_item(trans, root, path, new_key, size); if (ret) return ret; if (skip) { const u32 start = btrfs_file_extent_calc_inline_size(0); memmove(inline_data + start, inline_data + start + skip, datal); } write_extent_buffer(path->nodes[0], inline_data, btrfs_item_ptr_offset(path->nodes[0], path->slots[0]), size); inode_add_bytes(dst, datal); return 0; } |
32b7c687c btrfs_ioctl_clone... |
3327 3328 3329 3330 3331 3332 3333 |
/** * btrfs_clone() - clone a range from inode file to another * * @src: Inode to clone from * @inode: Inode to clone to * @off: Offset within source to start clone from * @olen: Original length, passed by user, of range to clone |
1c919a5e1 btrfs: don't upda... |
3334 |
* @olen_aligned: Block-aligned value of olen |
32b7c687c btrfs_ioctl_clone... |
3335 |
* @destoff: Offset within @inode to start clone |
1c919a5e1 btrfs: don't upda... |
3336 |
* @no_time_update: Whether to update mtime/ctime on the target inode |
32b7c687c btrfs_ioctl_clone... |
3337 3338 |
*/ static int btrfs_clone(struct inode *src, struct inode *inode, |
f82a9901b Btrfs: fix clone ... |
3339 |
const u64 off, const u64 olen, const u64 olen_aligned, |
1c919a5e1 btrfs: don't upda... |
3340 |
const u64 destoff, int no_time_update) |
f46b5a66b Btrfs: split out ... |
3341 |
{ |
0b246afa6 btrfs: root->fs_i... |
3342 |
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); |
f46b5a66b Btrfs: split out ... |
3343 |
struct btrfs_root *root = BTRFS_I(inode)->root; |
32b7c687c btrfs_ioctl_clone... |
3344 |
struct btrfs_path *path = NULL; |
f46b5a66b Btrfs: split out ... |
3345 |
struct extent_buffer *leaf; |
32b7c687c btrfs_ioctl_clone... |
3346 3347 |
struct btrfs_trans_handle *trans; char *buf = NULL; |
ae01a0abf Btrfs: Update clo... |
3348 |
struct btrfs_key key; |
f46b5a66b Btrfs: split out ... |
3349 3350 |
u32 nritems; int slot; |
ae01a0abf Btrfs: Update clo... |
3351 |
int ret; |
f82a9901b Btrfs: fix clone ... |
3352 |
const u64 len = olen_aligned; |
f82a9901b Btrfs: fix clone ... |
3353 |
u64 last_dest_end = destoff; |
ae01a0abf Btrfs: Update clo... |
3354 3355 |
ret = -ENOMEM; |
752ade68c treewide: use kv[... |
3356 3357 3358 |
buf = kvmalloc(fs_info->nodesize, GFP_KERNEL); if (!buf) return ret; |
ae01a0abf Btrfs: Update clo... |
3359 3360 3361 |
path = btrfs_alloc_path(); if (!path) { |
153519559 btrfs: clone: use... |
3362 |
kvfree(buf); |
32b7c687c btrfs_ioctl_clone... |
3363 |
return ret; |
d525e8ab0 Btrfs: add dummy ... |
3364 |
} |
e4058b54d btrfs: cleanup, u... |
3365 |
path->reada = READA_FORWARD; |
c5c9cd4d1 Btrfs: allow clon... |
3366 |
/* clone data */ |
4a0cc7ca6 btrfs: Make btrfs... |
3367 |
key.objectid = btrfs_ino(BTRFS_I(src)); |
ae01a0abf Btrfs: Update clo... |
3368 |
key.type = BTRFS_EXTENT_DATA_KEY; |
2c463823c Btrfs: avoid visi... |
3369 |
key.offset = off; |
f46b5a66b Btrfs: split out ... |
3370 3371 |
while (1) { |
de249e66a Btrfs: fix uninit... |
3372 |
u64 next_key_min_offset = key.offset + 1; |
df858e767 Btrfs: fix range ... |
3373 |
|
f46b5a66b Btrfs: split out ... |
3374 3375 3376 3377 |
/* * note the key will change type as we walk through the * tree. */ |
e4355f34e Btrfs: faster fil... |
3378 |
path->leave_spinning = 1; |
362a20c5e btrfs: allow cros... |
3379 3380 |
ret = btrfs_search_slot(NULL, BTRFS_I(src)->root, &key, path, 0, 0); |
f46b5a66b Btrfs: split out ... |
3381 3382 |
if (ret < 0) goto out; |
2c463823c Btrfs: avoid visi... |
3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 |
/* * First search, if no extent item that starts at offset off was * found but the previous item is an extent item, it's possible * it might overlap our target range, therefore process it. */ if (key.offset == off && ret > 0 && path->slots[0] > 0) { btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0] - 1); if (key.type == BTRFS_EXTENT_DATA_KEY) path->slots[0]--; } |
f46b5a66b Btrfs: split out ... |
3394 |
|
ae01a0abf Btrfs: Update clo... |
3395 |
nritems = btrfs_header_nritems(path->nodes[0]); |
e4355f34e Btrfs: faster fil... |
3396 |
process_slot: |
ae01a0abf Btrfs: Update clo... |
3397 |
if (path->slots[0] >= nritems) { |
362a20c5e btrfs: allow cros... |
3398 |
ret = btrfs_next_leaf(BTRFS_I(src)->root, path); |
f46b5a66b Btrfs: split out ... |
3399 3400 3401 3402 |
if (ret < 0) goto out; if (ret > 0) break; |
ae01a0abf Btrfs: Update clo... |
3403 |
nritems = btrfs_header_nritems(path->nodes[0]); |
f46b5a66b Btrfs: split out ... |
3404 3405 3406 |
} leaf = path->nodes[0]; slot = path->slots[0]; |
f46b5a66b Btrfs: split out ... |
3407 |
|
ae01a0abf Btrfs: Update clo... |
3408 |
btrfs_item_key_to_cpu(leaf, &key, slot); |
962a298f3 btrfs: kill the k... |
3409 |
if (key.type > BTRFS_EXTENT_DATA_KEY || |
4a0cc7ca6 btrfs: Make btrfs... |
3410 |
key.objectid != btrfs_ino(BTRFS_I(src))) |
f46b5a66b Btrfs: split out ... |
3411 |
break; |
962a298f3 btrfs: kill the k... |
3412 |
if (key.type == BTRFS_EXTENT_DATA_KEY) { |
c5c9cd4d1 Btrfs: allow clon... |
3413 3414 |
struct btrfs_file_extent_item *extent; int type; |
31840ae1a Btrfs: Full back ... |
3415 3416 |
u32 size; struct btrfs_key new_key; |
c5c9cd4d1 Btrfs: allow clon... |
3417 3418 3419 |
u64 disko = 0, diskl = 0; u64 datao = 0, datal = 0; u8 comp; |
f82a9901b Btrfs: fix clone ... |
3420 |
u64 drop_start; |
31840ae1a Btrfs: Full back ... |
3421 |
|
c5c9cd4d1 Btrfs: allow clon... |
3422 3423 3424 3425 |
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... |
3426 3427 |
if (type == BTRFS_FILE_EXTENT_REG || type == BTRFS_FILE_EXTENT_PREALLOC) { |
d397712bc Btrfs: Fix checkp... |
3428 3429 3430 3431 |
disko = btrfs_file_extent_disk_bytenr(leaf, extent); diskl = btrfs_file_extent_disk_num_bytes(leaf, extent); |
c5c9cd4d1 Btrfs: allow clon... |
3432 |
datao = btrfs_file_extent_offset(leaf, extent); |
d397712bc Btrfs: Fix checkp... |
3433 3434 |
datal = btrfs_file_extent_num_bytes(leaf, extent); |
c5c9cd4d1 Btrfs: allow clon... |
3435 3436 3437 3438 3439 |
} else if (type == BTRFS_FILE_EXTENT_INLINE) { /* take upper bound, may be compressed */ datal = btrfs_file_extent_ram_bytes(leaf, extent); } |
31840ae1a Btrfs: Full back ... |
3440 |
|
2c463823c Btrfs: avoid visi... |
3441 3442 3443 3444 3445 3446 |
/* * The first search might have left us at an extent * item that ends before our target range's start, can * happen if we have holes and NO_HOLES feature enabled. */ if (key.offset + datal <= off) { |
e4355f34e Btrfs: faster fil... |
3447 3448 |
path->slots[0]++; goto process_slot; |
2c463823c Btrfs: avoid visi... |
3449 3450 |
} else if (key.offset >= off + len) { break; |
e4355f34e Btrfs: faster fil... |
3451 |
} |
df858e767 Btrfs: fix range ... |
3452 |
next_key_min_offset = key.offset + datal; |
e4355f34e Btrfs: faster fil... |
3453 3454 3455 3456 3457 3458 3459 |
size = btrfs_item_size_nr(leaf, slot); read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf, slot), size); btrfs_release_path(path); path->leave_spinning = 0; |
c5c9cd4d1 Btrfs: allow clon... |
3460 |
|
31840ae1a Btrfs: Full back ... |
3461 |
memcpy(&new_key, &key, sizeof(new_key)); |
4a0cc7ca6 btrfs: Make btrfs... |
3462 |
new_key.objectid = btrfs_ino(BTRFS_I(inode)); |
4d728ec7a Btrfs: Fix file c... |
3463 3464 3465 3466 |
if (off <= key.offset) new_key.offset = key.offset + destoff - off; else new_key.offset = destoff; |
31840ae1a Btrfs: Full back ... |
3467 |
|
b6f3409b2 Btrfs: reserve su... |
3468 |
/* |
f82a9901b Btrfs: fix clone ... |
3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 |
* Deal with a hole that doesn't have an extent item * that represents it (NO_HOLES feature enabled). * This hole is either in the middle of the cloning * range or at the beginning (fully overlaps it or * partially overlaps it). */ if (new_key.offset != last_dest_end) drop_start = last_dest_end; else drop_start = new_key.offset; /* |
b6f3409b2 Btrfs: reserve su... |
3481 3482 3483 3484 3485 |
* 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 ... |
3486 3487 3488 3489 |
if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto out; } |
c8a894d77 Btrfs: fix the fi... |
3490 3491 |
if (type == BTRFS_FILE_EXTENT_REG || type == BTRFS_FILE_EXTENT_PREALLOC) { |
d72c0842f Btrfs: calc file ... |
3492 3493 3494 3495 |
/* * a | --- range to clone ---| b * | ------------- extent ------------- | */ |
939155841 trivial: fs/btrfs... |
3496 |
/* subtract range b */ |
d72c0842f Btrfs: calc file ... |
3497 3498 |
if (key.offset + datal > off + len) datal = off + len - key.offset; |
939155841 trivial: fs/btrfs... |
3499 |
/* subtract range a */ |
a22285a6a Btrfs: Integrate ... |
3500 3501 3502 3503 |
if (off > key.offset) { datao += off - key.offset; datal -= off - key.offset; } |
5dc562c54 Btrfs: turbo char... |
3504 |
ret = btrfs_drop_extents(trans, root, inode, |
f82a9901b Btrfs: fix clone ... |
3505 |
drop_start, |
a22285a6a Btrfs: Integrate ... |
3506 |
new_key.offset + datal, |
2671485d3 Btrfs: remove unu... |
3507 |
1); |
79787eaab btrfs: replace ma... |
3508 |
if (ret) { |
3f9e3df8d btrfs: replace er... |
3509 |
if (ret != -EOPNOTSUPP) |
00fdf13a2 Btrfs: fix a cras... |
3510 |
btrfs_abort_transaction(trans, |
66642832f btrfs: btrfs_abor... |
3511 |
ret); |
3a45bb207 btrfs: remove roo... |
3512 |
btrfs_end_transaction(trans); |
79787eaab btrfs: replace ma... |
3513 3514 |
goto out; } |
a22285a6a Btrfs: Integrate ... |
3515 |
|
c5c9cd4d1 Btrfs: allow clon... |
3516 3517 |
ret = btrfs_insert_empty_item(trans, root, path, &new_key, size); |
79787eaab btrfs: replace ma... |
3518 |
if (ret) { |
66642832f btrfs: btrfs_abor... |
3519 |
btrfs_abort_transaction(trans, ret); |
3a45bb207 btrfs: remove roo... |
3520 |
btrfs_end_transaction(trans); |
79787eaab btrfs: replace ma... |
3521 3522 |
goto out; } |
c5c9cd4d1 Btrfs: allow clon... |
3523 3524 3525 3526 |
leaf = path->nodes[0]; slot = path->slots[0]; write_extent_buffer(leaf, buf, |
31840ae1a Btrfs: Full back ... |
3527 3528 |
btrfs_item_ptr_offset(leaf, slot), size); |
ae01a0abf Btrfs: Update clo... |
3529 |
|
c5c9cd4d1 Btrfs: allow clon... |
3530 |
extent = btrfs_item_ptr(leaf, slot, |
f46b5a66b Btrfs: split out ... |
3531 |
struct btrfs_file_extent_item); |
c5c9cd4d1 Btrfs: allow clon... |
3532 |
|
c5c9cd4d1 Btrfs: allow clon... |
3533 3534 3535 |
/* disko == 0 means it's a hole */ if (!disko) datao = 0; |
c5c9cd4d1 Btrfs: allow clon... |
3536 3537 3538 3539 3540 |
btrfs_set_file_extent_offset(leaf, extent, datao); btrfs_set_file_extent_num_bytes(leaf, extent, datal); |
fcebe4562 Btrfs: rework qgr... |
3541 |
|
c5c9cd4d1 Btrfs: allow clon... |
3542 3543 |
if (disko) { inode_add_bytes(inode, datal); |
2ff7e61e0 btrfs: take an fs... |
3544 3545 |
ret = btrfs_inc_extent_ref(trans, fs_info, |
5d4f98a28 Btrfs: Mixed back... |
3546 3547 |
disko, diskl, 0, root->root_key.objectid, |
4a0cc7ca6 btrfs: Make btrfs... |
3548 |
btrfs_ino(BTRFS_I(inode)), |
b06c4bf5c Btrfs: fix regres... |
3549 |
new_key.offset - datao); |
79787eaab btrfs: replace ma... |
3550 3551 |
if (ret) { btrfs_abort_transaction(trans, |
79787eaab btrfs: replace ma... |
3552 |
ret); |
3a45bb207 btrfs: remove roo... |
3553 |
btrfs_end_transaction(trans); |
79787eaab btrfs: replace ma... |
3554 3555 3556 |
goto out; } |
f46b5a66b Btrfs: split out ... |
3557 |
} |
c5c9cd4d1 Btrfs: allow clon... |
3558 3559 3560 |
} else if (type == BTRFS_FILE_EXTENT_INLINE) { u64 skip = 0; u64 trim = 0; |
ed9587626 Btrfs: fix file c... |
3561 |
|
c5c9cd4d1 Btrfs: allow clon... |
3562 3563 3564 3565 |
if (off > key.offset) { skip = off - key.offset; new_key.offset += skip; } |
d397712bc Btrfs: Fix checkp... |
3566 |
|
aa42ffd91 Btrfs: fix off-by... |
3567 3568 |
if (key.offset + datal > off + len) trim = key.offset + datal - (off + len); |
d397712bc Btrfs: Fix checkp... |
3569 |
|
c5c9cd4d1 Btrfs: allow clon... |
3570 |
if (comp && (skip || trim)) { |
c5c9cd4d1 Btrfs: allow clon... |
3571 |
ret = -EINVAL; |
3a45bb207 btrfs: remove roo... |
3572 |
btrfs_end_transaction(trans); |
c5c9cd4d1 Btrfs: allow clon... |
3573 3574 3575 3576 |
goto out; } size -= skip + trim; datal -= skip + trim; |
a22285a6a Btrfs: Integrate ... |
3577 |
|
4a0ab9d71 btrfs: remove unu... |
3578 |
ret = clone_copy_inline_extent(inode, |
8039d87d9 Btrfs: fix file c... |
3579 3580 3581 3582 3583 |
trans, path, &new_key, drop_start, datal, skip, size, buf); |
79787eaab btrfs: replace ma... |
3584 |
if (ret) { |
3f9e3df8d btrfs: replace er... |
3585 |
if (ret != -EOPNOTSUPP) |
3a29bc092 Btrfs: fix EINVAL... |
3586 |
btrfs_abort_transaction(trans, |
8039d87d9 Btrfs: fix file c... |
3587 |
ret); |
3a45bb207 btrfs: remove roo... |
3588 |
btrfs_end_transaction(trans); |
79787eaab btrfs: replace ma... |
3589 3590 |
goto out; } |
c5c9cd4d1 Btrfs: allow clon... |
3591 3592 |
leaf = path->nodes[0]; slot = path->slots[0]; |
f46b5a66b Btrfs: split out ... |
3593 |
} |
c5c9cd4d1 Btrfs: allow clon... |
3594 |
|
7ffbb598a Btrfs: make fsync... |
3595 3596 |
/* If we have an implicit hole (NO_HOLES feature). */ if (drop_start < new_key.offset) |
a2f392e40 btrfs: Make clone... |
3597 |
clone_update_extent_map(BTRFS_I(inode), trans, |
14f597963 Btrfs: fix use-af... |
3598 |
NULL, drop_start, |
7ffbb598a Btrfs: make fsync... |
3599 |
new_key.offset - drop_start); |
a2f392e40 btrfs: Make clone... |
3600 3601 |
clone_update_extent_map(BTRFS_I(inode), trans, path, 0, 0); |
7ffbb598a Btrfs: make fsync... |
3602 |
|
c5c9cd4d1 Btrfs: allow clon... |
3603 |
btrfs_mark_buffer_dirty(leaf); |
b3b4aa74b btrfs: drop unuse... |
3604 |
btrfs_release_path(path); |
c5c9cd4d1 Btrfs: allow clon... |
3605 |
|
62e2390e1 Btrfs: clone, don... |
3606 |
last_dest_end = ALIGN(new_key.offset + datal, |
0b246afa6 btrfs: root->fs_i... |
3607 |
fs_info->sectorsize); |
f82a9901b Btrfs: fix clone ... |
3608 3609 |
ret = clone_finish_inode_update(trans, inode, last_dest_end, |
1c919a5e1 btrfs: don't upda... |
3610 3611 |
destoff, olen, no_time_update); |
f82a9901b Btrfs: fix clone ... |
3612 |
if (ret) |
79787eaab btrfs: replace ma... |
3613 |
goto out; |
2c463823c Btrfs: avoid visi... |
3614 3615 |
if (new_key.offset + datal >= destoff + len) break; |
a22285a6a Btrfs: Integrate ... |
3616 |
} |
b3b4aa74b btrfs: drop unuse... |
3617 |
btrfs_release_path(path); |
df858e767 Btrfs: fix range ... |
3618 |
key.offset = next_key_min_offset; |
69ae5e445 btrfs: make file ... |
3619 3620 3621 3622 3623 |
if (fatal_signal_pending(current)) { ret = -EINTR; goto out; } |
f46b5a66b Btrfs: split out ... |
3624 |
} |
f46b5a66b Btrfs: split out ... |
3625 |
ret = 0; |
32b7c687c btrfs_ioctl_clone... |
3626 |
|
f82a9901b Btrfs: fix clone ... |
3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 |
if (last_dest_end < destoff + len) { /* * We have an implicit hole (NO_HOLES feature is enabled) that * fully or partially overlaps our cloning range at its end. */ btrfs_release_path(path); /* * 1 - remove extent(s) * 1 - inode update */ trans = btrfs_start_transaction(root, 2); if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto out; } ret = btrfs_drop_extents(trans, root, inode, last_dest_end, destoff + len, 1); if (ret) { if (ret != -EOPNOTSUPP) |
66642832f btrfs: btrfs_abor... |
3647 |
btrfs_abort_transaction(trans, ret); |
3a45bb207 btrfs: remove roo... |
3648 |
btrfs_end_transaction(trans); |
f82a9901b Btrfs: fix clone ... |
3649 3650 |
goto out; } |
a2f392e40 btrfs: Make clone... |
3651 3652 3653 |
clone_update_extent_map(BTRFS_I(inode), trans, NULL, last_dest_end, destoff + len - last_dest_end); |
f82a9901b Btrfs: fix clone ... |
3654 |
ret = clone_finish_inode_update(trans, inode, destoff + len, |
1c919a5e1 btrfs: don't upda... |
3655 |
destoff, olen, no_time_update); |
f82a9901b Btrfs: fix clone ... |
3656 |
} |
f46b5a66b Btrfs: split out ... |
3657 |
out: |
32b7c687c btrfs_ioctl_clone... |
3658 |
btrfs_free_path(path); |
153519559 btrfs: clone: use... |
3659 |
kvfree(buf); |
32b7c687c btrfs_ioctl_clone... |
3660 3661 |
return ret; } |
3db11b2ee btrfs: add .copy_... |
3662 3663 |
static noinline int btrfs_clone_files(struct file *file, struct file *file_src, u64 off, u64 olen, u64 destoff) |
32b7c687c btrfs_ioctl_clone... |
3664 |
{ |
54563d41a btrfs: get rid of... |
3665 |
struct inode *inode = file_inode(file); |
3db11b2ee btrfs: add .copy_... |
3666 |
struct inode *src = file_inode(file_src); |
0b246afa6 btrfs: root->fs_i... |
3667 |
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); |
32b7c687c btrfs_ioctl_clone... |
3668 |
struct btrfs_root *root = BTRFS_I(inode)->root; |
32b7c687c btrfs_ioctl_clone... |
3669 3670 |
int ret; u64 len = olen; |
0b246afa6 btrfs: root->fs_i... |
3671 |
u64 bs = fs_info->sb->s_blocksize; |
3db11b2ee btrfs: add .copy_... |
3672 |
int same_inode = src == inode; |
32b7c687c btrfs_ioctl_clone... |
3673 3674 3675 3676 3677 3678 3679 |
/* * 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. |
00fdf13a2 Btrfs: fix a cras... |
3680 3681 3682 |
* * - split destination inode's inline extents. The inline extents can * be either compressed or non-compressed. |
32b7c687c btrfs_ioctl_clone... |
3683 |
*/ |
32b7c687c btrfs_ioctl_clone... |
3684 3685 |
if (btrfs_root_readonly(root)) return -EROFS; |
3db11b2ee btrfs: add .copy_... |
3686 3687 3688 |
if (file_src->f_path.mnt != file->f_path.mnt || src->i_sb != inode->i_sb) return -EXDEV; |
32b7c687c btrfs_ioctl_clone... |
3689 |
|
32b7c687c btrfs_ioctl_clone... |
3690 |
if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode)) |
3db11b2ee btrfs: add .copy_... |
3691 |
return -EISDIR; |
32b7c687c btrfs_ioctl_clone... |
3692 3693 |
if (!same_inode) { |
293a8489f btrfs: fix clone ... |
3694 |
btrfs_double_inode_lock(src, inode); |
32b7c687c btrfs_ioctl_clone... |
3695 |
} else { |
5955102c9 wrappers for ->i_... |
3696 |
inode_lock(src); |
32b7c687c btrfs_ioctl_clone... |
3697 |
} |
55d29ff48 Btrfs: fix clone ... |
3698 3699 3700 3701 3702 3703 |
/* don't make the dst file partly checksummed */ if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) != (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) { ret = -EINVAL; goto out_unlock; } |
32b7c687c btrfs_ioctl_clone... |
3704 3705 3706 3707 3708 3709 |
/* determine range to clone */ ret = -EINVAL; if (off + len > src->i_size || off + len < off) goto out_unlock; if (len == 0) olen = len = src->i_size - off; |
d62eead02 Btrfs: fix data c... |
3710 3711 3712 3713 3714 3715 3716 3717 3718 |
/* * If we extend to eof, continue to block boundary if and only if the * destination end offset matches the destination file's size, otherwise * we would be corrupting data by placing the eof block into the middle * of a file. */ if (off + len == src->i_size) { if (!IS_ALIGNED(len, bs) && destoff + len < inode->i_size) goto out_unlock; |
32b7c687c btrfs_ioctl_clone... |
3719 |
len = ALIGN(src->i_size, bs) - off; |
d62eead02 Btrfs: fix data c... |
3720 |
} |
32b7c687c btrfs_ioctl_clone... |
3721 |
|
ccccf3d67 Btrfs: fix inode ... |
3722 3723 3724 3725 |
if (len == 0) { ret = 0; goto out_unlock; } |
32b7c687c btrfs_ioctl_clone... |
3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 |
/* verify the end result is block aligned */ if (!IS_ALIGNED(off, bs) || !IS_ALIGNED(off + len, bs) || !IS_ALIGNED(destoff, bs)) goto out_unlock; /* verify if ranges are overlapped within the same file */ if (same_inode) { if (destoff + len > off && destoff < off + len) goto out_unlock; } if (destoff > inode->i_size) { ret = btrfs_cont_expand(inode, inode->i_size, destoff); if (ret) goto out_unlock; } |
c125b8bff Btrfs: ensure rea... |
3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 |
/* * Lock the target range too. Right after we replace the file extent * items in the fs tree (which now point to the cloned data), we might * have a worker replace them with extent items relative to a write * operation that was issued before this clone operation (i.e. confront * with inode.c:btrfs_finish_ordered_io). */ if (same_inode) { u64 lock_start = min_t(u64, off, destoff); u64 lock_len = max_t(u64, off, destoff) + len - lock_start; |
32b7c687c btrfs_ioctl_clone... |
3752 |
|
e0bd70c67 Btrfs: fix invali... |
3753 |
ret = lock_extent_range(src, lock_start, lock_len, true); |
c125b8bff Btrfs: ensure rea... |
3754 |
} else { |
e0bd70c67 Btrfs: fix invali... |
3755 3756 3757 3758 3759 3760 3761 |
ret = btrfs_double_extent_lock(src, off, inode, destoff, len, true); } ASSERT(ret == 0); if (WARN_ON(ret)) { /* ranges in the io trees already unlocked */ goto out_unlock; |
c125b8bff Btrfs: ensure rea... |
3762 |
} |
32b7c687c btrfs_ioctl_clone... |
3763 |
|
1c919a5e1 btrfs: don't upda... |
3764 |
ret = btrfs_clone(src, inode, off, olen, len, destoff, 0); |
32b7c687c btrfs_ioctl_clone... |
3765 |
|
c125b8bff Btrfs: ensure rea... |
3766 3767 3768 3769 3770 3771 |
if (same_inode) { u64 lock_start = min_t(u64, off, destoff); u64 lock_end = max_t(u64, off, destoff) + len - 1; unlock_extent(&BTRFS_I(src)->io_tree, lock_start, lock_end); } else { |
293a8489f btrfs: fix clone ... |
3772 |
btrfs_double_extent_unlock(src, off, inode, destoff, len); |
c125b8bff Btrfs: ensure rea... |
3773 3774 3775 3776 3777 |
} /* * Truncate page cache pages so that future reads will see the cloned * data immediately and not the previous data. */ |
65bfa6580 Btrfs: btrfs_ioct... |
3778 |
truncate_inode_pages_range(&inode->i_data, |
09cbfeaf1 mm, fs: get rid o... |
3779 3780 |
round_down(destoff, PAGE_SIZE), round_up(destoff + len, PAGE_SIZE) - 1); |
f46b5a66b Btrfs: split out ... |
3781 |
out_unlock: |
293a8489f btrfs: fix clone ... |
3782 3783 3784 |
if (!same_inode) btrfs_double_inode_unlock(src, inode); else |
5955102c9 wrappers for ->i_... |
3785 |
inode_unlock(src); |
3db11b2ee btrfs: add .copy_... |
3786 3787 |
return ret; } |
04b38d601 vfs: pull btrfs c... |
3788 3789 |
int btrfs_clone_file_range(struct file *src_file, loff_t off, struct file *dst_file, loff_t destoff, u64 len) |
3db11b2ee btrfs: add .copy_... |
3790 |
{ |
04b38d601 vfs: pull btrfs c... |
3791 |
return btrfs_clone_files(dst_file, src_file, off, len, destoff); |
c5c9cd4d1 Btrfs: allow clon... |
3792 |
} |
f46b5a66b Btrfs: split out ... |
3793 3794 3795 3796 3797 3798 |
/* * 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... |
3799 |
static long btrfs_ioctl_trans_start(struct file *file) |
f46b5a66b Btrfs: split out ... |
3800 |
{ |
496ad9aa8 new helper: file_... |
3801 |
struct inode *inode = file_inode(file); |
0b246afa6 btrfs: root->fs_i... |
3802 |
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); |
f46b5a66b Btrfs: split out ... |
3803 3804 |
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_trans_handle *trans; |
23b5ec749 btrfs: fix readdi... |
3805 |
struct btrfs_file_private *private; |
1ab86aedb Btrfs: fix error ... |
3806 |
int ret; |
3558d4f88 btrfs: Deprecate ... |
3807 |
static bool warned = false; |
f46b5a66b Btrfs: split out ... |
3808 |
|
1ab86aedb Btrfs: fix error ... |
3809 |
ret = -EPERM; |
df5b5520b BTRFS_IOC_TRANS_S... |
3810 |
if (!capable(CAP_SYS_ADMIN)) |
1ab86aedb Btrfs: fix error ... |
3811 |
goto out; |
df5b5520b BTRFS_IOC_TRANS_S... |
3812 |
|
3558d4f88 btrfs: Deprecate ... |
3813 3814 3815 3816 3817 3818 3819 3820 3821 |
if (!warned) { btrfs_warn(fs_info, "Userspace transaction mechanism is considered " "deprecated and slated to be removed in 4.17. " "If you have a valid use case please " "speak up on the mailing list"); WARN_ON(1); warned = true; } |
1ab86aedb Btrfs: fix error ... |
3822 |
ret = -EINPROGRESS; |
23b5ec749 btrfs: fix readdi... |
3823 3824 |
private = file->private_data; if (private && private->trans) |
f46b5a66b Btrfs: split out ... |
3825 |
goto out; |
23b5ec749 btrfs: fix readdi... |
3826 3827 3828 3829 3830 3831 3832 |
if (!private) { private = kzalloc(sizeof(struct btrfs_file_private), GFP_KERNEL); if (!private) return -ENOMEM; file->private_data = private; } |
9ca9ee09c Btrfs: fix ioctl-... |
3833 |
|
b83cc9693 Btrfs: Add readon... |
3834 3835 3836 |
ret = -EROFS; if (btrfs_root_readonly(root)) goto out; |
a561be710 switch a bunch of... |
3837 |
ret = mnt_want_write_file(file); |
c146afad2 Btrfs: mount ro a... |
3838 3839 |
if (ret) goto out; |
0b246afa6 btrfs: root->fs_i... |
3840 |
atomic_inc(&fs_info->open_ioctl_trans); |
9ca9ee09c Btrfs: fix ioctl-... |
3841 |
|
1ab86aedb Btrfs: fix error ... |
3842 |
ret = -ENOMEM; |
7a7eaa40a Btrfs: take away ... |
3843 |
trans = btrfs_start_ioctl_transaction(root); |
abd30bb0a btrfs: check retu... |
3844 |
if (IS_ERR(trans)) |
1ab86aedb Btrfs: fix error ... |
3845 |
goto out_drop; |
23b5ec749 btrfs: fix readdi... |
3846 |
private->trans = trans; |
1ab86aedb Btrfs: fix error ... |
3847 3848 3849 |
return 0; out_drop: |
0b246afa6 btrfs: root->fs_i... |
3850 |
atomic_dec(&fs_info->open_ioctl_trans); |
2a79f17e4 vfs: mnt_drop_wri... |
3851 |
mnt_drop_write_file(file); |
f46b5a66b Btrfs: split out ... |
3852 |
out: |
f46b5a66b Btrfs: split out ... |
3853 3854 |
return ret; } |
6ef5ed0d3 Btrfs: add ioctl ... |
3855 3856 |
static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) { |
496ad9aa8 new helper: file_... |
3857 |
struct inode *inode = file_inode(file); |
0b246afa6 btrfs: root->fs_i... |
3858 |
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); |
6ef5ed0d3 Btrfs: add ioctl ... |
3859 3860 3861 3862 3863 3864 3865 |
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; |
6ef5ed0d3 Btrfs: add ioctl ... |
3866 3867 |
u64 objectid = 0; u64 dir_id; |
3c04ce010 Btrfs: get write ... |
3868 |
int ret; |
6ef5ed0d3 Btrfs: add ioctl ... |
3869 3870 3871 |
if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
3c04ce010 Btrfs: get write ... |
3872 3873 3874 3875 3876 3877 3878 3879 |
ret = mnt_want_write_file(file); if (ret) return ret; if (copy_from_user(&objectid, argp, sizeof(objectid))) { ret = -EFAULT; goto out; } |
6ef5ed0d3 Btrfs: add ioctl ... |
3880 3881 |
if (!objectid) |
1cecf579d Btrfs: btrfs_ioct... |
3882 |
objectid = BTRFS_FS_TREE_OBJECTID; |
6ef5ed0d3 Btrfs: add ioctl ... |
3883 3884 3885 3886 |
location.objectid = objectid; location.type = BTRFS_ROOT_ITEM_KEY; location.offset = (u64)-1; |
0b246afa6 btrfs: root->fs_i... |
3887 |
new_root = btrfs_read_fs_root_no_name(fs_info, &location); |
3c04ce010 Btrfs: get write ... |
3888 3889 3890 3891 |
if (IS_ERR(new_root)) { ret = PTR_ERR(new_root); goto out; } |
6d6d28293 btrfs: prevent to... |
3892 3893 3894 3895 |
if (!is_fstree(new_root->objectid)) { ret = -ENOENT; goto out; } |
6ef5ed0d3 Btrfs: add ioctl ... |
3896 |
|
6ef5ed0d3 Btrfs: add ioctl ... |
3897 |
path = btrfs_alloc_path(); |
3c04ce010 Btrfs: get write ... |
3898 3899 3900 3901 |
if (!path) { ret = -ENOMEM; goto out; } |
6ef5ed0d3 Btrfs: add ioctl ... |
3902 3903 3904 |
path->leave_spinning = 1; trans = btrfs_start_transaction(root, 1); |
98d5dc13e btrfs: fix return... |
3905 |
if (IS_ERR(trans)) { |
6ef5ed0d3 Btrfs: add ioctl ... |
3906 |
btrfs_free_path(path); |
3c04ce010 Btrfs: get write ... |
3907 3908 |
ret = PTR_ERR(trans); goto out; |
6ef5ed0d3 Btrfs: add ioctl ... |
3909 |
} |
0b246afa6 btrfs: root->fs_i... |
3910 3911 |
dir_id = btrfs_super_root_dir(fs_info->super_copy); di = btrfs_lookup_dir_item(trans, fs_info->tree_root, path, |
6ef5ed0d3 Btrfs: add ioctl ... |
3912 |
dir_id, "default", 7, 1); |
cf1e99a4e Btrfs: btrfs_look... |
3913 |
if (IS_ERR_OR_NULL(di)) { |
6ef5ed0d3 Btrfs: add ioctl ... |
3914 |
btrfs_free_path(path); |
3a45bb207 btrfs: remove roo... |
3915 |
btrfs_end_transaction(trans); |
0b246afa6 btrfs: root->fs_i... |
3916 |
btrfs_err(fs_info, |
5d163e0e6 btrfs: unsplit pr... |
3917 |
"Umm, you don't have the default diritem, this isn't going to work"); |
3c04ce010 Btrfs: get write ... |
3918 3919 |
ret = -ENOENT; goto out; |
6ef5ed0d3 Btrfs: add ioctl ... |
3920 3921 3922 3923 3924 3925 |
} 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); |
0b246afa6 btrfs: root->fs_i... |
3926 |
btrfs_set_fs_incompat(fs_info, DEFAULT_SUBVOL); |
3a45bb207 btrfs: remove roo... |
3927 |
btrfs_end_transaction(trans); |
3c04ce010 Btrfs: get write ... |
3928 3929 3930 |
out: mnt_drop_write_file(file); return ret; |
6ef5ed0d3 Btrfs: add ioctl ... |
3931 |
} |
5af3e8cce Btrfs: make files... |
3932 3933 |
void btrfs_get_block_group_info(struct list_head *groups_list, struct btrfs_ioctl_space_info *space) |
bf5fc093c Btrfs: fix the df... |
3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 |
{ 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); } } |
2ff7e61e0 btrfs: take an fs... |
3947 3948 |
static long btrfs_ioctl_space_info(struct btrfs_fs_info *fs_info, void __user *arg) |
1406e4327 Btrfs: add a "df"... |
3949 3950 3951 3952 |
{ struct btrfs_ioctl_space_args space_args; struct btrfs_ioctl_space_info space; struct btrfs_ioctl_space_info *dest; |
7fde62bff Btrfs: buffer res... |
3953 |
struct btrfs_ioctl_space_info *dest_orig; |
13f2696f1 fix user annotati... |
3954 |
struct btrfs_ioctl_space_info __user *user_dest; |
1406e4327 Btrfs: add a "df"... |
3955 |
struct btrfs_space_info *info; |
bf5fc093c Btrfs: fix the df... |
3956 3957 3958 3959 3960 |
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... |
3961 |
int alloc_size; |
1406e4327 Btrfs: add a "df"... |
3962 |
int ret = 0; |
51788b1bd btrfs: prevent he... |
3963 |
u64 slot_count = 0; |
bf5fc093c Btrfs: fix the df... |
3964 |
int i, c; |
1406e4327 Btrfs: add a "df"... |
3965 3966 3967 3968 3969 |
if (copy_from_user(&space_args, (struct btrfs_ioctl_space_args __user *)arg, sizeof(space_args))) return -EFAULT; |
bf5fc093c Btrfs: fix the df... |
3970 3971 3972 3973 3974 |
for (i = 0; i < num_types; i++) { struct btrfs_space_info *tmp; info = NULL; rcu_read_lock(); |
0b246afa6 btrfs: root->fs_i... |
3975 |
list_for_each_entry_rcu(tmp, &fs_info->space_info, |
bf5fc093c Btrfs: fix the df... |
3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 |
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... |
3994 |
|
36523e951 btrfs: export glo... |
3995 3996 3997 3998 |
/* * Global block reserve, exported as a space_info */ slot_count++; |
7fde62bff Btrfs: buffer res... |
3999 4000 4001 4002 4003 |
/* 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... |
4004 |
|
51788b1bd btrfs: prevent he... |
4005 |
slot_count = min_t(u64, space_args.space_slots, slot_count); |
bf5fc093c Btrfs: fix the df... |
4006 |
|
7fde62bff Btrfs: buffer res... |
4007 |
alloc_size = sizeof(*dest) * slot_count; |
bf5fc093c Btrfs: fix the df... |
4008 |
|
7fde62bff Btrfs: buffer res... |
4009 4010 4011 |
/* 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 */ |
09cbfeaf1 mm, fs: get rid o... |
4012 |
if (alloc_size > PAGE_SIZE) |
7fde62bff Btrfs: buffer res... |
4013 |
return -ENOMEM; |
1406e4327 Btrfs: add a "df"... |
4014 |
space_args.total_spaces = 0; |
8d2db7855 btrfs: use GFP_KE... |
4015 |
dest = kmalloc(alloc_size, GFP_KERNEL); |
7fde62bff Btrfs: buffer res... |
4016 4017 4018 |
if (!dest) return -ENOMEM; dest_orig = dest; |
1406e4327 Btrfs: add a "df"... |
4019 |
|
7fde62bff Btrfs: buffer res... |
4020 |
/* now we have a buffer to copy into */ |
bf5fc093c Btrfs: fix the df... |
4021 4022 |
for (i = 0; i < num_types; i++) { struct btrfs_space_info *tmp; |
51788b1bd btrfs: prevent he... |
4023 4024 |
if (!slot_count) break; |
bf5fc093c Btrfs: fix the df... |
4025 4026 |
info = NULL; rcu_read_lock(); |
0b246afa6 btrfs: root->fs_i... |
4027 |
list_for_each_entry_rcu(tmp, &fs_info->space_info, |
bf5fc093c Btrfs: fix the df... |
4028 4029 4030 4031 4032 4033 4034 |
list) { if (tmp->flags == types[i]) { info = tmp; break; } } rcu_read_unlock(); |
7fde62bff Btrfs: buffer res... |
4035 |
|
bf5fc093c Btrfs: fix the df... |
4036 4037 4038 4039 4040 |
if (!info) continue; down_read(&info->groups_sem); for (c = 0; c < BTRFS_NR_RAID_TYPES; c++) { if (!list_empty(&info->block_groups[c])) { |
5af3e8cce Btrfs: make files... |
4041 4042 |
btrfs_get_block_group_info( &info->block_groups[c], &space); |
bf5fc093c Btrfs: fix the df... |
4043 4044 4045 |
memcpy(dest, &space, sizeof(space)); dest++; space_args.total_spaces++; |
51788b1bd btrfs: prevent he... |
4046 |
slot_count--; |
bf5fc093c Btrfs: fix the df... |
4047 |
} |
51788b1bd btrfs: prevent he... |
4048 4049 |
if (!slot_count) break; |
bf5fc093c Btrfs: fix the df... |
4050 4051 |
} up_read(&info->groups_sem); |
1406e4327 Btrfs: add a "df"... |
4052 |
} |
1406e4327 Btrfs: add a "df"... |
4053 |
|
36523e951 btrfs: export glo... |
4054 4055 4056 4057 |
/* * Add global block reserve */ if (slot_count) { |
0b246afa6 btrfs: root->fs_i... |
4058 |
struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv; |
36523e951 btrfs: export glo... |
4059 4060 4061 4062 4063 4064 4065 4066 4067 |
spin_lock(&block_rsv->lock); space.total_bytes = block_rsv->size; space.used_bytes = block_rsv->size - block_rsv->reserved; spin_unlock(&block_rsv->lock); space.flags = BTRFS_SPACE_INFO_GLOBAL_RSV; memcpy(dest, &space, sizeof(space)); space_args.total_spaces++; } |
2eec6c810 Fix minor type is... |
4068 |
user_dest = (struct btrfs_ioctl_space_info __user *) |
7fde62bff Btrfs: buffer res... |
4069 4070 4071 4072 4073 4074 4075 4076 |
(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"... |
4077 4078 4079 4080 |
ret = -EFAULT; return ret; } |
f46b5a66b Btrfs: split out ... |
4081 4082 4083 4084 4085 4086 4087 4088 |
/* * 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) { |
496ad9aa8 new helper: file_... |
4089 |
struct inode *inode = file_inode(file); |
f46b5a66b Btrfs: split out ... |
4090 |
struct btrfs_root *root = BTRFS_I(inode)->root; |
23b5ec749 btrfs: fix readdi... |
4091 |
struct btrfs_file_private *private = file->private_data; |
f46b5a66b Btrfs: split out ... |
4092 |
|
23b5ec749 btrfs: fix readdi... |
4093 |
if (!private || !private->trans) |
1ab86aedb Btrfs: fix error ... |
4094 |
return -EINVAL; |
9ca9ee09c Btrfs: fix ioctl-... |
4095 |
|
23b5ec749 btrfs: fix readdi... |
4096 4097 |
btrfs_end_transaction(private->trans); private->trans = NULL; |
1ab86aedb Btrfs: fix error ... |
4098 |
|
a4abeea41 Btrfs: kill trans... |
4099 |
atomic_dec(&root->fs_info->open_ioctl_trans); |
9ca9ee09c Btrfs: fix ioctl-... |
4100 |
|
2a79f17e4 vfs: mnt_drop_wri... |
4101 |
mnt_drop_write_file(file); |
1ab86aedb Btrfs: fix error ... |
4102 |
return 0; |
f46b5a66b Btrfs: split out ... |
4103 |
} |
9a8c28bec Btrfs: pass root ... |
4104 4105 |
static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root, void __user *argp) |
462045928 Btrfs: add START_... |
4106 |
{ |
462045928 Btrfs: add START_... |
4107 4108 |
struct btrfs_trans_handle *trans; u64 transid; |
db5b493ac Btrfs: cleanup so... |
4109 |
int ret; |
462045928 Btrfs: add START_... |
4110 |
|
d4edf39bd Btrfs: fix uncomp... |
4111 |
trans = btrfs_attach_transaction_barrier(root); |
ff7c1d335 Btrfs: don't star... |
4112 4113 4114 4115 4116 4117 4118 4119 |
if (IS_ERR(trans)) { if (PTR_ERR(trans) != -ENOENT) return PTR_ERR(trans); /* No running transaction, don't bother */ transid = root->fs_info->last_trans_committed; goto out; } |
462045928 Btrfs: add START_... |
4120 |
transid = trans->transid; |
3a45bb207 btrfs: remove roo... |
4121 |
ret = btrfs_commit_transaction_async(trans, 0); |
8b2b2d3cb Btrfs: fix memory... |
4122 |
if (ret) { |
3a45bb207 btrfs: remove roo... |
4123 |
btrfs_end_transaction(trans); |
db5b493ac Btrfs: cleanup so... |
4124 |
return ret; |
8b2b2d3cb Btrfs: fix memory... |
4125 |
} |
ff7c1d335 Btrfs: don't star... |
4126 |
out: |
462045928 Btrfs: add START_... |
4127 4128 4129 4130 4131 |
if (argp) if (copy_to_user(argp, &transid, sizeof(transid))) return -EFAULT; return 0; } |
2ff7e61e0 btrfs: take an fs... |
4132 |
static noinline long btrfs_ioctl_wait_sync(struct btrfs_fs_info *fs_info, |
9a8c28bec Btrfs: pass root ... |
4133 |
void __user *argp) |
462045928 Btrfs: add START_... |
4134 |
{ |
462045928 Btrfs: add START_... |
4135 4136 4137 4138 4139 4140 4141 4142 |
u64 transid; if (argp) { if (copy_from_user(&transid, argp, sizeof(transid))) return -EFAULT; } else { transid = 0; /* current trans */ } |
2ff7e61e0 btrfs: take an fs... |
4143 |
return btrfs_wait_for_commit(fs_info, transid); |
462045928 Btrfs: add START_... |
4144 |
} |
b8e95489b Btrfs: get write ... |
4145 |
static long btrfs_ioctl_scrub(struct file *file, void __user *arg) |
475f63874 btrfs: new ioctls... |
4146 |
{ |
0b246afa6 btrfs: root->fs_i... |
4147 |
struct btrfs_fs_info *fs_info = btrfs_sb(file_inode(file)->i_sb); |
475f63874 btrfs: new ioctls... |
4148 |
struct btrfs_ioctl_scrub_args *sa; |
b8e95489b Btrfs: get write ... |
4149 |
int ret; |
475f63874 btrfs: new ioctls... |
4150 4151 4152 4153 4154 4155 4156 |
if (!capable(CAP_SYS_ADMIN)) return -EPERM; sa = memdup_user(arg, sizeof(*sa)); if (IS_ERR(sa)) return PTR_ERR(sa); |
b8e95489b Btrfs: get write ... |
4157 4158 4159 4160 4161 |
if (!(sa->flags & BTRFS_SCRUB_READONLY)) { ret = mnt_want_write_file(file); if (ret) goto out; } |
0b246afa6 btrfs: root->fs_i... |
4162 |
ret = btrfs_scrub_dev(fs_info, sa->devid, sa->start, sa->end, |
63a212abc Btrfs: disallow s... |
4163 4164 |
&sa->progress, sa->flags & BTRFS_SCRUB_READONLY, 0); |
475f63874 btrfs: new ioctls... |
4165 4166 4167 |
if (copy_to_user(arg, sa, sizeof(*sa))) ret = -EFAULT; |
b8e95489b Btrfs: get write ... |
4168 4169 4170 |
if (!(sa->flags & BTRFS_SCRUB_READONLY)) mnt_drop_write_file(file); out: |
475f63874 btrfs: new ioctls... |
4171 4172 4173 |
kfree(sa); return ret; } |
2ff7e61e0 btrfs: take an fs... |
4174 |
static long btrfs_ioctl_scrub_cancel(struct btrfs_fs_info *fs_info) |
475f63874 btrfs: new ioctls... |
4175 4176 4177 |
{ if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
2ff7e61e0 btrfs: take an fs... |
4178 |
return btrfs_scrub_cancel(fs_info); |
475f63874 btrfs: new ioctls... |
4179 |
} |
2ff7e61e0 btrfs: take an fs... |
4180 |
static long btrfs_ioctl_scrub_progress(struct btrfs_fs_info *fs_info, |
475f63874 btrfs: new ioctls... |
4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 |
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); |
2ff7e61e0 btrfs: take an fs... |
4192 |
ret = btrfs_scrub_progress(fs_info, sa->devid, &sa->progress); |
475f63874 btrfs: new ioctls... |
4193 4194 4195 4196 4197 4198 4199 |
if (copy_to_user(arg, sa, sizeof(*sa))) ret = -EFAULT; kfree(sa); return ret; } |
2ff7e61e0 btrfs: take an fs... |
4200 |
static long btrfs_ioctl_get_dev_stats(struct btrfs_fs_info *fs_info, |
b27f7c0c1 btrfs: join DEV_S... |
4201 |
void __user *arg) |
c11d2c236 Btrfs: add ioctl ... |
4202 4203 4204 |
{ struct btrfs_ioctl_get_dev_stats *sa; int ret; |
c11d2c236 Btrfs: add ioctl ... |
4205 4206 4207 |
sa = memdup_user(arg, sizeof(*sa)); if (IS_ERR(sa)) return PTR_ERR(sa); |
b27f7c0c1 btrfs: join DEV_S... |
4208 4209 4210 4211 |
if ((sa->flags & BTRFS_DEV_STATS_RESET) && !capable(CAP_SYS_ADMIN)) { kfree(sa); return -EPERM; } |
2ff7e61e0 btrfs: take an fs... |
4212 |
ret = btrfs_get_dev_stats(fs_info, sa); |
c11d2c236 Btrfs: add ioctl ... |
4213 4214 4215 4216 4217 4218 4219 |
if (copy_to_user(arg, sa, sizeof(*sa))) ret = -EFAULT; kfree(sa); return ret; } |
2ff7e61e0 btrfs: take an fs... |
4220 4221 |
static long btrfs_ioctl_dev_replace(struct btrfs_fs_info *fs_info, void __user *arg) |
3f6bcfbd4 Btrfs: add suppor... |
4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 |
{ struct btrfs_ioctl_dev_replace_args *p; int ret; if (!capable(CAP_SYS_ADMIN)) return -EPERM; p = memdup_user(arg, sizeof(*p)); if (IS_ERR(p)) return PTR_ERR(p); switch (p->cmd) { case BTRFS_IOCTL_DEV_REPLACE_CMD_START: |
bc98a42c1 VFS: Convert sb->... |
4235 |
if (sb_rdonly(fs_info->sb)) { |
adfa97cbd Btrfs: don't leak... |
4236 4237 4238 |
ret = -EROFS; goto out; } |
171938e52 btrfs: track excl... |
4239 |
if (test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)) { |
e57138b3e btrfs: return btr... |
4240 |
ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; |
3f6bcfbd4 Btrfs: add suppor... |
4241 |
} else { |
2ff7e61e0 btrfs: take an fs... |
4242 |
ret = btrfs_dev_replace_by_ioctl(fs_info, p); |
171938e52 btrfs: track excl... |
4243 |
clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags); |
3f6bcfbd4 Btrfs: add suppor... |
4244 4245 4246 |
} break; case BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS: |
0b246afa6 btrfs: root->fs_i... |
4247 |
btrfs_dev_replace_status(fs_info, p); |
3f6bcfbd4 Btrfs: add suppor... |
4248 4249 4250 |
ret = 0; break; case BTRFS_IOCTL_DEV_REPLACE_CMD_CANCEL: |
0b246afa6 btrfs: root->fs_i... |
4251 |
ret = btrfs_dev_replace_cancel(fs_info, p); |
3f6bcfbd4 Btrfs: add suppor... |
4252 4253 4254 4255 4256 4257 4258 4259 |
break; default: ret = -EINVAL; break; } if (copy_to_user(arg, p, sizeof(*p))) ret = -EFAULT; |
adfa97cbd Btrfs: don't leak... |
4260 |
out: |
3f6bcfbd4 Btrfs: add suppor... |
4261 4262 4263 |
kfree(p); return ret; } |
d7728c960 btrfs: new ioctls... |
4264 4265 4266 4267 |
static long btrfs_ioctl_ino_to_path(struct btrfs_root *root, void __user *arg) { int ret = 0; int i; |
740c3d226 Btrfs: fix the ne... |
4268 |
u64 rel_ptr; |
d7728c960 btrfs: new ioctls... |
4269 |
int size; |
806468f8b Merge git://git.j... |
4270 |
struct btrfs_ioctl_ino_path_args *ipa = NULL; |
d7728c960 btrfs: new ioctls... |
4271 4272 |
struct inode_fs_paths *ipath = NULL; struct btrfs_path *path; |
82b22ac8f Btrfs: Check CAP_... |
4273 |
if (!capable(CAP_DAC_READ_SEARCH)) |
d7728c960 btrfs: new ioctls... |
4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 |
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/... |
4302 4303 |
rel_ptr = ipath->fspath->val[i] - (u64)(unsigned long)ipath->fspath->val; |
740c3d226 Btrfs: fix the ne... |
4304 |
ipath->fspath->val[i] = rel_ptr; |
d7728c960 btrfs: new ioctls... |
4305 |
} |
745c4d8e1 btrfs: Fix up 32/... |
4306 4307 |
ret = copy_to_user((void *)(unsigned long)ipa->fspath, (void *)(unsigned long)ipath->fspath, size); |
d7728c960 btrfs: new ioctls... |
4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 |
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; } |
2ff7e61e0 btrfs: take an fs... |
4340 |
static long btrfs_ioctl_logical_to_ino(struct btrfs_fs_info *fs_info, |
d7728c960 btrfs: new ioctls... |
4341 4342 4343 4344 |
void __user *arg) { int ret = 0; int size; |
d7728c960 btrfs: new ioctls... |
4345 4346 4347 |
struct btrfs_ioctl_logical_ino_args *loi; struct btrfs_data_container *inodes = NULL; struct btrfs_path *path = NULL; |
d7728c960 btrfs: new ioctls... |
4348 4349 4350 4351 4352 |
if (!capable(CAP_SYS_ADMIN)) return -EPERM; loi = memdup_user(arg, sizeof(*loi)); |
7b9ea6279 btrfs: return ear... |
4353 4354 |
if (IS_ERR(loi)) return PTR_ERR(loi); |
d7728c960 btrfs: new ioctls... |
4355 4356 4357 4358 4359 4360 |
path = btrfs_alloc_path(); if (!path) { ret = -ENOMEM; goto out; } |
ee22184b5 Btrfs: use linux/... |
4361 |
size = min_t(u32, loi->size, SZ_64K); |
d7728c960 btrfs: new ioctls... |
4362 4363 4364 4365 4366 4367 |
inodes = init_data_container(size); if (IS_ERR(inodes)) { ret = PTR_ERR(inodes); inodes = NULL; goto out; } |
2ff7e61e0 btrfs: take an fs... |
4368 |
ret = iterate_inodes_from_logical(loi->logical, fs_info, path, |
df031f075 Btrfs: use helper... |
4369 4370 |
build_ino_list, inodes); if (ret == -EINVAL) |
d7728c960 btrfs: new ioctls... |
4371 4372 4373 |
ret = -ENOENT; if (ret < 0) goto out; |
745c4d8e1 btrfs: Fix up 32/... |
4374 4375 |
ret = copy_to_user((void *)(unsigned long)loi->inodes, (void *)(unsigned long)inodes, size); |
d7728c960 btrfs: new ioctls... |
4376 4377 4378 4379 4380 |
if (ret) ret = -EFAULT; out: btrfs_free_path(path); |
f54de068d btrfs: use GFP_KE... |
4381 |
kvfree(inodes); |
d7728c960 btrfs: new ioctls... |
4382 4383 4384 4385 |
kfree(loi); return ret; } |
19a39dce3 Btrfs: add balanc... |
4386 |
void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock, |
c9e9f97bd Btrfs: add basic ... |
4387 4388 4389 4390 4391 |
struct btrfs_ioctl_balance_args *bargs) { struct btrfs_balance_control *bctl = fs_info->balance_ctl; bargs->flags = bctl->flags; |
837d5b6e4 Btrfs: allow for ... |
4392 4393 4394 4395 |
if (atomic_read(&fs_info->balance_running)) bargs->state |= BTRFS_BALANCE_STATE_RUNNING; if (atomic_read(&fs_info->balance_pause_req)) bargs->state |= BTRFS_BALANCE_STATE_PAUSE_REQ; |
a7e99c691 Btrfs: allow for ... |
4396 4397 |
if (atomic_read(&fs_info->balance_cancel_req)) bargs->state |= BTRFS_BALANCE_STATE_CANCEL_REQ; |
837d5b6e4 Btrfs: allow for ... |
4398 |
|
c9e9f97bd Btrfs: add basic ... |
4399 4400 4401 |
memcpy(&bargs->data, &bctl->data, sizeof(bargs->data)); memcpy(&bargs->meta, &bctl->meta, sizeof(bargs->meta)); memcpy(&bargs->sys, &bctl->sys, sizeof(bargs->sys)); |
19a39dce3 Btrfs: add balanc... |
4402 4403 4404 4405 4406 4407 4408 4409 |
if (lock) { spin_lock(&fs_info->balance_lock); memcpy(&bargs->stat, &bctl->stat, sizeof(bargs->stat)); spin_unlock(&fs_info->balance_lock); } else { memcpy(&bargs->stat, &bctl->stat, sizeof(bargs->stat)); } |
c9e9f97bd Btrfs: add basic ... |
4410 |
} |
9ba1f6e44 Btrfs: do not do ... |
4411 |
static long btrfs_ioctl_balance(struct file *file, void __user *arg) |
c9e9f97bd Btrfs: add basic ... |
4412 |
{ |
496ad9aa8 new helper: file_... |
4413 |
struct btrfs_root *root = BTRFS_I(file_inode(file))->root; |
c9e9f97bd Btrfs: add basic ... |
4414 4415 4416 |
struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_ioctl_balance_args *bargs; struct btrfs_balance_control *bctl; |
ed0fb78fb Btrfs: bring back... |
4417 |
bool need_unlock; /* for mut. excl. ops lock */ |
c9e9f97bd Btrfs: add basic ... |
4418 4419 4420 4421 |
int ret; if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
e54bfa310 Btrfs: use mnt_wa... |
4422 |
ret = mnt_want_write_file(file); |
9ba1f6e44 Btrfs: do not do ... |
4423 4424 |
if (ret) return ret; |
ed0fb78fb Btrfs: bring back... |
4425 |
again: |
171938e52 btrfs: track excl... |
4426 |
if (!test_and_set_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)) { |
ed0fb78fb Btrfs: bring back... |
4427 4428 4429 4430 4431 4432 4433 |
mutex_lock(&fs_info->volume_mutex); mutex_lock(&fs_info->balance_mutex); need_unlock = true; goto locked; } /* |
013276101 btrfs: fix string... |
4434 |
* mut. excl. ops lock is locked. Three possibilities: |
ed0fb78fb Btrfs: bring back... |
4435 4436 4437 4438 |
* (1) some other op is running * (2) balance is running * (3) balance is paused -- special case (think resume) */ |
c9e9f97bd Btrfs: add basic ... |
4439 |
mutex_lock(&fs_info->balance_mutex); |
ed0fb78fb Btrfs: bring back... |
4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 |
if (fs_info->balance_ctl) { /* this is either (2) or (3) */ if (!atomic_read(&fs_info->balance_running)) { mutex_unlock(&fs_info->balance_mutex); if (!mutex_trylock(&fs_info->volume_mutex)) goto again; mutex_lock(&fs_info->balance_mutex); if (fs_info->balance_ctl && !atomic_read(&fs_info->balance_running)) { /* this is (3) */ need_unlock = false; goto locked; } mutex_unlock(&fs_info->balance_mutex); mutex_unlock(&fs_info->volume_mutex); goto again; } else { /* this is (2) */ mutex_unlock(&fs_info->balance_mutex); ret = -EINPROGRESS; goto out; } } else { /* this is (1) */ mutex_unlock(&fs_info->balance_mutex); |
e57138b3e btrfs: return btr... |
4467 |
ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; |
ed0fb78fb Btrfs: bring back... |
4468 4469 4470 4471 |
goto out; } locked: |
171938e52 btrfs: track excl... |
4472 |
BUG_ON(!test_bit(BTRFS_FS_EXCL_OP, &fs_info->flags)); |
c9e9f97bd Btrfs: add basic ... |
4473 4474 4475 4476 4477 |
if (arg) { bargs = memdup_user(arg, sizeof(*bargs)); if (IS_ERR(bargs)) { ret = PTR_ERR(bargs); |
ed0fb78fb Btrfs: bring back... |
4478 |
goto out_unlock; |
c9e9f97bd Btrfs: add basic ... |
4479 |
} |
de322263d Btrfs: allow for ... |
4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 |
if (bargs->flags & BTRFS_BALANCE_RESUME) { if (!fs_info->balance_ctl) { ret = -ENOTCONN; goto out_bargs; } bctl = fs_info->balance_ctl; spin_lock(&fs_info->balance_lock); bctl->flags |= BTRFS_BALANCE_RESUME; spin_unlock(&fs_info->balance_lock); goto do_balance; } |
c9e9f97bd Btrfs: add basic ... |
4494 4495 4496 |
} else { bargs = NULL; } |
ed0fb78fb Btrfs: bring back... |
4497 |
if (fs_info->balance_ctl) { |
837d5b6e4 Btrfs: allow for ... |
4498 4499 4500 |
ret = -EINPROGRESS; goto out_bargs; } |
8d2db7855 btrfs: use GFP_KE... |
4501 |
bctl = kzalloc(sizeof(*bctl), GFP_KERNEL); |
c9e9f97bd Btrfs: add basic ... |
4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 |
if (!bctl) { ret = -ENOMEM; goto out_bargs; } bctl->fs_info = fs_info; if (arg) { memcpy(&bctl->data, &bargs->data, sizeof(bctl->data)); memcpy(&bctl->meta, &bargs->meta, sizeof(bctl->meta)); memcpy(&bctl->sys, &bargs->sys, sizeof(bctl->sys)); bctl->flags = bargs->flags; |
f43ffb60f Btrfs: add basic ... |
4514 4515 4516 |
} else { /* balance everything - no filters */ bctl->flags |= BTRFS_BALANCE_TYPE_MASK; |
c9e9f97bd Btrfs: add basic ... |
4517 |
} |
8eb934591 btrfs: check unsu... |
4518 4519 |
if (bctl->flags & ~(BTRFS_BALANCE_ARGS_MASK | BTRFS_BALANCE_TYPE_MASK)) { ret = -EINVAL; |
0f89abf56 btrfs: fix possib... |
4520 |
goto out_bctl; |
8eb934591 btrfs: check unsu... |
4521 |
} |
de322263d Btrfs: allow for ... |
4522 |
do_balance: |
c9e9f97bd Btrfs: add basic ... |
4523 |
/* |
171938e52 btrfs: track excl... |
4524 |
* Ownership of bctl and filesystem flag BTRFS_FS_EXCL_OP |
ed0fb78fb Btrfs: bring back... |
4525 4526 |
* goes to to btrfs_balance. bctl is freed in __cancel_balance, * or, if restriper was paused all the way until unmount, in |
171938e52 btrfs: track excl... |
4527 |
* free_fs_info. The flag is cleared in __cancel_balance. |
c9e9f97bd Btrfs: add basic ... |
4528 |
*/ |
ed0fb78fb Btrfs: bring back... |
4529 4530 4531 |
need_unlock = false; ret = btrfs_balance(bctl, bargs); |
0f89abf56 btrfs: fix possib... |
4532 |
bctl = NULL; |
ed0fb78fb Btrfs: bring back... |
4533 |
|
c9e9f97bd Btrfs: add basic ... |
4534 4535 4536 4537 |
if (arg) { if (copy_to_user(arg, bargs, sizeof(*bargs))) ret = -EFAULT; } |
0f89abf56 btrfs: fix possib... |
4538 4539 |
out_bctl: kfree(bctl); |
c9e9f97bd Btrfs: add basic ... |
4540 4541 |
out_bargs: kfree(bargs); |
ed0fb78fb Btrfs: bring back... |
4542 |
out_unlock: |
c9e9f97bd Btrfs: add basic ... |
4543 4544 |
mutex_unlock(&fs_info->balance_mutex); mutex_unlock(&fs_info->volume_mutex); |
ed0fb78fb Btrfs: bring back... |
4545 |
if (need_unlock) |
171938e52 btrfs: track excl... |
4546 |
clear_bit(BTRFS_FS_EXCL_OP, &fs_info->flags); |
ed0fb78fb Btrfs: bring back... |
4547 |
out: |
e54bfa310 Btrfs: use mnt_wa... |
4548 |
mnt_drop_write_file(file); |
c9e9f97bd Btrfs: add basic ... |
4549 4550 |
return ret; } |
2ff7e61e0 btrfs: take an fs... |
4551 |
static long btrfs_ioctl_balance_ctl(struct btrfs_fs_info *fs_info, int cmd) |
837d5b6e4 Btrfs: allow for ... |
4552 4553 4554 4555 4556 4557 |
{ if (!capable(CAP_SYS_ADMIN)) return -EPERM; switch (cmd) { case BTRFS_BALANCE_CTL_PAUSE: |
0b246afa6 btrfs: root->fs_i... |
4558 |
return btrfs_pause_balance(fs_info); |
a7e99c691 Btrfs: allow for ... |
4559 |
case BTRFS_BALANCE_CTL_CANCEL: |
0b246afa6 btrfs: root->fs_i... |
4560 |
return btrfs_cancel_balance(fs_info); |
837d5b6e4 Btrfs: allow for ... |
4561 4562 4563 4564 |
} return -EINVAL; } |
2ff7e61e0 btrfs: take an fs... |
4565 |
static long btrfs_ioctl_balance_progress(struct btrfs_fs_info *fs_info, |
19a39dce3 Btrfs: add balanc... |
4566 4567 |
void __user *arg) { |
19a39dce3 Btrfs: add balanc... |
4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 |
struct btrfs_ioctl_balance_args *bargs; int ret = 0; if (!capable(CAP_SYS_ADMIN)) return -EPERM; mutex_lock(&fs_info->balance_mutex); if (!fs_info->balance_ctl) { ret = -ENOTCONN; goto out; } |
8d2db7855 btrfs: use GFP_KE... |
4579 |
bargs = kzalloc(sizeof(*bargs), GFP_KERNEL); |
19a39dce3 Btrfs: add balanc... |
4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 |
if (!bargs) { ret = -ENOMEM; goto out; } update_ioctl_balance_args(fs_info, 1, bargs); if (copy_to_user(arg, bargs, sizeof(*bargs))) ret = -EFAULT; kfree(bargs); out: mutex_unlock(&fs_info->balance_mutex); return ret; } |
905b0dda0 Btrfs: get write ... |
4595 |
static long btrfs_ioctl_quota_ctl(struct file *file, void __user *arg) |
5d13a37bd Btrfs: add qgroup... |
4596 |
{ |
0b246afa6 btrfs: root->fs_i... |
4597 4598 |
struct inode *inode = file_inode(file); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); |
5d13a37bd Btrfs: add qgroup... |
4599 4600 4601 4602 4603 4604 4605 |
struct btrfs_ioctl_quota_ctl_args *sa; struct btrfs_trans_handle *trans = NULL; int ret; int err; if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
905b0dda0 Btrfs: get write ... |
4606 4607 4608 |
ret = mnt_want_write_file(file); if (ret) return ret; |
5d13a37bd Btrfs: add qgroup... |
4609 4610 |
sa = memdup_user(arg, sizeof(*sa)); |
905b0dda0 Btrfs: get write ... |
4611 4612 4613 4614 |
if (IS_ERR(sa)) { ret = PTR_ERR(sa); goto drop_write; } |
5d13a37bd Btrfs: add qgroup... |
4615 |
|
0b246afa6 btrfs: root->fs_i... |
4616 4617 |
down_write(&fs_info->subvol_sem); trans = btrfs_start_transaction(fs_info->tree_root, 2); |
2f2320360 Btrfs: rescan for... |
4618 4619 4620 |
if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto out; |
5d13a37bd Btrfs: add qgroup... |
4621 4622 4623 4624 |
} switch (sa->cmd) { case BTRFS_QUOTA_CTL_ENABLE: |
0b246afa6 btrfs: root->fs_i... |
4625 |
ret = btrfs_quota_enable(trans, fs_info); |
5d13a37bd Btrfs: add qgroup... |
4626 4627 |
break; case BTRFS_QUOTA_CTL_DISABLE: |
0b246afa6 btrfs: root->fs_i... |
4628 |
ret = btrfs_quota_disable(trans, fs_info); |
5d13a37bd Btrfs: add qgroup... |
4629 |
break; |
5d13a37bd Btrfs: add qgroup... |
4630 4631 4632 4633 |
default: ret = -EINVAL; break; } |
3a45bb207 btrfs: remove roo... |
4634 |
err = btrfs_commit_transaction(trans); |
2f2320360 Btrfs: rescan for... |
4635 4636 |
if (err && !ret) ret = err; |
5d13a37bd Btrfs: add qgroup... |
4637 4638 |
out: kfree(sa); |
0b246afa6 btrfs: root->fs_i... |
4639 |
up_write(&fs_info->subvol_sem); |
905b0dda0 Btrfs: get write ... |
4640 4641 |
drop_write: mnt_drop_write_file(file); |
5d13a37bd Btrfs: add qgroup... |
4642 4643 |
return ret; } |
905b0dda0 Btrfs: get write ... |
4644 |
static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg) |
5d13a37bd Btrfs: add qgroup... |
4645 |
{ |
0b246afa6 btrfs: root->fs_i... |
4646 4647 4648 |
struct inode *inode = file_inode(file); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct btrfs_root *root = BTRFS_I(inode)->root; |
5d13a37bd Btrfs: add qgroup... |
4649 4650 4651 4652 4653 4654 4655 |
struct btrfs_ioctl_qgroup_assign_args *sa; struct btrfs_trans_handle *trans; int ret; int err; if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
905b0dda0 Btrfs: get write ... |
4656 4657 4658 |
ret = mnt_want_write_file(file); if (ret) return ret; |
5d13a37bd Btrfs: add qgroup... |
4659 4660 |
sa = memdup_user(arg, sizeof(*sa)); |
905b0dda0 Btrfs: get write ... |
4661 4662 4663 4664 |
if (IS_ERR(sa)) { ret = PTR_ERR(sa); goto drop_write; } |
5d13a37bd Btrfs: add qgroup... |
4665 4666 4667 4668 4669 4670 |
trans = btrfs_join_transaction(root); if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto out; } |
5d13a37bd Btrfs: add qgroup... |
4671 |
if (sa->assign) { |
0b246afa6 btrfs: root->fs_i... |
4672 |
ret = btrfs_add_qgroup_relation(trans, fs_info, |
5d13a37bd Btrfs: add qgroup... |
4673 4674 |
sa->src, sa->dst); } else { |
0b246afa6 btrfs: root->fs_i... |
4675 |
ret = btrfs_del_qgroup_relation(trans, fs_info, |
5d13a37bd Btrfs: add qgroup... |
4676 4677 |
sa->src, sa->dst); } |
e082f5631 btrfs: quota: Upd... |
4678 |
/* update qgroup status and info */ |
0b246afa6 btrfs: root->fs_i... |
4679 |
err = btrfs_run_qgroups(trans, fs_info); |
e082f5631 btrfs: quota: Upd... |
4680 |
if (err < 0) |
0b246afa6 btrfs: root->fs_i... |
4681 4682 |
btrfs_handle_fs_error(fs_info, err, "failed to update qgroup status and info"); |
3a45bb207 btrfs: remove roo... |
4683 |
err = btrfs_end_transaction(trans); |
5d13a37bd Btrfs: add qgroup... |
4684 4685 4686 4687 4688 |
if (err && !ret) ret = err; out: kfree(sa); |
905b0dda0 Btrfs: get write ... |
4689 4690 |
drop_write: mnt_drop_write_file(file); |
5d13a37bd Btrfs: add qgroup... |
4691 4692 |
return ret; } |
905b0dda0 Btrfs: get write ... |
4693 |
static long btrfs_ioctl_qgroup_create(struct file *file, void __user *arg) |
5d13a37bd Btrfs: add qgroup... |
4694 |
{ |
0b246afa6 btrfs: root->fs_i... |
4695 4696 4697 |
struct inode *inode = file_inode(file); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct btrfs_root *root = BTRFS_I(inode)->root; |
5d13a37bd Btrfs: add qgroup... |
4698 4699 4700 4701 4702 4703 4704 |
struct btrfs_ioctl_qgroup_create_args *sa; struct btrfs_trans_handle *trans; int ret; int err; if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
905b0dda0 Btrfs: get write ... |
4705 4706 4707 |
ret = mnt_want_write_file(file); if (ret) return ret; |
5d13a37bd Btrfs: add qgroup... |
4708 4709 |
sa = memdup_user(arg, sizeof(*sa)); |
905b0dda0 Btrfs: get write ... |
4710 4711 4712 4713 |
if (IS_ERR(sa)) { ret = PTR_ERR(sa); goto drop_write; } |
5d13a37bd Btrfs: add qgroup... |
4714 |
|
d86e56cf7 Btrfs: disable qg... |
4715 4716 4717 4718 |
if (!sa->qgroupid) { ret = -EINVAL; goto out; } |
5d13a37bd Btrfs: add qgroup... |
4719 4720 4721 4722 4723 |
trans = btrfs_join_transaction(root); if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto out; } |
5d13a37bd Btrfs: add qgroup... |
4724 |
if (sa->create) { |
0b246afa6 btrfs: root->fs_i... |
4725 |
ret = btrfs_create_qgroup(trans, fs_info, sa->qgroupid); |
5d13a37bd Btrfs: add qgroup... |
4726 |
} else { |
0b246afa6 btrfs: root->fs_i... |
4727 |
ret = btrfs_remove_qgroup(trans, fs_info, sa->qgroupid); |
5d13a37bd Btrfs: add qgroup... |
4728 |
} |
3a45bb207 btrfs: remove roo... |
4729 |
err = btrfs_end_transaction(trans); |
5d13a37bd Btrfs: add qgroup... |
4730 4731 4732 4733 4734 |
if (err && !ret) ret = err; out: kfree(sa); |
905b0dda0 Btrfs: get write ... |
4735 4736 |
drop_write: mnt_drop_write_file(file); |
5d13a37bd Btrfs: add qgroup... |
4737 4738 |
return ret; } |
905b0dda0 Btrfs: get write ... |
4739 |
static long btrfs_ioctl_qgroup_limit(struct file *file, void __user *arg) |
5d13a37bd Btrfs: add qgroup... |
4740 |
{ |
0b246afa6 btrfs: root->fs_i... |
4741 4742 4743 |
struct inode *inode = file_inode(file); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct btrfs_root *root = BTRFS_I(inode)->root; |
5d13a37bd Btrfs: add qgroup... |
4744 4745 4746 4747 4748 4749 4750 4751 |
struct btrfs_ioctl_qgroup_limit_args *sa; struct btrfs_trans_handle *trans; int ret; int err; u64 qgroupid; if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
905b0dda0 Btrfs: get write ... |
4752 4753 4754 |
ret = mnt_want_write_file(file); if (ret) return ret; |
5d13a37bd Btrfs: add qgroup... |
4755 4756 |
sa = memdup_user(arg, sizeof(*sa)); |
905b0dda0 Btrfs: get write ... |
4757 4758 4759 4760 |
if (IS_ERR(sa)) { ret = PTR_ERR(sa); goto drop_write; } |
5d13a37bd Btrfs: add qgroup... |
4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 |
trans = btrfs_join_transaction(root); if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto out; } qgroupid = sa->qgroupid; if (!qgroupid) { /* take the current subvol as qgroup */ qgroupid = root->root_key.objectid; } |
0b246afa6 btrfs: root->fs_i... |
4773 |
ret = btrfs_limit_qgroup(trans, fs_info, qgroupid, &sa->lim); |
5d13a37bd Btrfs: add qgroup... |
4774 |
|
3a45bb207 btrfs: remove roo... |
4775 |
err = btrfs_end_transaction(trans); |
5d13a37bd Btrfs: add qgroup... |
4776 4777 4778 4779 4780 |
if (err && !ret) ret = err; out: kfree(sa); |
905b0dda0 Btrfs: get write ... |
4781 4782 |
drop_write: mnt_drop_write_file(file); |
5d13a37bd Btrfs: add qgroup... |
4783 4784 |
return ret; } |
2f2320360 Btrfs: rescan for... |
4785 4786 |
static long btrfs_ioctl_quota_rescan(struct file *file, void __user *arg) { |
0b246afa6 btrfs: root->fs_i... |
4787 4788 |
struct inode *inode = file_inode(file); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); |
2f2320360 Btrfs: rescan for... |
4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 |
struct btrfs_ioctl_quota_rescan_args *qsa; int ret; if (!capable(CAP_SYS_ADMIN)) return -EPERM; ret = mnt_want_write_file(file); if (ret) return ret; qsa = memdup_user(arg, sizeof(*qsa)); if (IS_ERR(qsa)) { ret = PTR_ERR(qsa); goto drop_write; } if (qsa->flags) { ret = -EINVAL; goto out; } |
0b246afa6 btrfs: root->fs_i... |
4809 |
ret = btrfs_qgroup_rescan(fs_info); |
2f2320360 Btrfs: rescan for... |
4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 |
out: kfree(qsa); drop_write: mnt_drop_write_file(file); return ret; } static long btrfs_ioctl_quota_rescan_status(struct file *file, void __user *arg) { |
0b246afa6 btrfs: root->fs_i... |
4820 4821 |
struct inode *inode = file_inode(file); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); |
2f2320360 Btrfs: rescan for... |
4822 4823 4824 4825 4826 |
struct btrfs_ioctl_quota_rescan_args *qsa; int ret = 0; if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
8d2db7855 btrfs: use GFP_KE... |
4827 |
qsa = kzalloc(sizeof(*qsa), GFP_KERNEL); |
2f2320360 Btrfs: rescan for... |
4828 4829 |
if (!qsa) return -ENOMEM; |
0b246afa6 btrfs: root->fs_i... |
4830 |
if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) { |
2f2320360 Btrfs: rescan for... |
4831 |
qsa->flags = 1; |
0b246afa6 btrfs: root->fs_i... |
4832 |
qsa->progress = fs_info->qgroup_rescan_progress.objectid; |
2f2320360 Btrfs: rescan for... |
4833 4834 4835 4836 4837 4838 4839 4840 |
} if (copy_to_user(arg, qsa, sizeof(*qsa))) ret = -EFAULT; kfree(qsa); return ret; } |
57254b6eb Btrfs: add ioctl ... |
4841 4842 |
static long btrfs_ioctl_quota_rescan_wait(struct file *file, void __user *arg) { |
0b246afa6 btrfs: root->fs_i... |
4843 4844 |
struct inode *inode = file_inode(file); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); |
57254b6eb Btrfs: add ioctl ... |
4845 4846 4847 |
if (!capable(CAP_SYS_ADMIN)) return -EPERM; |
0b246afa6 btrfs: root->fs_i... |
4848 |
return btrfs_qgroup_wait_for_completion(fs_info, true); |
57254b6eb Btrfs: add ioctl ... |
4849 |
} |
abccd00f8 btrfs: Fix 32/64-... |
4850 4851 |
static long _btrfs_ioctl_set_received_subvol(struct file *file, struct btrfs_ioctl_received_subvol_args *sa) |
8ea05e3a4 Btrfs: introduce ... |
4852 |
{ |
496ad9aa8 new helper: file_... |
4853 |
struct inode *inode = file_inode(file); |
0b246afa6 btrfs: root->fs_i... |
4854 |
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); |
8ea05e3a4 Btrfs: introduce ... |
4855 4856 4857 |
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root_item *root_item = &root->root_item; struct btrfs_trans_handle *trans; |
c2050a454 fs: Replace curre... |
4858 |
struct timespec ct = current_time(inode); |
8ea05e3a4 Btrfs: introduce ... |
4859 |
int ret = 0; |
dd5f9615f Btrfs: maintain s... |
4860 |
int received_uuid_changed; |
8ea05e3a4 Btrfs: introduce ... |
4861 |
|
bd60ea0fe btrfs: call permi... |
4862 4863 |
if (!inode_owner_or_capable(inode)) return -EPERM; |
8ea05e3a4 Btrfs: introduce ... |
4864 4865 4866 |
ret = mnt_want_write_file(file); if (ret < 0) return ret; |
0b246afa6 btrfs: root->fs_i... |
4867 |
down_write(&fs_info->subvol_sem); |
8ea05e3a4 Btrfs: introduce ... |
4868 |
|
4a0cc7ca6 btrfs: Make btrfs... |
4869 |
if (btrfs_ino(BTRFS_I(inode)) != BTRFS_FIRST_FREE_OBJECTID) { |
8ea05e3a4 Btrfs: introduce ... |
4870 4871 4872 4873 4874 4875 4876 4877 |
ret = -EINVAL; goto out; } if (btrfs_root_readonly(root)) { ret = -EROFS; goto out; } |
dd5f9615f Btrfs: maintain s... |
4878 4879 4880 4881 4882 |
/* * 1 - root item * 2 - uuid items (received uuid + subvol uuid) */ trans = btrfs_start_transaction(root, 3); |
8ea05e3a4 Btrfs: introduce ... |
4883 4884 4885 4886 4887 4888 4889 4890 4891 |
if (IS_ERR(trans)) { ret = PTR_ERR(trans); trans = NULL; goto out; } sa->rtransid = trans->transid; sa->rtime.sec = ct.tv_sec; sa->rtime.nsec = ct.tv_nsec; |
dd5f9615f Btrfs: maintain s... |
4892 4893 4894 4895 |
received_uuid_changed = memcmp(root_item->received_uuid, sa->uuid, BTRFS_UUID_SIZE); if (received_uuid_changed && !btrfs_is_empty_uuid(root_item->received_uuid)) |
0b246afa6 btrfs: root->fs_i... |
4896 |
btrfs_uuid_tree_rem(trans, fs_info, root_item->received_uuid, |
dd5f9615f Btrfs: maintain s... |
4897 4898 |
BTRFS_UUID_KEY_RECEIVED_SUBVOL, root->root_key.objectid); |
8ea05e3a4 Btrfs: introduce ... |
4899 4900 4901 |
memcpy(root_item->received_uuid, sa->uuid, BTRFS_UUID_SIZE); btrfs_set_root_stransid(root_item, sa->stransid); btrfs_set_root_rtransid(root_item, sa->rtransid); |
3cae210fa btrfs: Cleanup fo... |
4902 4903 4904 4905 |
btrfs_set_stack_timespec_sec(&root_item->stime, sa->stime.sec); btrfs_set_stack_timespec_nsec(&root_item->stime, sa->stime.nsec); btrfs_set_stack_timespec_sec(&root_item->rtime, sa->rtime.sec); btrfs_set_stack_timespec_nsec(&root_item->rtime, sa->rtime.nsec); |
8ea05e3a4 Btrfs: introduce ... |
4906 |
|
0b246afa6 btrfs: root->fs_i... |
4907 |
ret = btrfs_update_root(trans, fs_info->tree_root, |
8ea05e3a4 Btrfs: introduce ... |
4908 4909 |
&root->root_key, &root->root_item); if (ret < 0) { |
3a45bb207 btrfs: remove roo... |
4910 |
btrfs_end_transaction(trans); |
8ea05e3a4 Btrfs: introduce ... |
4911 |
goto out; |
dd5f9615f Btrfs: maintain s... |
4912 4913 |
} if (received_uuid_changed && !btrfs_is_empty_uuid(sa->uuid)) { |
0b246afa6 btrfs: root->fs_i... |
4914 |
ret = btrfs_uuid_tree_add(trans, fs_info, sa->uuid, |
dd5f9615f Btrfs: maintain s... |
4915 4916 4917 |
BTRFS_UUID_KEY_RECEIVED_SUBVOL, root->root_key.objectid); if (ret < 0 && ret != -EEXIST) { |
66642832f btrfs: btrfs_abor... |
4918 |
btrfs_abort_transaction(trans, ret); |
8ea05e3a4 Btrfs: introduce ... |
4919 |
goto out; |
dd5f9615f Btrfs: maintain s... |
4920 4921 |
} } |
3a45bb207 btrfs: remove roo... |
4922 |
ret = btrfs_commit_transaction(trans); |
dd5f9615f Btrfs: maintain s... |
4923 |
if (ret < 0) { |
66642832f btrfs: btrfs_abor... |
4924 |
btrfs_abort_transaction(trans, ret); |
dd5f9615f Btrfs: maintain s... |
4925 |
goto out; |
8ea05e3a4 Btrfs: introduce ... |
4926 |
} |
abccd00f8 btrfs: Fix 32/64-... |
4927 |
out: |
0b246afa6 btrfs: root->fs_i... |
4928 |
up_write(&fs_info->subvol_sem); |
abccd00f8 btrfs: Fix 32/64-... |
4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 |
mnt_drop_write_file(file); return ret; } #ifdef CONFIG_64BIT static long btrfs_ioctl_set_received_subvol_32(struct file *file, void __user *arg) { struct btrfs_ioctl_received_subvol_args_32 *args32 = NULL; struct btrfs_ioctl_received_subvol_args *args64 = NULL; int ret = 0; args32 = memdup_user(arg, sizeof(*args32)); |
7b9ea6279 btrfs: return ear... |
4942 4943 |
if (IS_ERR(args32)) return PTR_ERR(args32); |
abccd00f8 btrfs: Fix 32/64-... |
4944 |
|
8d2db7855 btrfs: use GFP_KE... |
4945 |
args64 = kmalloc(sizeof(*args64), GFP_KERNEL); |
84dbeb87d Btrfs: kmalloc() ... |
4946 4947 |
if (!args64) { ret = -ENOMEM; |
abccd00f8 btrfs: Fix 32/64-... |
4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 |
goto out; } memcpy(args64->uuid, args32->uuid, BTRFS_UUID_SIZE); args64->stransid = args32->stransid; args64->rtransid = args32->rtransid; args64->stime.sec = args32->stime.sec; args64->stime.nsec = args32->stime.nsec; args64->rtime.sec = args32->rtime.sec; args64->rtime.nsec = args32->rtime.nsec; args64->flags = args32->flags; ret = _btrfs_ioctl_set_received_subvol(file, args64); if (ret) goto out; memcpy(args32->uuid, args64->uuid, BTRFS_UUID_SIZE); args32->stransid = args64->stransid; args32->rtransid = args64->rtransid; args32->stime.sec = args64->stime.sec; args32->stime.nsec = args64->stime.nsec; args32->rtime.sec = args64->rtime.sec; args32->rtime.nsec = args64->rtime.nsec; args32->flags = args64->flags; ret = copy_to_user(arg, args32, sizeof(*args32)); if (ret) ret = -EFAULT; out: kfree(args32); kfree(args64); return ret; } #endif static long btrfs_ioctl_set_received_subvol(struct file *file, void __user *arg) { struct btrfs_ioctl_received_subvol_args *sa = NULL; int ret = 0; sa = memdup_user(arg, sizeof(*sa)); |
7b9ea6279 btrfs: return ear... |
4991 4992 |
if (IS_ERR(sa)) return PTR_ERR(sa); |
abccd00f8 btrfs: Fix 32/64-... |
4993 4994 4995 4996 4997 |
ret = _btrfs_ioctl_set_received_subvol(file, sa); if (ret) goto out; |
8ea05e3a4 Btrfs: introduce ... |
4998 4999 5000 5001 5002 5003 |
ret = copy_to_user(arg, sa, sizeof(*sa)); if (ret) ret = -EFAULT; out: kfree(sa); |
8ea05e3a4 Btrfs: introduce ... |
5004 5005 |
return ret; } |
867ab667e Btrfs: Add a new ... |
5006 5007 |
static int btrfs_ioctl_get_fslabel(struct file *file, void __user *arg) { |
0b246afa6 btrfs: root->fs_i... |
5008 5009 |
struct inode *inode = file_inode(file); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); |
a1b83ac52 btrfs: fix get se... |
5010 |
size_t len; |
867ab667e Btrfs: Add a new ... |
5011 |
int ret; |
a1b83ac52 btrfs: fix get se... |
5012 |
char label[BTRFS_LABEL_SIZE]; |
0b246afa6 btrfs: root->fs_i... |
5013 5014 5015 |
spin_lock(&fs_info->super_lock); memcpy(label, fs_info->super_copy->label, BTRFS_LABEL_SIZE); spin_unlock(&fs_info->super_lock); |
a1b83ac52 btrfs: fix get se... |
5016 5017 |
len = strnlen(label, BTRFS_LABEL_SIZE); |
867ab667e Btrfs: Add a new ... |
5018 5019 |
if (len == BTRFS_LABEL_SIZE) { |
0b246afa6 btrfs: root->fs_i... |
5020 5021 5022 |
btrfs_warn(fs_info, "label is too long, return the first %zu bytes", --len); |
867ab667e Btrfs: Add a new ... |
5023 |
} |
867ab667e Btrfs: Add a new ... |
5024 |
ret = copy_to_user(arg, label, len); |
867ab667e Btrfs: Add a new ... |
5025 5026 5027 |
return ret ? -EFAULT : 0; } |
a8bfd4abe Btrfs: set/change... |
5028 5029 |
static int btrfs_ioctl_set_fslabel(struct file *file, void __user *arg) { |
0b246afa6 btrfs: root->fs_i... |
5030 5031 5032 5033 |
struct inode *inode = file_inode(file); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_super_block *super_block = fs_info->super_copy; |
a8bfd4abe Btrfs: set/change... |
5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 |
struct btrfs_trans_handle *trans; char label[BTRFS_LABEL_SIZE]; int ret; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user(label, arg, sizeof(label))) return -EFAULT; if (strnlen(label, BTRFS_LABEL_SIZE) == BTRFS_LABEL_SIZE) { |
0b246afa6 btrfs: root->fs_i... |
5045 |
btrfs_err(fs_info, |
5d163e0e6 btrfs: unsplit pr... |
5046 5047 |
"unable to set label with more than %d bytes", BTRFS_LABEL_SIZE - 1); |
a8bfd4abe Btrfs: set/change... |
5048 5049 5050 5051 5052 5053 |
return -EINVAL; } ret = mnt_want_write_file(file); if (ret) return ret; |
a8bfd4abe Btrfs: set/change... |
5054 5055 5056 5057 5058 |
trans = btrfs_start_transaction(root, 0); if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto out_unlock; } |
0b246afa6 btrfs: root->fs_i... |
5059 |
spin_lock(&fs_info->super_lock); |
a8bfd4abe Btrfs: set/change... |
5060 |
strcpy(super_block->label, label); |
0b246afa6 btrfs: root->fs_i... |
5061 |
spin_unlock(&fs_info->super_lock); |
3a45bb207 btrfs: remove roo... |
5062 |
ret = btrfs_commit_transaction(trans); |
a8bfd4abe Btrfs: set/change... |
5063 5064 |
out_unlock: |
a8bfd4abe Btrfs: set/change... |
5065 5066 5067 |
mnt_drop_write_file(file); return ret; } |
2eaa055fa btrfs: add ioctls... |
5068 5069 5070 5071 |
#define INIT_FEATURE_FLAGS(suffix) \ { .compat_flags = BTRFS_FEATURE_COMPAT_##suffix, \ .compat_ro_flags = BTRFS_FEATURE_COMPAT_RO_##suffix, \ .incompat_flags = BTRFS_FEATURE_INCOMPAT_##suffix } |
d5131b658 btrfs: drop unuse... |
5072 |
int btrfs_ioctl_get_supported_features(void __user *arg) |
2eaa055fa btrfs: add ioctls... |
5073 |
{ |
4d4ab6d6b btrfs: constify s... |
5074 |
static const struct btrfs_ioctl_feature_flags features[3] = { |
2eaa055fa btrfs: add ioctls... |
5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 |
INIT_FEATURE_FLAGS(SUPP), INIT_FEATURE_FLAGS(SAFE_SET), INIT_FEATURE_FLAGS(SAFE_CLEAR) }; if (copy_to_user(arg, &features, sizeof(features))) return -EFAULT; return 0; } static int btrfs_ioctl_get_features(struct file *file, void __user *arg) { |
0b246afa6 btrfs: root->fs_i... |
5088 5089 5090 |
struct inode *inode = file_inode(file); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct btrfs_super_block *super_block = fs_info->super_copy; |
2eaa055fa btrfs: add ioctls... |
5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 |
struct btrfs_ioctl_feature_flags features; features.compat_flags = btrfs_super_compat_flags(super_block); features.compat_ro_flags = btrfs_super_compat_ro_flags(super_block); features.incompat_flags = btrfs_super_incompat_flags(super_block); if (copy_to_user(arg, &features, sizeof(features))) return -EFAULT; return 0; } |
2ff7e61e0 btrfs: take an fs... |
5102 |
static int check_feature_bits(struct btrfs_fs_info *fs_info, |
3b02a68a6 btrfs: use featur... |
5103 |
enum btrfs_feature_set set, |
2eaa055fa btrfs: add ioctls... |
5104 5105 5106 |
u64 change_mask, u64 flags, u64 supported_flags, u64 safe_set, u64 safe_clear) { |
3b02a68a6 btrfs: use featur... |
5107 5108 |
const char *type = btrfs_feature_set_names[set]; char *names; |
2eaa055fa btrfs: add ioctls... |
5109 5110 5111 5112 5113 5114 |
u64 disallowed, unsupported; u64 set_mask = flags & change_mask; u64 clear_mask = ~flags & change_mask; unsupported = set_mask & ~supported_flags; if (unsupported) { |
3b02a68a6 btrfs: use featur... |
5115 5116 |
names = btrfs_printable_features(set, unsupported); if (names) { |
0b246afa6 btrfs: root->fs_i... |
5117 5118 5119 |
btrfs_warn(fs_info, "this kernel does not support the %s feature bit%s", names, strchr(names, ',') ? "s" : ""); |
3b02a68a6 btrfs: use featur... |
5120 5121 |
kfree(names); } else |
0b246afa6 btrfs: root->fs_i... |
5122 5123 5124 |
btrfs_warn(fs_info, "this kernel does not support %s bits 0x%llx", type, unsupported); |
2eaa055fa btrfs: add ioctls... |
5125 5126 5127 5128 5129 |
return -EOPNOTSUPP; } disallowed = set_mask & ~safe_set; if (disallowed) { |
3b02a68a6 btrfs: use featur... |
5130 5131 |
names = btrfs_printable_features(set, disallowed); if (names) { |
0b246afa6 btrfs: root->fs_i... |
5132 5133 5134 |
btrfs_warn(fs_info, "can't set the %s feature bit%s while mounted", names, strchr(names, ',') ? "s" : ""); |
3b02a68a6 btrfs: use featur... |
5135 5136 |
kfree(names); } else |
0b246afa6 btrfs: root->fs_i... |
5137 5138 5139 |
btrfs_warn(fs_info, "can't set %s bits 0x%llx while mounted", type, disallowed); |
2eaa055fa btrfs: add ioctls... |
5140 5141 5142 5143 5144 |
return -EPERM; } disallowed = clear_mask & ~safe_clear; if (disallowed) { |
3b02a68a6 btrfs: use featur... |
5145 5146 |
names = btrfs_printable_features(set, disallowed); if (names) { |
0b246afa6 btrfs: root->fs_i... |
5147 5148 5149 |
btrfs_warn(fs_info, "can't clear the %s feature bit%s while mounted", names, strchr(names, ',') ? "s" : ""); |
3b02a68a6 btrfs: use featur... |
5150 5151 |
kfree(names); } else |
0b246afa6 btrfs: root->fs_i... |
5152 5153 5154 |
btrfs_warn(fs_info, "can't clear %s bits 0x%llx while mounted", type, disallowed); |
2eaa055fa btrfs: add ioctls... |
5155 5156 5157 5158 5159 |
return -EPERM; } return 0; } |
2ff7e61e0 btrfs: take an fs... |
5160 5161 |
#define check_feature(fs_info, change_mask, flags, mask_base) \ check_feature_bits(fs_info, FEAT_##mask_base, change_mask, flags, \ |
2eaa055fa btrfs: add ioctls... |
5162 5163 5164 5165 5166 5167 |
BTRFS_FEATURE_ ## mask_base ## _SUPP, \ BTRFS_FEATURE_ ## mask_base ## _SAFE_SET, \ BTRFS_FEATURE_ ## mask_base ## _SAFE_CLEAR) static int btrfs_ioctl_set_features(struct file *file, void __user *arg) { |
0b246afa6 btrfs: root->fs_i... |
5168 5169 5170 5171 |
struct inode *inode = file_inode(file); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_super_block *super_block = fs_info->super_copy; |
2eaa055fa btrfs: add ioctls... |
5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 |
struct btrfs_ioctl_feature_flags flags[2]; struct btrfs_trans_handle *trans; u64 newflags; int ret; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user(flags, arg, sizeof(flags))) return -EFAULT; /* Nothing to do */ if (!flags[0].compat_flags && !flags[0].compat_ro_flags && !flags[0].incompat_flags) return 0; |
2ff7e61e0 btrfs: take an fs... |
5187 |
ret = check_feature(fs_info, flags[0].compat_flags, |
2eaa055fa btrfs: add ioctls... |
5188 5189 5190 |
flags[1].compat_flags, COMPAT); if (ret) return ret; |
2ff7e61e0 btrfs: take an fs... |
5191 |
ret = check_feature(fs_info, flags[0].compat_ro_flags, |
2eaa055fa btrfs: add ioctls... |
5192 5193 5194 |
flags[1].compat_ro_flags, COMPAT_RO); if (ret) return ret; |
2ff7e61e0 btrfs: take an fs... |
5195 |
ret = check_feature(fs_info, flags[0].incompat_flags, |
2eaa055fa btrfs: add ioctls... |
5196 5197 5198 |
flags[1].incompat_flags, INCOMPAT); if (ret) return ret; |
7ab19625a btrfs: add write ... |
5199 5200 5201 |
ret = mnt_want_write_file(file); if (ret) return ret; |
8051aa1a3 btrfs: reserve no... |
5202 |
trans = btrfs_start_transaction(root, 0); |
7ab19625a btrfs: add write ... |
5203 5204 5205 5206 |
if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto out_drop_write; } |
2eaa055fa btrfs: add ioctls... |
5207 |
|
0b246afa6 btrfs: root->fs_i... |
5208 |
spin_lock(&fs_info->super_lock); |
2eaa055fa btrfs: add ioctls... |
5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 |
newflags = btrfs_super_compat_flags(super_block); newflags |= flags[0].compat_flags & flags[1].compat_flags; newflags &= ~(flags[0].compat_flags & ~flags[1].compat_flags); btrfs_set_super_compat_flags(super_block, newflags); newflags = btrfs_super_compat_ro_flags(super_block); newflags |= flags[0].compat_ro_flags & flags[1].compat_ro_flags; newflags &= ~(flags[0].compat_ro_flags & ~flags[1].compat_ro_flags); btrfs_set_super_compat_ro_flags(super_block, newflags); newflags = btrfs_super_incompat_flags(super_block); newflags |= flags[0].incompat_flags & flags[1].incompat_flags; newflags &= ~(flags[0].incompat_flags & ~flags[1].incompat_flags); btrfs_set_super_incompat_flags(super_block, newflags); |
0b246afa6 btrfs: root->fs_i... |
5223 |
spin_unlock(&fs_info->super_lock); |
2eaa055fa btrfs: add ioctls... |
5224 |
|
3a45bb207 btrfs: remove roo... |
5225 |
ret = btrfs_commit_transaction(trans); |
7ab19625a btrfs: add write ... |
5226 5227 5228 5229 |
out_drop_write: mnt_drop_write_file(file); return ret; |
2eaa055fa btrfs: add ioctls... |
5230 |
} |
f46b5a66b Btrfs: split out ... |
5231 5232 5233 |
long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { |
0b246afa6 btrfs: root->fs_i... |
5234 5235 5236 |
struct inode *inode = file_inode(file); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct btrfs_root *root = BTRFS_I(inode)->root; |
4bcabaa30 Btrfs: clean up b... |
5237 |
void __user *argp = (void __user *)arg; |
f46b5a66b Btrfs: split out ... |
5238 5239 |
switch (cmd) { |
6cbff00f4 Btrfs: implement ... |
5240 5241 5242 5243 5244 5245 |
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_... |
5246 5247 |
case FITRIM: return btrfs_ioctl_fitrim(file, argp); |
f46b5a66b Btrfs: split out ... |
5248 |
case BTRFS_IOC_SNAP_CREATE: |
fa0d2b9bd Btrfs: Refactor b... |
5249 |
return btrfs_ioctl_snap_create(file, argp, 0); |
fdfb1e4f6 Btrfs: Make async... |
5250 |
case BTRFS_IOC_SNAP_CREATE_V2: |
fa0d2b9bd Btrfs: Refactor b... |
5251 |
return btrfs_ioctl_snap_create_v2(file, argp, 0); |
3de4586c5 Btrfs: Allow subv... |
5252 |
case BTRFS_IOC_SUBVOL_CREATE: |
fa0d2b9bd Btrfs: Refactor b... |
5253 |
return btrfs_ioctl_snap_create(file, argp, 1); |
6f72c7e20 Btrfs: add qgroup... |
5254 5255 |
case BTRFS_IOC_SUBVOL_CREATE_V2: return btrfs_ioctl_snap_create_v2(file, argp, 1); |
76dda93c6 Btrfs: add snapsh... |
5256 5257 |
case BTRFS_IOC_SNAP_DESTROY: return btrfs_ioctl_snap_destroy(file, argp); |
0caa102da Btrfs: Add BTRFS_... |
5258 5259 5260 5261 |
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 ... |
5262 5263 |
case BTRFS_IOC_DEFAULT_SUBVOL: return btrfs_ioctl_default_subvol(file, argp); |
f46b5a66b Btrfs: split out ... |
5264 |
case BTRFS_IOC_DEFRAG: |
1e701a329 Btrfs: add new de... |
5265 5266 5267 |
return btrfs_ioctl_defrag(file, NULL); case BTRFS_IOC_DEFRAG_RANGE: return btrfs_ioctl_defrag(file, argp); |
f46b5a66b Btrfs: split out ... |
5268 |
case BTRFS_IOC_RESIZE: |
198605a8e Btrfs: get write ... |
5269 |
return btrfs_ioctl_resize(file, argp); |
f46b5a66b Btrfs: split out ... |
5270 |
case BTRFS_IOC_ADD_DEV: |
2ff7e61e0 btrfs: take an fs... |
5271 |
return btrfs_ioctl_add_dev(fs_info, argp); |
f46b5a66b Btrfs: split out ... |
5272 |
case BTRFS_IOC_RM_DEV: |
da24927b1 Btrfs: get write ... |
5273 |
return btrfs_ioctl_rm_dev(file, argp); |
6b526ed70 btrfs: introduce ... |
5274 5275 |
case BTRFS_IOC_RM_DEV_V2: return btrfs_ioctl_rm_dev_v2(file, argp); |
475f63874 btrfs: new ioctls... |
5276 |
case BTRFS_IOC_FS_INFO: |
2ff7e61e0 btrfs: take an fs... |
5277 |
return btrfs_ioctl_fs_info(fs_info, argp); |
475f63874 btrfs: new ioctls... |
5278 |
case BTRFS_IOC_DEV_INFO: |
2ff7e61e0 btrfs: take an fs... |
5279 |
return btrfs_ioctl_dev_info(fs_info, argp); |
f46b5a66b Btrfs: split out ... |
5280 |
case BTRFS_IOC_BALANCE: |
9ba1f6e44 Btrfs: do not do ... |
5281 |
return btrfs_ioctl_balance(file, NULL); |
f46b5a66b Btrfs: split out ... |
5282 5283 5284 5285 |
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... |
5286 5287 |
case BTRFS_IOC_TREE_SEARCH: return btrfs_ioctl_tree_search(file, argp); |
cc68a8a5a btrfs: new ioctl ... |
5288 5289 |
case BTRFS_IOC_TREE_SEARCH_V2: return btrfs_ioctl_tree_search_v2(file, argp); |
ac8e9819d Btrfs: add search... |
5290 5291 |
case BTRFS_IOC_INO_LOOKUP: return btrfs_ioctl_ino_lookup(file, argp); |
d7728c960 btrfs: new ioctls... |
5292 5293 5294 |
case BTRFS_IOC_INO_PATHS: return btrfs_ioctl_ino_to_path(root, argp); case BTRFS_IOC_LOGICAL_INO: |
2ff7e61e0 btrfs: take an fs... |
5295 |
return btrfs_ioctl_logical_to_ino(fs_info, argp); |
1406e4327 Btrfs: add a "df"... |
5296 |
case BTRFS_IOC_SPACE_INFO: |
2ff7e61e0 btrfs: take an fs... |
5297 |
return btrfs_ioctl_space_info(fs_info, argp); |
9b1998598 Btrfs: fix sync f... |
5298 5299 |
case BTRFS_IOC_SYNC: { int ret; |
0b246afa6 btrfs: root->fs_i... |
5300 |
ret = btrfs_start_delalloc_roots(fs_info, 0, -1); |
9b1998598 Btrfs: fix sync f... |
5301 5302 |
if (ret) return ret; |
0b246afa6 btrfs: root->fs_i... |
5303 |
ret = btrfs_sync_fs(inode->i_sb, 1); |
2fad4e83e btrfs: wake up tr... |
5304 5305 |
/* * The transaction thread may want to do more work, |
013276101 btrfs: fix string... |
5306 |
* namely it pokes the cleaner kthread that will start |
2fad4e83e btrfs: wake up tr... |
5307 5308 |
* processing uncleaned subvols. */ |
0b246afa6 btrfs: root->fs_i... |
5309 |
wake_up_process(fs_info->transaction_kthread); |
9b1998598 Btrfs: fix sync f... |
5310 5311 |
return ret; } |
462045928 Btrfs: add START_... |
5312 |
case BTRFS_IOC_START_SYNC: |
9a8c28bec Btrfs: pass root ... |
5313 |
return btrfs_ioctl_start_sync(root, argp); |
462045928 Btrfs: add START_... |
5314 |
case BTRFS_IOC_WAIT_SYNC: |
2ff7e61e0 btrfs: take an fs... |
5315 |
return btrfs_ioctl_wait_sync(fs_info, argp); |
475f63874 btrfs: new ioctls... |
5316 |
case BTRFS_IOC_SCRUB: |
b8e95489b Btrfs: get write ... |
5317 |
return btrfs_ioctl_scrub(file, argp); |
475f63874 btrfs: new ioctls... |
5318 |
case BTRFS_IOC_SCRUB_CANCEL: |
2ff7e61e0 btrfs: take an fs... |
5319 |
return btrfs_ioctl_scrub_cancel(fs_info); |
475f63874 btrfs: new ioctls... |
5320 |
case BTRFS_IOC_SCRUB_PROGRESS: |
2ff7e61e0 btrfs: take an fs... |
5321 |
return btrfs_ioctl_scrub_progress(fs_info, argp); |
c9e9f97bd Btrfs: add basic ... |
5322 |
case BTRFS_IOC_BALANCE_V2: |
9ba1f6e44 Btrfs: do not do ... |
5323 |
return btrfs_ioctl_balance(file, argp); |
837d5b6e4 Btrfs: allow for ... |
5324 |
case BTRFS_IOC_BALANCE_CTL: |
2ff7e61e0 btrfs: take an fs... |
5325 |
return btrfs_ioctl_balance_ctl(fs_info, arg); |
19a39dce3 Btrfs: add balanc... |
5326 |
case BTRFS_IOC_BALANCE_PROGRESS: |
2ff7e61e0 btrfs: take an fs... |
5327 |
return btrfs_ioctl_balance_progress(fs_info, argp); |
8ea05e3a4 Btrfs: introduce ... |
5328 5329 |
case BTRFS_IOC_SET_RECEIVED_SUBVOL: return btrfs_ioctl_set_received_subvol(file, argp); |
abccd00f8 btrfs: Fix 32/64-... |
5330 5331 5332 5333 |
#ifdef CONFIG_64BIT case BTRFS_IOC_SET_RECEIVED_SUBVOL_32: return btrfs_ioctl_set_received_subvol_32(file, argp); #endif |
31db9f7c2 Btrfs: introduce ... |
5334 5335 |
case BTRFS_IOC_SEND: return btrfs_ioctl_send(file, argp); |
c11d2c236 Btrfs: add ioctl ... |
5336 |
case BTRFS_IOC_GET_DEV_STATS: |
2ff7e61e0 btrfs: take an fs... |
5337 |
return btrfs_ioctl_get_dev_stats(fs_info, argp); |
5d13a37bd Btrfs: add qgroup... |
5338 |
case BTRFS_IOC_QUOTA_CTL: |
905b0dda0 Btrfs: get write ... |
5339 |
return btrfs_ioctl_quota_ctl(file, argp); |
5d13a37bd Btrfs: add qgroup... |
5340 |
case BTRFS_IOC_QGROUP_ASSIGN: |
905b0dda0 Btrfs: get write ... |
5341 |
return btrfs_ioctl_qgroup_assign(file, argp); |
5d13a37bd Btrfs: add qgroup... |
5342 |
case BTRFS_IOC_QGROUP_CREATE: |
905b0dda0 Btrfs: get write ... |
5343 |
return btrfs_ioctl_qgroup_create(file, argp); |
5d13a37bd Btrfs: add qgroup... |
5344 |
case BTRFS_IOC_QGROUP_LIMIT: |
905b0dda0 Btrfs: get write ... |
5345 |
return btrfs_ioctl_qgroup_limit(file, argp); |
2f2320360 Btrfs: rescan for... |
5346 5347 5348 5349 |
case BTRFS_IOC_QUOTA_RESCAN: return btrfs_ioctl_quota_rescan(file, argp); case BTRFS_IOC_QUOTA_RESCAN_STATUS: return btrfs_ioctl_quota_rescan_status(file, argp); |
57254b6eb Btrfs: add ioctl ... |
5350 5351 |
case BTRFS_IOC_QUOTA_RESCAN_WAIT: return btrfs_ioctl_quota_rescan_wait(file, argp); |
3f6bcfbd4 Btrfs: add suppor... |
5352 |
case BTRFS_IOC_DEV_REPLACE: |
2ff7e61e0 btrfs: take an fs... |
5353 |
return btrfs_ioctl_dev_replace(fs_info, argp); |
867ab667e Btrfs: Add a new ... |
5354 5355 |
case BTRFS_IOC_GET_FSLABEL: return btrfs_ioctl_get_fslabel(file, argp); |
a8bfd4abe Btrfs: set/change... |
5356 5357 |
case BTRFS_IOC_SET_FSLABEL: return btrfs_ioctl_set_fslabel(file, argp); |
2eaa055fa btrfs: add ioctls... |
5358 |
case BTRFS_IOC_GET_SUPPORTED_FEATURES: |
d5131b658 btrfs: drop unuse... |
5359 |
return btrfs_ioctl_get_supported_features(argp); |
2eaa055fa btrfs: add ioctls... |
5360 5361 5362 5363 |
case BTRFS_IOC_GET_FEATURES: return btrfs_ioctl_get_features(file, argp); case BTRFS_IOC_SET_FEATURES: return btrfs_ioctl_set_features(file, argp); |
f46b5a66b Btrfs: split out ... |
5364 5365 5366 5367 |
} return -ENOTTY; } |
4c63c2454 btrfs: bugfix: ha... |
5368 5369 5370 5371 |
#ifdef CONFIG_COMPAT long btrfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { |
2a3622491 btrfs: fix btrfs_... |
5372 5373 5374 5375 |
/* * These all access 32-bit values anyway so no further * handling is necessary. */ |
4c63c2454 btrfs: bugfix: ha... |
5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 |
switch (cmd) { case FS_IOC32_GETFLAGS: cmd = FS_IOC_GETFLAGS; break; case FS_IOC32_SETFLAGS: cmd = FS_IOC_SETFLAGS; break; case FS_IOC32_GETVERSION: cmd = FS_IOC_GETVERSION; break; |
4c63c2454 btrfs: bugfix: ha... |
5386 5387 5388 5389 5390 |
} return btrfs_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); } #endif |