* INFORMATIONAL ONLY - NO ACTION/READING NEEDED BUG: https://bugs.linaro.org/show_bug.cgi?id=3881 Because the lack of the following commit: commit 764baba80168ad3adafb521d2ab483ccbc49e344 Author: Amir Goldstein <amir73il@xxxxxxxxx> Date: Sun Feb 4 15:35:09 2018 +0200 ovl: hash non-dir by lower inode for fsnotify INFO: inotify issue with non-dir non-upper files in overlayfs exists in LTS <= v4.14. INFO: LTP inotify08 test fails on * v4.14 and bellow * and should be skipped. Trying to cherry-pick to v4.14 has proven not to be feasible without bringing many new features/code into LTS tree (up to any Linux distribution to decide to backport or not). For clean cherry picks, commits: ovl: hash non-dir by lower inode for fsnotify ovl: hash non-indexed dir by upper inode for NFS export ovl: do not pass overlay dentry to ovl_get_inode() ovl: hash directory inodes for fsnotify ovl: no direct iteration for dir with origin xattr Revert "ovl: hash directory inodes for fsnotify" are needed AND all the logic for setting up "origin" variable in ovl_lookup, passed to ovl_lookup_index() after it got its prototype changed, would still be missing. Unfortunately the "origin" also depends on commit 051224438 ("ovl: generalize ovl_verify_origin() and helpers") and some others ones that refactor many functions. -Rafael On Mon, Mar 12, 2018 at 12:02 PM <gregkh@xxxxxxxxxxxxxxxxxxx> wrote: > > > The patch below does not apply to the 4.14-stable tree. > If someone wants it applied there, or to any other stable or longterm > tree, then please email the backport, including the original git commit > id to <stable@xxxxxxxxxxxxxxx>. > > thanks, > > greg k-h > > ------------------ original commit in Linus's tree ------------------ > > From 764baba80168ad3adafb521d2ab483ccbc49e344 Mon Sep 17 00:00:00 2001 > From: Amir Goldstein <amir73il@xxxxxxxxx> > Date: Sun, 4 Feb 2018 15:35:09 +0200 > Subject: [PATCH] ovl: hash non-dir by lower inode for fsnotify > > 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. > > Cc: <stable@xxxxxxxxxxxxxxx> #v4.13 > Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx> > Signed-off-by: Miklos Szeredi <mszeredi@xxxxxxxxxx> > > diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c > index fcd97b783fa1..3b1bd469accd 100644 > --- a/fs/overlayfs/inode.c > +++ b/fs/overlayfs/inode.c > @@ -669,38 +669,59 @@ struct inode *ovl_lookup_inode(struct super_block *sb, struct dentry *real, > return inode; > } > > +/* > + * 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 super_block *sb, struct dentry *upperdentry, > struct dentry *lowerdentry, struct dentry *index, > unsigned int numlower) > { > - struct ovl_fs *ofs = sb->s_fs_info; > 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(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. > - * Hash non-indexed dir by upper inode for NFS export. > + * 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 && (indexed || !sb->s_export_op || !ofs->upper_mnt)) > - 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(sb, (unsigned long) key, > @@ -728,6 +749,7 @@ struct inode *ovl_get_inode(struct super_block *sb, struct dentry *upperdentry, > nlink = ovl_get_nlink(lowerdentry, upperdentry, nlink); > set_nlink(inode, nlink); > } else { > + /* Lower hardlink that will be broken on copy up */ > inode = new_inode(sb); > if (!inode) > goto out_nomem; >