aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2017-06-20 08:35:14 -0400
committerMiklos Szeredi <mszeredi@redhat.com>2017-07-04 16:03:19 -0400
commit5f8415d6b87ecb4ebf1bbd02c538694ebb7fb57c (patch)
treed3764780b95675c7d834ae4ba0d3d834bb9fc6e9
parent59be09712ab98a3060f13e31343c7abb9bc4583d (diff)
ovl: persistent overlay inode nlink for indexed inodes
With inodes index enabled, an overlay inode nlink counts the union of upper and non-covered lower hardlinks. During the lifetime of a non-pure upper inode, the following nlink modifying operations can happen: 1. Lower hardlink copy up 2. Upper hardlink created, unlinked or renamed over 3. Lower hardlink whiteout or renamed over For the first, copy up case, the union nlink does not change, whether the operation succeeds or fails, but the upper inode nlink may change. Therefore, before copy up, we store the union nlink value relative to the lower inode nlink in the index inode xattr trusted.overlay.nlink. For the second, upper hardlink case, the union nlink should be incremented or decremented IFF the operation succeeds, aligned with nlink change of the upper inode. Therefore, before link/unlink/rename, we store the union nlink value relative to the upper inode nlink in the index inode. For the last, lower cover up case, we simplify things by preceding the whiteout or cover up with copy up. This makes sure that there is an index upper inode where the nlink xattr can be stored before the copied up upper entry is unlink. Return the overlay inode nlinks for indexed upper inodes on stat(2). Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r--fs/overlayfs/copy_up.c5
-rw-r--r--fs/overlayfs/dir.c19
-rw-r--r--fs/overlayfs/inode.c112
-rw-r--r--fs/overlayfs/overlayfs.h5
-rw-r--r--fs/overlayfs/util.c66
5 files changed, 204 insertions, 3 deletions
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index 9f5a47338e59..f193976560de 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -323,6 +323,10 @@ static int ovl_link_up(struct dentry *parent, struct dentry *dentry)
323 struct dentry *upperdir = ovl_dentry_upper(parent); 323 struct dentry *upperdir = ovl_dentry_upper(parent);
324 struct inode *udir = d_inode(upperdir); 324 struct inode *udir = d_inode(upperdir);
325 325
326 err = ovl_set_nlink_lower(dentry);
327 if (err)
328 return err;
329
326 inode_lock_nested(udir, I_MUTEX_PARENT); 330 inode_lock_nested(udir, I_MUTEX_PARENT);
327 upper = lookup_one_len(dentry->d_name.name, upperdir, 331 upper = lookup_one_len(dentry->d_name.name, upperdir,
328 dentry->d_name.len); 332 dentry->d_name.len);
@@ -335,6 +339,7 @@ static int ovl_link_up(struct dentry *parent, struct dentry *dentry)
335 ovl_dentry_set_upper_alias(dentry); 339 ovl_dentry_set_upper_alias(dentry);
336 } 340 }
337 inode_unlock(udir); 341 inode_unlock(udir);
342 ovl_set_nlink_upper(dentry);
338 343
339 return err; 344 return err;
340} 345}
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index 8b2b23181b19..641d9ee97f91 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -591,6 +591,7 @@ static int ovl_link(struct dentry *old, struct inode *newdir,
591 struct dentry *new) 591 struct dentry *new)
592{ 592{
593 int err; 593 int err;
594 bool locked = false;
594 struct inode *inode; 595 struct inode *inode;
595 596
596 err = ovl_want_write(old); 597 err = ovl_want_write(old);
@@ -601,6 +602,10 @@ static int ovl_link(struct dentry *old, struct inode *newdir,
601 if (err) 602 if (err)
602 goto out_drop_write; 603 goto out_drop_write;
603 604
605 err = ovl_nlink_start(old, &locked);
606 if (err)
607 goto out_drop_write;
608
604 inode = d_inode(old); 609 inode = d_inode(old);
605 ihold(inode); 610 ihold(inode);
606 611
@@ -608,6 +613,7 @@ static int ovl_link(struct dentry *old, struct inode *newdir,
608 if (err) 613 if (err)
609 iput(inode); 614 iput(inode);
610 615
616 ovl_nlink_end(old, locked);
611out_drop_write: 617out_drop_write:
612 ovl_drop_write(old); 618 ovl_drop_write(old);
613out: 619out:
@@ -743,8 +749,8 @@ out:
743 749
744static int ovl_do_remove(struct dentry *dentry, bool is_dir) 750static int ovl_do_remove(struct dentry *dentry, bool is_dir)
745{ 751{
746 enum ovl_path_type type;
747 int err; 752 int err;
753 bool locked = false;
748 const struct cred *old_cred; 754 const struct cred *old_cred;
749 755
750 err = ovl_want_write(dentry); 756 err = ovl_want_write(dentry);
@@ -755,7 +761,9 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir)
755 if (err) 761 if (err)
756 goto out_drop_write; 762 goto out_drop_write;
757 763
758 type = ovl_path_type(dentry); 764 err = ovl_nlink_start(dentry, &locked);
765 if (err)
766 goto out_drop_write;
759 767
760 old_cred = ovl_override_creds(dentry->d_sb); 768 old_cred = ovl_override_creds(dentry->d_sb);
761 if (!ovl_lower_positive(dentry)) 769 if (!ovl_lower_positive(dentry))
@@ -769,6 +777,7 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir)
769 else 777 else
770 drop_nlink(dentry->d_inode); 778 drop_nlink(dentry->d_inode);
771 } 779 }
780 ovl_nlink_end(dentry, locked);
772out_drop_write: 781out_drop_write:
773 ovl_drop_write(dentry); 782 ovl_drop_write(dentry);
774out: 783out:
@@ -891,6 +900,7 @@ static int ovl_rename(struct inode *olddir, struct dentry *old,
891 unsigned int flags) 900 unsigned int flags)
892{ 901{
893 int err; 902 int err;
903 bool locked = false;
894 struct dentry *old_upperdir; 904 struct dentry *old_upperdir;
895 struct dentry *new_upperdir; 905 struct dentry *new_upperdir;
896 struct dentry *olddentry; 906 struct dentry *olddentry;
@@ -934,6 +944,10 @@ static int ovl_rename(struct inode *olddir, struct dentry *old,
934 err = ovl_copy_up(new); 944 err = ovl_copy_up(new);
935 if (err) 945 if (err)
936 goto out_drop_write; 946 goto out_drop_write;
947 } else {
948 err = ovl_nlink_start(new, &locked);
949 if (err)
950 goto out_drop_write;
937 } 951 }
938 952
939 old_cred = ovl_override_creds(old->d_sb); 953 old_cred = ovl_override_creds(old->d_sb);
@@ -1072,6 +1086,7 @@ out_unlock:
1072 unlock_rename(new_upperdir, old_upperdir); 1086 unlock_rename(new_upperdir, old_upperdir);
1073out_revert_creds: 1087out_revert_creds:
1074 revert_creds(old_cred); 1088 revert_creds(old_cred);
1089 ovl_nlink_end(new, locked);
1075out_drop_write: 1090out_drop_write:
1076 ovl_drop_write(old); 1091 ovl_drop_write(old);
1077out: 1092out:
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index 44d262a0a77e..196a4e5450c0 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -12,6 +12,7 @@
12#include <linux/cred.h> 12#include <linux/cred.h>
13#include <linux/xattr.h> 13#include <linux/xattr.h>
14#include <linux/posix_acl.h> 14#include <linux/posix_acl.h>
15#include <linux/ratelimit.h>
15#include "overlayfs.h" 16#include "overlayfs.h"
16 17
17int ovl_setattr(struct dentry *dentry, struct iattr *attr) 18int ovl_setattr(struct dentry *dentry, struct iattr *attr)
@@ -130,6 +131,15 @@ int ovl_getattr(const struct path *path, struct kstat *stat,
130 if (is_dir && OVL_TYPE_MERGE(type)) 131 if (is_dir && OVL_TYPE_MERGE(type))
131 stat->nlink = 1; 132 stat->nlink = 1;
132 133
134 /*
135 * Return the overlay inode nlinks for indexed upper inodes.
136 * Overlay inode nlink counts the union of the upper hardlinks
137 * and non-covered lower hardlinks. It does not include the upper
138 * index hardlink.
139 */
140 if (!is_dir && ovl_test_flag(OVL_INDEX, d_inode(dentry)))
141 stat->nlink = dentry->d_inode->i_nlink;
142
133out: 143out:
134 revert_creds(old_cred); 144 revert_creds(old_cred);
135 145
@@ -442,6 +452,103 @@ static void ovl_fill_inode(struct inode *inode, umode_t mode, dev_t rdev)
442 } 452 }
443} 453}
444 454
455/*
456 * With inodes index enabled, an overlay inode nlink counts the union of upper
457 * hardlinks and non-covered lower hardlinks. During the lifetime of a non-pure
458 * upper inode, the following nlink modifying operations can happen:
459 *
460 * 1. Lower hardlink copy up
461 * 2. Upper hardlink created, unlinked or renamed over
462 * 3. Lower hardlink whiteout or renamed over
463 *
464 * For the first, copy up case, the union nlink does not change, whether the
465 * operation succeeds or fails, but the upper inode nlink may change.
466 * Therefore, before copy up, we store the union nlink value relative to the
467 * lower inode nlink in the index inode xattr trusted.overlay.nlink.
468 *
469 * For the second, upper hardlink case, the union nlink should be incremented
470 * or decremented IFF the operation succeeds, aligned with nlink change of the
471 * upper inode. Therefore, before link/unlink/rename, we store the union nlink
472 * value relative to the upper inode nlink in the index inode.
473 *
474 * For the last, lower cover up case, we simplify things by preceding the
475 * whiteout or cover up with copy up. This makes sure that there is an index
476 * upper inode where the nlink xattr can be stored before the copied up upper
477 * entry is unlink.
478 */
479#define OVL_NLINK_ADD_UPPER (1 << 0)
480
481/*
482 * On-disk format for indexed nlink:
483 *
484 * nlink relative to the upper inode - "U[+-]NUM"
485 * nlink relative to the lower inode - "L[+-]NUM"
486 */
487
488static int ovl_set_nlink_common(struct dentry *dentry,
489 struct dentry *realdentry, const char *format)
490{
491 struct inode *inode = d_inode(dentry);