public inbox for linux-unionfs@vger.kernel.org
 help / color / mirror / Atom feed
From: Amir Goldstein <amir73il@gmail.com>
To: Miklos Szeredi <miklos@szeredi.hu>
Cc: linux-unionfs@vger.kernel.org
Subject: [PATCH v3 23/23] ovl: adjust overlay inode nlink for indexed inodes
Date: Wed, 14 Jun 2017 10:26:42 +0300	[thread overview]
Message-ID: <1497425202-16270-24-git-send-email-amir73il@gmail.com> (raw)
In-Reply-To: <1497425202-16270-1-git-send-email-amir73il@gmail.com>

Overlay inode nlink does not account for all the lower hardlinks that
have not been copied up yet. Those are added to nlink as they get copied up
and do not decrement nlink when they get unlinked or renamed over.

As a workaround for correct overlay nlink count, before trying to unlink
or rename over the first lower hardlink, try to copy up that lower and
create the index prior to removal of upper.

An overlay inode nlink of 1 stands for an orphan indexed inode. This is
the case where some of the lower hardlinks were copied up, modified, and
then all copied up upper hardlinks has been unlinked, but there are still
non covered lower hardlinks.

The important thing to take care of is that overlay inode nlink doesn't
drop to zero when there are still upper hardlinks or non covered
lower hardlinks.

Return the overlay inode nlinks for indexed upper inodes on stat(2),
excluding 1 nlink for the index entry.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 fs/overlayfs/dir.c   | 43 +++++++++++++++++++++++++++++++++++++++----
 fs/overlayfs/inode.c |  9 +++++++++
 2 files changed, 48 insertions(+), 4 deletions(-)

diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index cec89d33ab1e..6c354bd4483e 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -732,9 +732,42 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir)
 	return err;
 }
 
+static bool ovl_is_indexed_lower(struct dentry *dentry)
+{
+	enum ovl_path_type type = ovl_path_type(dentry);
+
+	/*
+	 * With inodes index feature, lower hardlinks are not counted in
+	 * overlay inode nlink. The lower hardlinks are added to overlay nlink
+	 * count as they get copied up and do not decrement overlay nlink when
+	 * they get unlinked or renamed over.
+	 *
+	 * An overlay inode nlink of 1 stands for an orphan indexed inode -
+	 * an inode that was copied up, modified, and then the copied up alias
+	 * has been unlinked. The orphan index can still be linked by another
+	 * lower hardlink copy up.
+	 *
+	 * Removing non indexed lower hardlinks would lead to negative overlay
+	 * nlink if we wanted to account for those removals in overlay nlink.
+	 * As a workaround, before whiteout/rename over of a lower hardlink,
+	 * try to copy up to create the upper index. Creating the upper index
+	 * will initialize the overlay nlink, do it could be dropped if unlink
+	 * or rename succeeds.
+	 * TODO: implement metadata only index copy up when called with
+	 *       ovl_copy_up_flags(dentry, O_PATH).
+	 */
+	if (ovl_indexdir(dentry->d_sb) && !OVL_TYPE_UPPER(type) &&
+	    ovl_dentry_lower(dentry)->d_inode->i_nlink > 1) {
+		ovl_copy_up(dentry);
+		type = ovl_path_type(dentry);
+	}
+
+	return !OVL_TYPE_UPPER(type) && OVL_TYPE_INDEX(type);
+}
+
 static int ovl_do_remove(struct dentry *dentry, bool is_dir)
 {
-	enum ovl_path_type type;
+	bool indexed_lower;
 	int err;
 	const struct cred *old_cred;
 
@@ -746,7 +779,8 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir)
 	if (err)
 		goto out_drop_write;
 
-	type = ovl_path_type(dentry);
+	if (!is_dir)
+		indexed_lower = ovl_is_indexed_lower(dentry);
 
 	old_cred = ovl_override_creds(dentry->d_sb);
 	if (!ovl_lower_positive(dentry))
@@ -757,7 +791,7 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir)
 	if (!err) {
 		if (is_dir)
 			clear_nlink(dentry->d_inode);
-		else
+		else if (!indexed_lower)
 			drop_nlink(dentry->d_inode);
 	}
 out_drop_write:
@@ -952,7 +986,8 @@ static int ovl_rename(struct inode *olddir, struct dentry *old,
 			flags |= RENAME_EXCHANGE;
 			cleanup_whiteout = true;
 		}
-		if (!new_is_dir && new->d_inode)
+		/* An indexed lower hardlink is not counted in overlay nlink */
+		if (!new_is_dir && new->d_inode && !ovl_is_indexed_lower(new))
 			new_drop_nlink = true;
 	}
 
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index 28f9a8cc0f61..35fda6fb9de3 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -131,6 +131,15 @@ int ovl_getattr(const struct path *path, struct kstat *stat,
 	if (is_dir && OVL_TYPE_MERGE(type))
 		stat->nlink = 1;
 
+	/*
+	 * Return the overlay inode nlinks for indexed upper inodes, excluding
+	 * 1 nlink for the index entry. Overlay inode nlink does not account
+	 * for all the lower hardlinks that have not been copied up yet.
+	 * TODO: add count of non-covered lower hardlinks.
+	 */
+	if (!is_dir && OVL_TYPE_UPPER(type) && OVL_TYPE_INDEX(type))
+		stat->nlink = dentry->d_inode->i_nlink - 1;
+
 out:
 	revert_creds(old_cred);
 
-- 
2.7.4

  parent reply	other threads:[~2017-06-14  7:27 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-06-14  7:26 [PATCH v3 00/23] Overlayfs inodes index Amir Goldstein
2017-06-14  7:26 ` [PATCH v3 01/23] vfs: introduce inode 'inuse' lock Amir Goldstein
2017-06-14  7:26 ` [PATCH v3 02/23] ovl: get exclusive ownership on upper/work dirs Amir Goldstein
2017-06-14  7:26 ` [PATCH v3 03/23] ovl: relax same fs constrain for ovl_check_origin() Amir Goldstein
2017-06-14  7:26 ` [PATCH v3 04/23] ovl: generalize ovl_create_workdir() Amir Goldstein
2017-06-14  7:26 ` [PATCH v3 05/23] ovl: introduce the inodes index dir feature Amir Goldstein
2017-06-14  7:26 ` [PATCH v3 06/23] ovl: verify upper root dir matches lower root dir Amir Goldstein
2017-06-14  7:26 ` [PATCH v3 07/23] ovl: verify index dir matches upper dir Amir Goldstein
2017-06-14  7:26 ` [PATCH v3 08/23] ovl: store path type in dentry Amir Goldstein
2017-06-14  7:26 ` [PATCH v3 09/23] ovl: cram dentry state booleans into type flags Amir Goldstein
2017-06-14  7:26 ` [PATCH v3 10/23] ovl: lookup index entry for copy up origin Amir Goldstein
2017-06-14  7:26 ` [PATCH v3 11/23] ovl: allocate an ovl_inode struct Amir Goldstein
2017-06-14  7:26 ` [PATCH v3 12/23] ovl: store upper/lower real inode in ovl_inode_info Amir Goldstein
2017-06-14 11:00   ` Amir Goldstein
2017-06-16 11:55     ` Amir Goldstein
2017-06-14  7:26 ` [PATCH v3 13/23] ovl: use ovl_inode_init() for initializing new inode Amir Goldstein
2017-06-14  7:26 ` [PATCH v3 14/23] ovl: hash overlay non-dir inodes by copy up origin inode Amir Goldstein
2017-06-14  7:26 ` [PATCH v3 15/23] ovl: defer upper dir lock to tempfile link Amir Goldstein
2017-06-14  7:26 ` [PATCH v3 16/23] ovl: factor out ovl_copy_up_inode() helper Amir Goldstein
2017-06-14  7:26 ` [PATCH v3 17/23] ovl: generalize ovl_copy_up_locked() using actors Amir Goldstein
2017-06-14  7:26 ` [PATCH v3 18/23] ovl: generalize ovl_copy_up_one() " Amir Goldstein
2017-06-14  7:26 ` [PATCH v3 19/23] ovl: use ovl_inode mutex to synchronize concurrent copy up Amir Goldstein
2017-06-14  7:26 ` [PATCH v3 20/23] ovl: implement index dir copy up method Amir Goldstein
2017-06-14  7:26 ` [PATCH v3 21/23] ovl: link up indexed lower hardlink on lookup Amir Goldstein
2017-06-19 10:22   ` Amir Goldstein
2017-06-14  7:26 ` [PATCH v3 22/23] ovl: fix nlink leak in ovl_rename() Amir Goldstein
2017-06-14  7:26 ` Amir Goldstein [this message]
2017-06-14  7:30 ` [PATCH v3 00/23] Overlayfs inodes index Miklos Szeredi
2017-06-14  7:48   ` Amir Goldstein

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1497425202-16270-24-git-send-email-amir73il@gmail.com \
    --to=amir73il@gmail.com \
    --cc=linux-unionfs@vger.kernel.org \
    --cc=miklos@szeredi.hu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox