diff options
-rw-r--r-- | fs/overlayfs/copy_up.c | 56 | ||||
-rw-r--r-- | fs/overlayfs/overlayfs.h | 18 | ||||
-rw-r--r-- | fs/overlayfs/super.c | 1 | ||||
-rw-r--r-- | fs/overlayfs/util.c | 78 |
4 files changed, 142 insertions, 11 deletions
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index aa3c62a4e462..7e6664d6643d 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c | |||
@@ -180,6 +180,16 @@ out_fput: | |||
180 | return error; | 180 | return error; |
181 | } | 181 | } |
182 | 182 | ||
183 | static int ovl_set_size(struct dentry *upperdentry, struct kstat *stat) | ||
184 | { | ||
185 | struct iattr attr = { | ||
186 | .ia_valid = ATTR_SIZE, | ||
187 | .ia_size = stat->size, | ||
188 | }; | ||
189 | |||
190 | return notify_change(upperdentry, &attr, NULL); | ||
191 | } | ||
192 | |||
183 | static int ovl_set_timestamps(struct dentry *upperdentry, struct kstat *stat) | 193 | static int ovl_set_timestamps(struct dentry *upperdentry, struct kstat *stat) |
184 | { | 194 | { |
185 | struct iattr attr = { | 195 | struct iattr attr = { |
@@ -520,8 +530,18 @@ static int ovl_copy_up_inode(struct ovl_copy_up_ctx *c, struct dentry *temp) | |||
520 | return err; | 530 | return err; |
521 | } | 531 | } |
522 | 532 | ||
533 | if (c->metacopy) { | ||
534 | err = ovl_check_setxattr(c->dentry, temp, OVL_XATTR_METACOPY, | ||
535 | NULL, 0, -EOPNOTSUPP); | ||
536 | if (err) | ||
537 | return err; | ||
538 | } | ||
539 | |||
523 | inode_lock(temp->d_inode); | 540 | inode_lock(temp->d_inode); |
524 | err = ovl_set_attr(temp, &c->stat); | 541 | if (c->metacopy) |
542 | err = ovl_set_size(temp, &c->stat); | ||
543 | if (!err) | ||
544 | err = ovl_set_attr(temp, &c->stat); | ||
525 | inode_unlock(temp->d_inode); | 545 | inode_unlock(temp->d_inode); |
526 | 546 | ||
527 | return err; | 547 | return err; |
@@ -559,6 +579,8 @@ static int ovl_copy_up_locked(struct ovl_copy_up_ctx *c) | |||
559 | if (err) | 579 | if (err) |
560 | goto out; | 580 | goto out; |
561 | 581 | ||
582 | if (!c->metacopy) | ||
583 | ovl_set_upperdata(d_inode(c->dentry)); | ||
562 | inode = d_inode(c->dentry); | 584 | inode = d_inode(c->dentry); |
563 | ovl_inode_update(inode, newdentry); | 585 | ovl_inode_update(inode, newdentry); |
564 | if (S_ISDIR(inode->i_mode)) | 586 | if (S_ISDIR(inode->i_mode)) |
@@ -681,6 +703,28 @@ static bool ovl_need_meta_copy_up(struct dentry *dentry, umode_t mode, | |||
681 | return true; | 703 | return true; |
682 | } | 704 | } |
683 | 705 | ||
706 | /* Copy up data of an inode which was copied up metadata only in the past. */ | ||
707 | static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c) | ||
708 | { | ||
709 | struct path upperpath; | ||
710 | int err; | ||
711 | |||
712 | ovl_path_upper(c->dentry, &upperpath); | ||
713 | if (WARN_ON(upperpath.dentry == NULL)) | ||
714 | return -EIO; | ||
715 | |||
716 | err = ovl_copy_up_data(&c->lowerpath, &upperpath, c->stat.size); | ||
717 | if (err) | ||
718 | return err; | ||
719 | |||
720 | err = vfs_removexattr(upperpath.dentry, OVL_XATTR_METACOPY); | ||
721 | if (err) | ||
722 | return err; | ||
723 | |||
724 | ovl_set_upperdata(d_inode(c->dentry)); | ||
725 | return err; | ||
726 | } | ||
727 | |||
684 | static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, | 728 | static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, |
685 | int flags) | 729 | int flags) |
686 | { | 730 | { |
@@ -726,7 +770,7 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, | |||
726 | return PTR_ERR(ctx.link); | 770 | return PTR_ERR(ctx.link); |
727 | } | 771 | } |
728 | 772 | ||
729 | err = ovl_copy_up_start(dentry); | 773 | err = ovl_copy_up_start(dentry, flags); |
730 | /* err < 0: interrupted, err > 0: raced with another copy-up */ | 774 | /* err < 0: interrupted, err > 0: raced with another copy-up */ |
731 | if (unlikely(err)) { | 775 | if (unlikely(err)) { |
732 | if (err > 0) | 776 | if (err > 0) |
@@ -736,6 +780,8 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, | |||
736 | err = ovl_do_copy_up(&ctx); | 780 | err = ovl_do_copy_up(&ctx); |
737 | if (!err && parent && !ovl_dentry_has_upper_alias(dentry)) | 781 | if (!err && parent && !ovl_dentry_has_upper_alias(dentry)) |
738 | err = ovl_link_up(&ctx); | 782 | err = ovl_link_up(&ctx); |
783 | if (!err && ovl_dentry_needs_data_copy_up_locked(dentry, flags)) | ||
784 | err = ovl_copy_up_meta_inode_data(&ctx); | ||
739 | ovl_copy_up_end(dentry); | 785 | ovl_copy_up_end(dentry); |
740 | } | 786 | } |
741 | do_delayed_call(&done); | 787 | do_delayed_call(&done); |
@@ -761,7 +807,7 @@ int ovl_copy_up_flags(struct dentry *dentry, int flags) | |||
761 | struct dentry *next; | 807 | struct dentry *next; |
762 | struct dentry *parent = NULL; | 808 | struct dentry *parent = NULL; |
763 | 809 | ||
764 | if (ovl_already_copied_up(dentry)) | 810 | if (ovl_already_copied_up(dentry, flags)) |
765 | break; | 811 | break; |
766 | 812 | ||
767 | next = dget(dentry); | 813 | next = dget(dentry); |
@@ -789,13 +835,13 @@ int ovl_copy_up_flags(struct dentry *dentry, int flags) | |||
789 | static bool ovl_open_need_copy_up(struct dentry *dentry, int flags) | 835 | static bool ovl_open_need_copy_up(struct dentry *dentry, int flags) |
790 | { | 836 | { |
791 | /* Copy up of disconnected dentry does not set upper alias */ | 837 | /* Copy up of disconnected dentry does not set upper alias */ |
792 | if (ovl_already_copied_up(dentry)) | 838 | if (ovl_already_copied_up(dentry, flags)) |
793 | return false; | 839 | return false; |
794 | 840 | ||
795 | if (special_file(d_inode(dentry)->i_mode)) | 841 | if (special_file(d_inode(dentry)->i_mode)) |
796 | return false; | 842 | return false; |
797 | 843 | ||
798 | if (!(OPEN_FMODE(flags) & FMODE_WRITE) && !(flags & O_TRUNC)) | 844 | if (!ovl_open_flags_need_copy_up(flags)) |
799 | return false; | 845 | return false; |
800 | 846 | ||
801 | return true; | 847 | return true; |
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 206e588df095..16a000694c4e 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h | |||
@@ -29,6 +29,7 @@ enum ovl_path_type { | |||
29 | #define OVL_XATTR_IMPURE OVL_XATTR_PREFIX "impure" | 29 | #define OVL_XATTR_IMPURE OVL_XATTR_PREFIX "impure" |
30 | #define OVL_XATTR_NLINK OVL_XATTR_PREFIX "nlink" | 30 | #define OVL_XATTR_NLINK OVL_XATTR_PREFIX "nlink" |
31 | #define OVL_XATTR_UPPER OVL_XATTR_PREFIX "upper" | 31 | #define OVL_XATTR_UPPER OVL_XATTR_PREFIX "upper" |
32 | #define OVL_XATTR_METACOPY OVL_XATTR_PREFIX "metacopy" | ||
32 | 33 | ||
33 | enum ovl_inode_flag { | 34 | enum ovl_inode_flag { |
34 | /* Pure upper dir that may contain non pure upper entries */ | 35 | /* Pure upper dir that may contain non pure upper entries */ |
@@ -36,6 +37,7 @@ enum ovl_inode_flag { | |||
36 | /* Non-merge dir that may contain whiteout entries */ | 37 | /* Non-merge dir that may contain whiteout entries */ |
37 | OVL_WHITEOUTS, | 38 | OVL_WHITEOUTS, |
38 | OVL_INDEX, | 39 | OVL_INDEX, |
40 | OVL_UPPERDATA, | ||
39 | }; | 41 | }; |
40 | 42 | ||
41 | enum ovl_entry_flag { | 43 | enum ovl_entry_flag { |
@@ -191,6 +193,14 @@ static inline struct dentry *ovl_do_tmpfile(struct dentry *dentry, umode_t mode) | |||
191 | return ret; | 193 | return ret; |
192 | } | 194 | } |
193 | 195 | ||
196 | static inline bool ovl_open_flags_need_copy_up(int flags) | ||
197 | { | ||
198 | if (!flags) | ||
199 | return false; | ||
200 | |||
201 | return ((OPEN_FMODE(flags) & FMODE_WRITE) || (flags & O_TRUNC)); | ||
202 | } | ||
203 | |||
194 | /* util.c */ | 204 | /* util.c */ |
195 | int ovl_want_write(struct dentry *dentry); | 205 | int ovl_want_write(struct dentry *dentry); |
196 | void ovl_drop_write(struct dentry *dentry); | 206 | void ovl_drop_write(struct dentry *dentry); |
@@ -226,6 +236,10 @@ bool ovl_dentry_is_whiteout(struct dentry *dentry); | |||
226 | void ovl_dentry_set_opaque(struct dentry *dentry); | 236 | void ovl_dentry_set_opaque(struct dentry *dentry); |
227 | bool ovl_dentry_has_upper_alias(struct dentry *dentry); | 237 | bool ovl_dentry_has_upper_alias(struct dentry *dentry); |
228 | void ovl_dentry_set_upper_alias(struct dentry *dentry); | 238 | void ovl_dentry_set_upper_alias(struct dentry *dentry); |
239 | bool ovl_dentry_needs_data_copy_up(struct dentry *dentry, int flags); | ||
240 | bool ovl_dentry_needs_data_copy_up_locked(struct dentry *dentry, int flags); | ||
241 | bool ovl_has_upperdata(struct inode *inode); | ||
242 | void ovl_set_upperdata(struct inode *inode); | ||
229 | bool ovl_redirect_dir(struct super_block *sb); | 243 | bool ovl_redirect_dir(struct super_block *sb); |
230 | const char *ovl_dentry_get_redirect(struct dentry *dentry); | 244 | const char *ovl_dentry_get_redirect(struct dentry *dentry); |
231 | void ovl_dentry_set_redirect(struct dentry *dentry, const char *redirect); | 245 | void ovl_dentry_set_redirect(struct dentry *dentry, const char *redirect); |
@@ -236,9 +250,9 @@ void ovl_dir_modified(struct dentry *dentry, bool impurity); | |||
236 | u64 ovl_dentry_version_get(struct dentry *dentry); | 250 | u64 ovl_dentry_version_get(struct dentry *dentry); |
237 | bool ovl_is_whiteout(struct dentry *dentry); | 251 | bool ovl_is_whiteout(struct dentry *dentry); |
238 | struct file *ovl_path_open(struct path *path, int flags); | 252 | struct file *ovl_path_open(struct path *path, int flags); |
239 | int ovl_copy_up_start(struct dentry *dentry); | 253 | int ovl_copy_up_start(struct dentry *dentry, int flags); |
240 | void ovl_copy_up_end(struct dentry *dentry); | 254 | void ovl_copy_up_end(struct dentry *dentry); |
241 | bool ovl_already_copied_up(struct dentry *dentry); | 255 | bool ovl_already_copied_up(struct dentry *dentry, int flags); |
242 | bool ovl_check_origin_xattr(struct dentry *dentry); | 256 | bool ovl_check_origin_xattr(struct dentry *dentry); |
243 | bool ovl_check_dir_xattr(struct dentry *dentry, const char *name); | 257 | bool ovl_check_dir_xattr(struct dentry *dentry, const char *name); |
244 | int ovl_check_setxattr(struct dentry *dentry, struct dentry *upperdentry, | 258 | int ovl_check_setxattr(struct dentry *dentry, struct dentry *upperdentry, |
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index d4caeee051ee..ab0039161f85 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c | |||
@@ -1485,6 +1485,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) | |||
1485 | /* Root is always merge -> can have whiteouts */ | 1485 | /* Root is always merge -> can have whiteouts */ |
1486 | ovl_set_flag(OVL_WHITEOUTS, d_inode(root_dentry)); | 1486 | ovl_set_flag(OVL_WHITEOUTS, d_inode(root_dentry)); |
1487 | ovl_dentry_set_flag(OVL_E_CONNECTED, root_dentry); | 1487 | ovl_dentry_set_flag(OVL_E_CONNECTED, root_dentry); |
1488 | ovl_set_upperdata(d_inode(root_dentry)); | ||
1488 | ovl_inode_init(d_inode(root_dentry), upperpath.dentry, | 1489 | ovl_inode_init(d_inode(root_dentry), upperpath.dentry, |
1489 | ovl_dentry_lower(root_dentry)); | 1490 | ovl_dentry_lower(root_dentry)); |
1490 | 1491 | ||
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index 43235294e77b..f8e3c95711b8 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c | |||
@@ -279,6 +279,62 @@ void ovl_dentry_set_upper_alias(struct dentry *dentry) | |||
279 | ovl_dentry_set_flag(OVL_E_UPPER_ALIAS, dentry); | 279 | ovl_dentry_set_flag(OVL_E_UPPER_ALIAS, dentry); |
280 | } | 280 | } |
281 | 281 | ||
282 | static bool ovl_should_check_upperdata(struct inode *inode) | ||
283 | { | ||
284 | if (!S_ISREG(inode->i_mode)) | ||
285 | return false; | ||
286 | |||
287 | if (!ovl_inode_lower(inode)) | ||
288 | return false; | ||
289 | |||
290 | return true; | ||
291 | } | ||
292 | |||
293 | bool ovl_has_upperdata(struct inode *inode) | ||
294 | { | ||
295 | if (!ovl_should_check_upperdata(inode)) | ||
296 | return true; | ||
297 | |||
298 | if (!ovl_test_flag(OVL_UPPERDATA, inode)) | ||
299 | return false; | ||
300 | /* | ||
301 | * Pairs with smp_wmb() in ovl_set_upperdata(). Main user of | ||
302 | * ovl_has_upperdata() is ovl_copy_up_meta_inode_data(). Make sure | ||
303 | * if setting of OVL_UPPERDATA is visible, then effects of writes | ||
304 | * before that are visible too. | ||
305 | */ | ||
306 | smp_rmb(); | ||
307 | return true; | ||
308 | } | ||
309 | |||
310 | void ovl_set_upperdata(struct inode *inode) | ||
311 | { | ||
312 | /* | ||
313 | * Pairs with smp_rmb() in ovl_has_upperdata(). Make sure | ||
314 | * if OVL_UPPERDATA flag is visible, then effects of write operations | ||
315 | * before it are visible as well. | ||
316 | */ | ||
317 | smp_wmb(); | ||
318 | ovl_set_flag(OVL_UPPERDATA, inode); | ||
319 | } | ||
320 | |||
321 | /* Caller should hold ovl_inode->lock */ | ||
322 | bool ovl_dentry_needs_data_copy_up_locked(struct dentry *dentry, int flags) | ||
323 | { | ||
324 | if (!ovl_open_flags_need_copy_up(flags)) | ||
325 | return false; | ||
326 | |||
327 | return !ovl_test_flag(OVL_UPPERDATA, d_inode(dentry)); | ||
328 | } | ||
329 | |||
330 | bool ovl_dentry_needs_data_copy_up(struct dentry *dentry, int flags) | ||
331 | { | ||
332 | if (!ovl_open_flags_need_copy_up(flags)) | ||
333 | return false; | ||
334 | |||
335 | return !ovl_has_upperdata(d_inode(dentry)); | ||
336 | } | ||
337 | |||
282 | bool ovl_redirect_dir(struct super_block *sb) | 338 | bool ovl_redirect_dir(struct super_block *sb) |
283 | { | 339 | { |
284 | struct ovl_fs *ofs = sb->s_fs_info; | 340 | struct ovl_fs *ofs = sb->s_fs_info; |
@@ -377,7 +433,20 @@ struct file *ovl_path_open(struct path *path, int flags) | |||
377 | return dentry_open(path, flags | O_NOATIME, current_cred()); | 433 | return dentry_open(path, flags | O_NOATIME, current_cred()); |
378 | } | 434 | } |
379 | 435 | ||
380 | bool ovl_already_copied_up(struct dentry *dentry) | 436 | /* Caller should hold ovl_inode->lock */ |
437 | static bool ovl_already_copied_up_locked(struct dentry *dentry, int flags) | ||
438 | { | ||
439 | bool disconnected = dentry->d_flags & DCACHE_DISCONNECTED; | ||
440 | |||
441 | if (ovl_dentry_upper(dentry) && | ||
442 | (ovl_dentry_has_upper_alias(dentry) || disconnected) && | ||
443 | !ovl_dentry_needs_data_copy_up_locked(dentry, flags)) | ||
444 | return true; | ||
445 | |||
446 | return false; | ||
447 | } | ||
448 | |||
449 | bool ovl_already_copied_up(struct dentry *dentry, int flags) | ||
381 | { | 450 | { |
382 | bool disconnected = dentry->d_flags & DCACHE_DISCONNECTED; | 451 | bool disconnected = dentry->d_flags & DCACHE_DISCONNECTED; |
383 | 452 | ||
@@ -395,19 +464,20 @@ bool ovl_already_copied_up(struct dentry *dentry) | |||
395 | * with rename. | 464 | * with rename. |
396 | */ | 465 | */ |
397 | if (ovl_dentry_upper(dentry) && | 466 | if (ovl_dentry_upper(dentry) && |
398 | (ovl_dentry_has_upper_alias(dentry) || disconnected)) | 467 | (ovl_dentry_has_upper_alias(dentry) || disconnected) && |
468 | !ovl_dentry_needs_data_copy_up(dentry, flags)) | ||
399 | return true; | 469 | return true; |
400 | 470 | ||
401 | return false; | 471 | return false; |
402 | } | 472 | } |
403 | 473 | ||
404 | int ovl_copy_up_start(struct dentry *dentry) | 474 | int ovl_copy_up_start(struct dentry *dentry, int flags) |
405 | { | 475 | { |
406 | struct ovl_inode *oi = OVL_I(d_inode(dentry)); | 476 | struct ovl_inode *oi = OVL_I(d_inode(dentry)); |
407 | int err; | 477 | int err; |
408 | 478 | ||
409 | err = mutex_lock_interruptible(&oi->lock); | 479 | err = mutex_lock_interruptible(&oi->lock); |
410 | if (!err && ovl_already_copied_up(dentry)) { | 480 | if (!err && ovl_already_copied_up_locked(dentry, flags)) { |
411 | err = 1; /* Already copied up */ | 481 | err = 1; /* Already copied up */ |
412 | mutex_unlock(&oi->lock); | 482 | mutex_unlock(&oi->lock); |
413 | } | 483 | } |