linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: ovl: hash non-dir by lower inode for fsnotify
       [not found] ` <20180802060549.GB3272@kroah.com>
@ 2018-08-02 15:29   ` Mark Salyzyn
  2018-09-07  9:51     ` Greg KH
  0 siblings, 1 reply; 5+ messages in thread
From: Mark Salyzyn @ 2018-08-02 15:29 UTC (permalink / raw)
  To: Greg KH; +Cc: stable, kernel, Amir Goldstein, Miklos Szeredi

On 08/01/2018 11:05 PM, Greg KH wrote:
> On Wed, Aug 01, 2018 at 02:29:01PM -0700, Mark Salyzyn wrote:
>> 764baba80168ad3adafb521d2ab483ccbc49e344 ovl: hash non-dir by lower inode
>> for fsnotify is not part of 4.14 stable and yet it was marked for 4.13
>> stable merge when committed.
>>
>> Please evaluate.
> Why not try applying it yourself to 4.14.y and note that it does not
> apply at all and then provide a working backport so that we can skip at
> least one email cycle here?  :)
>
> thanks,
>
> greg k-h

Because I am embarrassed by the backport (!) perhaps? :-)

+linux-kernel list and authors/approvers for clearance.

I took some liberty with sb = dentry_d_sb and then sprinkled it in, 
upstream passes sb to the function and the conflicts assumed so.

--------------------------> snip <-------------------------

 From 764baba80168ad3adafb521d2ab483ccbc49e344 Mon Sep 17 00:00:00 2001
From: Amir Goldstein <amir73il@gmail.com>
Date: Sun, 4 Feb 2018 15:35:09 +0200
Subject: ovl: hash non-dir by lower inode for fsnotify

(cherry pick from commit 764baba80168ad3adafb521d2ab483ccbc49e344)

Commit 31747eda41ef ("ovl: hash directory inodes for fsnotify")
fixed an issue of inotify watch on directory that stops getting
events after dropping dentry caches.

A similar issue exists for non-dir non-upper files, for example:

$ mkdir -p lower upper work merged
$ touch lower/foo
$ mount -t overlay -o
lowerdir=lower,workdir=work,upperdir=upper none merged
$ inotifywait merged/foo &
$ echo 2 > /proc/sys/vm/drop_caches
$ cat merged/foo

inotifywait doesn't get the OPEN event, because ovl_lookup() called
from 'cat' allocates a new overlay inode and does not reuse the
watched inode.

Fix this by hashing non-dir overlay inodes by lower real inode in
the following cases that were not hashed before this change:
  - A non-upper overlay mount
  - A lower non-hardlink when index=off

A helper ovl_hash_bylower() was added to put all the logic and
documentation about which real inode an overlay inode is hashed by
into one place.

The issue dates back to initial version of overlayfs, but this
patch depends on ovl_inode code that was introduced in kernel v4.13.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Cc: <stable@vger.kernel.org> #v4.13
Signed-off-by: Mark Salyzyn <salyzyn@android.com> #v4.14
---
  fs/overlayfs/inode.c | 62 +++++++++++++++++++++++++++++++-------------
  1 file changed, 44 insertions(+), 18 deletions(-)

diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index 28a320464609a..7cfef4152e9a4 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -14,6 +14,7 @@
  #include <linux/posix_acl.h>
  #include <linux/ratelimit.h>
  #include "overlayfs.h"
+#include "ovl_entry.h"

  int ovl_setattr(struct dentry *dentry, struct iattr *attr)
  {
@@ -608,39 +609,63 @@ static bool ovl_verify_inode(struct inode *inode, 
struct dentry *lowerdentry,
      return true;
  }

+/*
+ * Does overlay inode need to be hashed by lower inode?
+ */
+static bool ovl_hash_bylower(struct super_block *sb, struct dentry *upper,
+                 struct dentry *lower, struct dentry *index)
+{
+    struct ovl_fs *ofs = sb->s_fs_info;
+
+    /* No, if pure upper */
+    if (!lower)
+        return false;
+
+    /* Yes, if already indexed */
+    if (index)
+        return true;
+
+    /* Yes, if won't be copied up */
+    if (!ofs->upper_mnt)
+        return true;
+
+    /* No, if lower hardlink is or will be broken on copy up */
+    if ((upper || !ovl_indexdir(sb)) &&
+        !d_is_dir(lower) && d_inode(lower)->i_nlink > 1)
+        return false;
+
+    /* No, if non-indexed upper with NFS export */
+    if (sb->s_export_op && upper)
+        return false;
+
+    /* Otherwise, hash by lower inode for fsnotify */
+    return true;
+}
+
  struct inode *ovl_get_inode(struct dentry *dentry, struct dentry 
*upperdentry,
                  struct dentry *index)
  {
+    struct super_block *sb = dentry->d_sb;
      struct dentry *lowerdentry = ovl_dentry_lower(dentry);
      struct inode *realinode = upperdentry ? d_inode(upperdentry) : NULL;
      struct inode *inode;
-    /* Already indexed or could be indexed on copy up? */
-    bool indexed = (index || (ovl_indexdir(dentry->d_sb) && !upperdentry));
-    struct dentry *origin = indexed ? lowerdentry : NULL;
+    bool bylower = ovl_hash_bylower(sb, upperdentry, lowerdentry, index);
      bool is_dir;

-    if (WARN_ON(upperdentry && indexed && !lowerdentry))
-        return ERR_PTR(-EIO);
-
      if (!realinode)
          realinode = d_inode(lowerdentry);

      /*
-     * Copy up origin (lower) may exist for non-indexed non-dir upper, but
-     * we must not use lower as hash key in that case.
-     * Hash non-dir that is or could be indexed by origin inode.
-     * Hash dir that is or could be merged by origin inode.
-     * Hash pure upper and non-indexed non-dir by upper inode.
+     * Copy up origin (lower) may exist for non-indexed upper, but we must
+     * not use lower as hash key if this is a broken hardlink.
       */
      is_dir = S_ISDIR(realinode->i_mode);
-    if (is_dir)
-        origin = lowerdentry;
-
-    if (upperdentry || origin) {
-        struct inode *key = d_inode(origin ?: upperdentry);
+    if (upperdentry || bylower) {
+        struct inode *key = d_inode(bylower ? lowerdentry :
+                              upperdentry);
          unsigned int nlink = is_dir ? 1 : realinode->i_nlink;

-        inode = iget5_locked(dentry->d_sb, (unsigned long) key,
+        inode = iget5_locked(sb, (unsigned long) key,
                       ovl_inode_test, ovl_inode_set, key);
          if (!inode)
              goto out_nomem;
@@ -664,7 +689,8 @@ struct inode *ovl_get_inode(struct dentry *dentry, 
struct dentry *upperdentry,
              nlink = ovl_get_nlink(lowerdentry, upperdentry, nlink);
          set_nlink(inode, nlink);
      } else {
-        inode = new_inode(dentry->d_sb);
+        /* Lower hardlink that will be broken on copy up */
+        inode = new_inode(sb);
          if (!inode)
              goto out_nomem;
      }
-- 
2.18.0.597.ga71716f1ad-goog



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: ovl: hash non-dir by lower inode for fsnotify
  2018-08-02 15:29   ` ovl: hash non-dir by lower inode for fsnotify Mark Salyzyn
@ 2018-09-07  9:51     ` Greg KH
  2018-09-28 17:24       ` Mark Salyzyn
  0 siblings, 1 reply; 5+ messages in thread
From: Greg KH @ 2018-09-07  9:51 UTC (permalink / raw)
  To: Mark Salyzyn; +Cc: stable, kernel, Amir Goldstein, Miklos Szeredi

On Thu, Aug 02, 2018 at 08:29:02AM -0700, Mark Salyzyn wrote:
> On 08/01/2018 11:05 PM, Greg KH wrote:
> > On Wed, Aug 01, 2018 at 02:29:01PM -0700, Mark Salyzyn wrote:
> > > 764baba80168ad3adafb521d2ab483ccbc49e344 ovl: hash non-dir by lower inode
> > > for fsnotify is not part of 4.14 stable and yet it was marked for 4.13
> > > stable merge when committed.
> > > 
> > > Please evaluate.
> > Why not try applying it yourself to 4.14.y and note that it does not
> > apply at all and then provide a working backport so that we can skip at
> > least one email cycle here?  :)
> > 
> > thanks,
> > 
> > greg k-h
> 
> Because I am embarrassed by the backport (!) perhaps? :-)
> 
> +linux-kernel list and authors/approvers for clearance.
> 
> I took some liberty with sb = dentry_d_sb and then sprinkled it in, upstream
> passes sb to the function and the conflicts assumed so.
> 
> --------------------------> snip <-------------------------
> 
> From 764baba80168ad3adafb521d2ab483ccbc49e344 Mon Sep 17 00:00:00 2001
> From: Amir Goldstein <amir73il@gmail.com>
> Date: Sun, 4 Feb 2018 15:35:09 +0200
> Subject: ovl: hash non-dir by lower inode for fsnotify
> 
> (cherry pick from commit 764baba80168ad3adafb521d2ab483ccbc49e344)
> 
> Commit 31747eda41ef ("ovl: hash directory inodes for fsnotify")
> fixed an issue of inotify watch on directory that stops getting
> events after dropping dentry caches.
> 
> A similar issue exists for non-dir non-upper files, for example:
> 
> $ mkdir -p lower upper work merged
> $ touch lower/foo
> $ mount -t overlay -o
> lowerdir=lower,workdir=work,upperdir=upper none merged
> $ inotifywait merged/foo &
> $ echo 2 > /proc/sys/vm/drop_caches
> $ cat merged/foo
> 
> inotifywait doesn't get the OPEN event, because ovl_lookup() called
> from 'cat' allocates a new overlay inode and does not reuse the
> watched inode.
> 
> Fix this by hashing non-dir overlay inodes by lower real inode in
> the following cases that were not hashed before this change:
>  - A non-upper overlay mount
>  - A lower non-hardlink when index=off
> 
> A helper ovl_hash_bylower() was added to put all the logic and
> documentation about which real inode an overlay inode is hashed by
> into one place.
> 
> The issue dates back to initial version of overlayfs, but this
> patch depends on ovl_inode code that was introduced in kernel v4.13.
> 
> Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
> Cc: <stable@vger.kernel.org> #v4.13
> Signed-off-by: Mark Salyzyn <salyzyn@android.com> #v4.14
> ---
>  fs/overlayfs/inode.c | 62 +++++++++++++++++++++++++++++++-------------
>  1 file changed, 44 insertions(+), 18 deletions(-)
> 
> diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
> index 28a320464609a..7cfef4152e9a4 100644
> --- a/fs/overlayfs/inode.c
> +++ b/fs/overlayfs/inode.c
> @@ -14,6 +14,7 @@
>  #include <linux/posix_acl.h>
>  #include <linux/ratelimit.h>
>  #include "overlayfs.h"
> +#include "ovl_entry.h"
> 
>  int ovl_setattr(struct dentry *dentry, struct iattr *attr)
>  {
> @@ -608,39 +609,63 @@ static bool ovl_verify_inode(struct inode *inode,
> struct dentry *lowerdentry,

As this patch is deemed "good", can you please resend it in a
non-corrupted way so that I can apply it to the 4.14.y tree?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: ovl: hash non-dir by lower inode for fsnotify
  2018-09-07  9:51     ` Greg KH
@ 2018-09-28 17:24       ` Mark Salyzyn
  2018-09-30 15:40         ` Greg KH
  0 siblings, 1 reply; 5+ messages in thread
From: Mark Salyzyn @ 2018-09-28 17:24 UTC (permalink / raw)
  To: Greg KH; +Cc: stable, kernel, Amir Goldstein, Miklos Szeredi

On 09/07/2018 02:51 AM, Greg KH wrote:
> As this patch is deemed "good", can you please resend it in a
> non-corrupted way so that I can apply it to the 4.14.y tree?
>
> thanks,
>
> greg k-h

The toll of numerous vacations, and manic priorities that resulted, 
sorry for the delay, composed and resent.

-- Mark



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: ovl: hash non-dir by lower inode for fsnotify
  2018-09-28 17:24       ` Mark Salyzyn
@ 2018-09-30 15:40         ` Greg KH
  0 siblings, 0 replies; 5+ messages in thread
From: Greg KH @ 2018-09-30 15:40 UTC (permalink / raw)
  To: Mark Salyzyn; +Cc: stable, kernel, Amir Goldstein, Miklos Szeredi

On Fri, Sep 28, 2018 at 10:24:34AM -0700, Mark Salyzyn wrote:
> On 09/07/2018 02:51 AM, Greg KH wrote:
> > As this patch is deemed "good", can you please resend it in a
> > non-corrupted way so that I can apply it to the 4.14.y tree?
> > 
> > thanks,
> > 
> > greg k-h
> 
> The toll of numerous vacations, and manic priorities that resulted, sorry
> for the delay, composed and resent.

No worries, thanks for the patch, now queued up.

greg k-h

^ permalink raw reply	[flat|nested] 5+ messages in thread

* ovl: hash non-dir by lower inode for fsnotify
@ 2018-09-28 17:22 Mark Salyzyn
  0 siblings, 0 replies; 5+ messages in thread
From: Mark Salyzyn @ 2018-09-28 17:22 UTC (permalink / raw)
  To: linux-kernel
  Cc: Mark Salyzyn, Amir Goldstein, Miklos Szeredi, stable,
	linux-unionfs, Greg KH, Miklos Szeredi

(cherry pick from commit 764baba80168ad3adafb521d2ab483ccbc49e344)

Commit 31747eda41ef ("ovl: hash directory inodes for fsnotify")
fixed an issue of inotify watch on directory that stops getting
events after dropping dentry caches.

A similar issue exists for non-dir non-upper files, for example:

$ mkdir -p lower upper work merged
$ touch lower/foo
$ mount -t overlay -o
lowerdir=lower,workdir=work,upperdir=upper none merged
$ inotifywait merged/foo &
$ echo 2 > /proc/sys/vm/drop_caches
$ cat merged/foo

inotifywait doesn't get the OPEN event, because ovl_lookup() called
from 'cat' allocates a new overlay inode and does not reuse the
watched inode.

Fix this by hashing non-dir overlay inodes by lower real inode in
the following cases that were not hashed before this change:
 - A non-upper overlay mount
 - A lower non-hardlink when index=off

A helper ovl_hash_bylower() was added to put all the logic and
documentation about which real inode an overlay inode is hashed by
into one place.

The issue dates back to initial version of overlayfs, but this
patch depends on ovl_inode code that was introduced in kernel v4.13.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Cc: <stable@vger.kernel.org> #v4.13
Signed-off-by: Mark Salyzyn <salyzyn@android.com> #4.14
Cc: <linux-unionfs@vger.kernel.org>
Cc: <linux-kernel@vger.kernel.org>
Cc: Greg KH <gregkh@linuxfoundation.org>
---
 fs/overlayfs/inode.c | 62 +++++++++++++++++++++++++++++++-------------
 1 file changed, 44 insertions(+), 18 deletions(-)

diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index d60900b615f9..efed50304b49 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -14,6 +14,7 @@
 #include <linux/posix_acl.h>
 #include <linux/ratelimit.h>
 #include "overlayfs.h"
+#include "ovl_entry.h"
 
 int ovl_setattr(struct dentry *dentry, struct iattr *attr)
 {
@@ -608,39 +609,63 @@ static bool ovl_verify_inode(struct inode *inode, struct dentry *lowerdentry,
 	return true;
 }
 
+/*
+ * Does overlay inode need to be hashed by lower inode?
+ */
+static bool ovl_hash_bylower(struct super_block *sb, struct dentry *upper,
+			     struct dentry *lower, struct dentry *index)
+{
+	struct ovl_fs *ofs = sb->s_fs_info;
+
+	/* No, if pure upper */
+	if (!lower)
+		return false;
+
+	/* Yes, if already indexed */
+	if (index)
+		return true;
+
+	/* Yes, if won't be copied up */
+	if (!ofs->upper_mnt)
+		return true;
+
+	/* No, if lower hardlink is or will be broken on copy up */
+	if ((upper || !ovl_indexdir(sb)) &&
+	    !d_is_dir(lower) && d_inode(lower)->i_nlink > 1)
+		return false;
+
+	/* No, if non-indexed upper with NFS export */
+	if (sb->s_export_op && upper)
+		return false;
+
+	/* Otherwise, hash by lower inode for fsnotify */
+	return true;
+}
+
 struct inode *ovl_get_inode(struct dentry *dentry, struct dentry *upperdentry,
 			    struct dentry *index)
 {
+	struct super_block *sb = dentry->d_sb;
 	struct dentry *lowerdentry = ovl_dentry_lower(dentry);
 	struct inode *realinode = upperdentry ? d_inode(upperdentry) : NULL;
 	struct inode *inode;
-	/* Already indexed or could be indexed on copy up? */
-	bool indexed = (index || (ovl_indexdir(dentry->d_sb) && !upperdentry));
-	struct dentry *origin = indexed ? lowerdentry : NULL;
+	bool bylower = ovl_hash_bylower(sb, upperdentry, lowerdentry, index);
 	bool is_dir;
 
-	if (WARN_ON(upperdentry && indexed && !lowerdentry))
-		return ERR_PTR(-EIO);
-
 	if (!realinode)
 		realinode = d_inode(lowerdentry);
 
 	/*
-	 * Copy up origin (lower) may exist for non-indexed non-dir upper, but
-	 * we must not use lower as hash key in that case.
-	 * Hash non-dir that is or could be indexed by origin inode.
-	 * Hash dir that is or could be merged by origin inode.
-	 * Hash pure upper and non-indexed non-dir by upper inode.
+	 * Copy up origin (lower) may exist for non-indexed upper, but we must
+	 * not use lower as hash key if this is a broken hardlink.
 	 */
 	is_dir = S_ISDIR(realinode->i_mode);
-	if (is_dir)
-		origin = lowerdentry;
-
-	if (upperdentry || origin) {
-		struct inode *key = d_inode(origin ?: upperdentry);
+	if (upperdentry || bylower) {
+		struct inode *key = d_inode(bylower ? lowerdentry :
+						      upperdentry);
 		unsigned int nlink = is_dir ? 1 : realinode->i_nlink;
 
-		inode = iget5_locked(dentry->d_sb, (unsigned long) key,
+		inode = iget5_locked(sb, (unsigned long) key,
 				     ovl_inode_test, ovl_inode_set, key);
 		if (!inode)
 			goto out_nomem;
@@ -664,7 +689,8 @@ struct inode *ovl_get_inode(struct dentry *dentry, struct dentry *upperdentry,
 			nlink = ovl_get_nlink(lowerdentry, upperdentry, nlink);
 		set_nlink(inode, nlink);
 	} else {
-		inode = new_inode(dentry->d_sb);
+		/* Lower hardlink that will be broken on copy up */
+		inode = new_inode(sb);
 		if (!inode)
 			goto out_nomem;
 	}
-- 
2.19.0.605.g01d371f741-goog


^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2018-09-30 15:40 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <2630a5c0-ef57-a4cf-a6f4-b4996c64043b@android.com>
     [not found] ` <20180802060549.GB3272@kroah.com>
2018-08-02 15:29   ` ovl: hash non-dir by lower inode for fsnotify Mark Salyzyn
2018-09-07  9:51     ` Greg KH
2018-09-28 17:24       ` Mark Salyzyn
2018-09-30 15:40         ` Greg KH
2018-09-28 17:22 Mark Salyzyn

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).