[RFC 2/2] fanotify: emit FAN_MODIFY_DIR on filesystem changes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Besause fanotify requires `struct path`, the event cannot be generated
directly in `fsnotify_move` and friends because they only get the inode
(and their callers, `vfs_rename`&co. cannot supply any better info).
So instead it needs to be generated higher in the call chain, i.e. in
the callers of functions like `vfs_rename`.

This leads to some code duplication. Currently, there are several places
whence functions like `vfs_rename` or `vfs_unlink` are called:

  * syscall handlers (done)
  * NFS server (done)
  * stacked filesystems
      - ecryptfs (done)
      - overlayfs
        (Currently doesn't report even ordinary fanotify events, because
         it internally clones the upper mount; not sure about the
         rationale.  One can always watch the overlay mount instead.)
  * few rather minor things
      - devtmpfs
        (its internal changes are not tied to any vfsmount so it cannot
         emit mount-scoped events)
      - cachefiles (done)
      - ipc/mqueue.c (done)
      - fs/nfsd/nfs4recover.c (done)
      - kernel/bpf/inode.c (done)
        net/unix/af_unix.c (done)

(grep -rE '\bvfs_(rename|unlink|mknod|whiteout|create|mkdir|rmdir|symlink|link)\(')

Signed-off-by: Filip Štědronský <r.lkml@xxxxxxxxxx>

---

An alternative might be to create wrapper functions like
vfs_path_(rename|unlink|...). They could also take care of calling
security_path_(rename|unlink|...), which is currently also up to
the indvidual callers (possibly with a flag because it might not
be always desired).
---
 fs/cachefiles/namei.c |  9 +++++++
 fs/ecryptfs/inode.c   | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/namei.c            | 23 +++++++++++++++++-
 fs/nfsd/nfs4recover.c |  7 ++++++
 fs/nfsd/vfs.c         | 24 ++++++++++++++++--
 ipc/mqueue.c          |  9 +++++++
 kernel/bpf/inode.c    |  3 +++
 net/unix/af_unix.c    |  2 ++
 8 files changed, 141 insertions(+), 3 deletions(-)

diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c
index 41df8a27d7eb..8c86699424d1 100644
--- a/fs/cachefiles/namei.c
+++ b/fs/cachefiles/namei.c
@@ -313,6 +313,8 @@ static int cachefiles_bury_object(struct cachefiles_cache *cache,
 			cachefiles_io_error(cache, "Unlink security error");
 		} else {
 			ret = vfs_unlink(d_inode(dir), rep, NULL);
+			if (ret == 0)
+				fsnotify_modify_dir(&path);
 
 			if (preemptive)
 				cachefiles_mark_object_buried(cache, rep, why);
@@ -418,6 +420,10 @@ static int cachefiles_bury_object(struct cachefiles_cache *cache,
 		if (ret != 0 && ret != -ENOMEM)
 			cachefiles_io_error(cache,
 					    "Rename failed with error %d", ret);
+		if (ret == 0) {
+			fsnotify_modify_dir(&path);
+			fsnotify_modify_dir(&path_to_graveyard);
+		}
 
 		if (preemptive)
 			cachefiles_mark_object_buried(cache, rep, why);
@@ -560,6 +566,7 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent,
 			cachefiles_hist(cachefiles_mkdir_histogram, start);
 			if (ret < 0)
 				goto create_error;
+			fsnotify_modify_dir(&path);
 
 			ASSERT(d_backing_inode(next));
 
@@ -589,6 +596,7 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent,
 			cachefiles_hist(cachefiles_create_histogram, start);
 			if (ret < 0)
 				goto create_error;
+			fsnotify_modify_dir(&path);
 
 			ASSERT(d_backing_inode(next));
 
@@ -779,6 +787,7 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
 		ret = vfs_mkdir(d_inode(dir), subdir, 0700);
 		if (ret < 0)
 			goto mkdir_error;
+		fsnotify_modify_dir(&path);
 
 		ASSERT(d_backing_inode(subdir));
 
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index e7413f82d27b..88a41b270bcc 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -29,6 +29,8 @@
 #include <linux/dcache.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
+#include <linux/path.h>
+#include <linux/fsnotify.h>
 #include <linux/fs_stack.h>
 #include <linux/slab.h>
 #include <linux/xattr.h>
@@ -144,16 +146,22 @@ static int ecryptfs_do_unlink(struct inode *dir, struct dentry *dentry,
 {
 	struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
 	struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir);
+	struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
+	struct path lower_dir_path = {lower_mnt, NULL};
 	struct dentry *lower_dir_dentry;
 	int rc;
 
 	dget(lower_dentry);
 	lower_dir_dentry = lock_parent(lower_dentry);
+	lower_dir_path.dentry = lower_dir_dentry;
 	rc = vfs_unlink(lower_dir_inode, lower_dentry, NULL);
 	if (rc) {
 		printk(KERN_ERR "Error in vfs_unlink; rc = [%d]\n", rc);
 		goto out_unlock;
 	}
+
+	fsnotify_modify_dir(&lower_dir_path);
+
 	fsstack_copy_attr_times(dir, lower_dir_inode);
 	set_nlink(inode, ecryptfs_inode_to_lower(inode)->i_nlink);
 	inode->i_ctime = dir->i_ctime;
@@ -184,9 +192,13 @@ ecryptfs_do_create(struct inode *directory_inode,
 	struct dentry *lower_dentry;
 	struct dentry *lower_dir_dentry;
 	struct inode *inode;
+	struct path lower_dir_path;
 
 	lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
 	lower_dir_dentry = lock_parent(lower_dentry);
+	lower_dir_path.dentry = lower_dir_dentry;
+	lower_dir_path.mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry);
+
 	rc = vfs_create(d_inode(lower_dir_dentry), lower_dentry, mode, true);
 	if (rc) {
 		printk(KERN_ERR "%s: Failure to create dentry in lower fs; "
@@ -194,10 +206,14 @@ ecryptfs_do_create(struct inode *directory_inode,
 		inode = ERR_PTR(rc);
 		goto out_lock;
 	}
+
+	fsnotify_modify_dir(&lower_dir_path);
+
 	inode = __ecryptfs_get_inode(d_inode(lower_dentry),
 				     directory_inode->i_sb);
 	if (IS_ERR(inode)) {
 		vfs_unlink(d_inode(lower_dir_dentry), lower_dentry, NULL);
+		fsnotify_modify_dir(&lower_dir_path);
 		goto out_lock;
 	}
 	fsstack_copy_attr_times(directory_inode, d_inode(lower_dir_dentry));
@@ -432,6 +448,7 @@ static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir,
 	struct dentry *lower_old_dentry;
 	struct dentry *lower_new_dentry;
 	struct dentry *lower_dir_dentry;
+	struct path lower_dir_path;
 	u64 file_size_save;
 	int rc;
 
@@ -441,10 +458,16 @@ static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir,
 	dget(lower_old_dentry);
 	dget(lower_new_dentry);
 	lower_dir_dentry = lock_parent(lower_new_dentry);
+	lower_dir_path.dentry = lower_dir_dentry;
+	lower_dir_path.mnt = ecryptfs_dentry_to_lower_mnt(new_dentry);
+
 	rc = vfs_link(lower_old_dentry, d_inode(lower_dir_dentry),
 		      lower_new_dentry, NULL);
 	if (rc || d_really_is_negative(lower_new_dentry))
 		goto out_lock;
+
+	fsnotify_modify_dir(&lower_dir_path);
+
 	rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb);
 	if (rc)
 		goto out_lock;
@@ -471,6 +494,7 @@ static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
 	int rc;
 	struct dentry *lower_dentry;
 	struct dentry *lower_dir_dentry;
+	struct path lower_dir_path;
 	char *encoded_symname;
 	size_t encoded_symlen;
 	struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL;
@@ -478,6 +502,9 @@ static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
 	lower_dentry = ecryptfs_dentry_to_lower(dentry);
 	dget(lower_dentry);
 	lower_dir_dentry = lock_parent(lower_dentry);
+	lower_dir_path.dentry = lower_dir_dentry;
+	lower_dir_path.mnt = ecryptfs_dentry_to_lower_mnt(dentry);
+
 	mount_crypt_stat = &ecryptfs_superblock_to_private(
 		dir->i_sb)->mount_crypt_stat;
 	rc = ecryptfs_encrypt_and_encode_filename(&encoded_symname,
@@ -491,6 +518,9 @@ static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
 	kfree(encoded_symname);
 	if (rc || d_really_is_negative(lower_dentry))
 		goto out_lock;
+
+	fsnotify_modify_dir(&lower_dir_path);
+
 	rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb);
 	if (rc)
 		goto out_lock;
@@ -509,12 +539,18 @@ static int ecryptfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
 	int rc;
 	struct dentry *lower_dentry;
 	struct dentry *lower_dir_dentry;
+	struct path lower_dir_path;
 
 	lower_dentry = ecryptfs_dentry_to_lower(dentry);
 	lower_dir_dentry = lock_parent(lower_dentry);
+	lower_dir_path.dentry = lower_dir_dentry;
+	lower_dir_path.mnt = ecryptfs_dentry_to_lower_mnt(dentry);
 	rc = vfs_mkdir(d_inode(lower_dir_dentry), lower_dentry, mode);
 	if (rc || d_really_is_negative(lower_dentry))
 		goto out;
+
+	fsnotify_modify_dir(&lower_dir_path);
+
 	rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb);
 	if (rc)
 		goto out;
@@ -532,16 +568,24 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
 	struct dentry *lower_dentry;
 	struct dentry *lower_dir_dentry;
+	struct path lower_dir_path;
 	int rc;
 
 	lower_dentry = ecryptfs_dentry_to_lower(dentry);
 	dget(dentry);
 	lower_dir_dentry = lock_parent(lower_dentry);
+	lower_dir_path.dentry = lower_dir_dentry;
+	lower_dir_path.mnt = ecryptfs_dentry_to_lower_mnt(dentry);
 	dget(lower_dentry);
+
 	rc = vfs_rmdir(d_inode(lower_dir_dentry), lower_dentry);
 	dput(lower_dentry);
 	if (!rc && d_really_is_positive(dentry))
 		clear_nlink(d_inode(dentry));
+
+	if (rc)
+		fsnotify_modify_dir(&lower_dir_path);
+
 	fsstack_copy_attr_times(dir, d_inode(lower_dir_dentry));
 	set_nlink(dir, d_inode(lower_dir_dentry)->i_nlink);
 	unlock_dir(lower_dir_dentry);
@@ -557,12 +601,19 @@ ecryptfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev
 	int rc;
 	struct dentry *lower_dentry;
 	struct dentry *lower_dir_dentry;
+	struct path lower_dir_path;
 
 	lower_dentry = ecryptfs_dentry_to_lower(dentry);
 	lower_dir_dentry = lock_parent(lower_dentry);
+	lower_dir_path.dentry = lower_dir_dentry;
+	lower_dir_path.mnt = ecryptfs_dentry_to_lower_mnt(dentry);
+
 	rc = vfs_mknod(d_inode(lower_dir_dentry), lower_dentry, mode, dev);
 	if (rc || d_really_is_negative(lower_dentry))
 		goto out;
+
+	fsnotify_modify_dir(&lower_dir_path);
+
 	rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb);
 	if (rc)
 		goto out;
@@ -585,6 +636,9 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 	struct dentry *lower_new_dentry;
 	struct dentry *lower_old_dir_dentry;
 	struct dentry *lower_new_dir_dentry;
+	struct vfsmount *lower_mnt;
+	struct path lower_old_dir_path;
+	struct path lower_new_dir_path;
 	struct dentry *trap = NULL;
 	struct inode *target_inode;
 
@@ -593,10 +647,15 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
 	lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
 	lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
+	lower_mnt = ecryptfs_dentry_to_lower_mnt(old_dentry);
 	dget(lower_old_dentry);
 	dget(lower_new_dentry);
 	lower_old_dir_dentry = dget_parent(lower_old_dentry);
 	lower_new_dir_dentry = dget_parent(lower_new_dentry);
+	lower_old_dir_path.dentry = lower_old_dir_dentry;
+	lower_old_dir_path.mnt = lower_mnt;
+	lower_new_dir_path.dentry = lower_new_dir_dentry;
+	lower_new_dir_path.mnt = lower_mnt;
 	target_inode = d_inode(new_dentry);
 	trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
 	/* source should not be ancestor of target */
@@ -614,6 +673,14 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 			NULL, 0);
 	if (rc)
 		goto out_lock;
+
+	/* ecryptfs does not support crossing mount boundaries, we can take
+	 * vfsmount from an arbitrary dentry.
+	 */
+	fsnotify_modify_dir(&lower_old_dir_path);
+	if (!path_equal(&lower_old_dir_path, &lower_new_dir_path))
+		fsnotify_modify_dir(&lower_new_dir_path);
+
 	if (target_inode)
 		fsstack_copy_attr_all(target_inode,
 				      ecryptfs_inode_to_lower(target_inode));
diff --git a/fs/namei.c b/fs/namei.c
index ad74877e1442..17667f0c89e5 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3009,8 +3009,12 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
 				dput(dentry);
 				dentry = file->f_path.dentry;
 			}
-			if (*opened & FILE_CREATED)
+			if (*opened & FILE_CREATED) {
+				struct path parent_path = {file->f_path.mnt,
+							dentry->d_parent};
 				fsnotify_create(dir, dentry);
+				fsnotify_modify_dir(&parent_path);
+			}
 			if (unlikely(d_is_negative(dentry))) {
 				error = -ENOENT;
 			} else {
@@ -3157,6 +3161,7 @@ static int lookup_open(struct nameidata *nd, struct path *path,
 		if (error)
 			goto out_dput;
 		fsnotify_create(dir_inode, dentry);
+		fsnotify_modify_dir(&nd->path);
 	}
 	if (unlikely(create_error) && !dentry->d_inode) {
 		error = create_error;
@@ -3702,6 +3707,7 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode,
 			error = vfs_mknod(path.dentry->d_inode,dentry,mode,0);
 			break;
 	}
+	fsnotify_modify_dir(&path);
 out:
 	done_path_create(&path, dentry);
 	if (retry_estale(error, lookup_flags)) {
@@ -3759,6 +3765,8 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
 	error = security_path_mkdir(&path, dentry, mode);
 	if (!error)
 		error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
+	if (!error)
+		fsnotify_modify_dir(&path);
 	done_path_create(&path, dentry);
 	if (retry_estale(error, lookup_flags)) {
 		lookup_flags |= LOOKUP_REVAL;
@@ -3855,6 +3863,8 @@ static long do_rmdir(int dfd, const char __user *pathname)
 	if (error)
 		goto exit3;
 	error = vfs_rmdir(path.dentry->d_inode, dentry);
+	if (!error)
+		fsnotify_modify_dir(&path);
 exit3:
 	dput(dentry);
 exit2:
@@ -3979,6 +3989,8 @@ static long do_unlinkat(int dfd, const char __user *pathname)
 		if (error)
 			goto exit2;
 		error = vfs_unlink(path.dentry->d_inode, dentry, &delegated_inode);
+		if (!error)
+			fsnotify_modify_dir(&path);
 exit2:
 		dput(dentry);
 	}
@@ -4070,6 +4082,8 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
 	error = security_path_symlink(&path, dentry, from->name);
 	if (!error)
 		error = vfs_symlink(path.dentry->d_inode, dentry, from->name);
+	if (!error)
+		fsnotify_modify_dir(&path);
 	done_path_create(&path, dentry);
 	if (retry_estale(error, lookup_flags)) {
 		lookup_flags |= LOOKUP_REVAL;
@@ -4219,6 +4233,8 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
 	if (error)
 		goto out_dput;
 	error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry, &delegated_inode);
+	if (!error)
+		fsnotify_modify_dir(&new_path);
 out_dput:
 	done_path_create(&new_path, new_dentry);
 	if (delegated_inode) {
@@ -4532,6 +4548,11 @@ SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
 	error = vfs_rename(old_path.dentry->d_inode, old_dentry,
 			   new_path.dentry->d_inode, new_dentry,
 			   &delegated_inode, flags);
+	if (error == 0) {
+		fsnotify_modify_dir(&old_path);
+		if (!path_equal(&old_path, &new_path))
+			fsnotify_modify_dir(&new_path);
+	}
 exit5:
 	dput(new_dentry);
 exit4:
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 66eaeb1e8c2c..58f70bbaac38 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -36,6 +36,7 @@
 #include <linux/file.h>
 #include <linux/slab.h>
 #include <linux/namei.h>
+#include <linux/fsnotify.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/module.h>
@@ -216,6 +217,8 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
 		 */
 		goto out_put;
 	status = vfs_mkdir(d_inode(dir), dentry, S_IRWXU);
+	if (status == 0)
+		fsnotify_modify_dir(&nn->rec_file->f_path);
 out_put:
 	dput(dentry);
 out_unlock:
@@ -338,6 +341,8 @@ nfsd4_unlink_clid_dir(char *name, int namlen, struct nfsd_net *nn)
 	if (d_really_is_negative(dentry))
 		goto out;
 	status = vfs_rmdir(d_inode(dir), dentry);
+	if (status == 0)
+		fsnotify_modify_dir(&nn->rec_file->f_path);
 out:
 	dput(dentry);
 out_unlock:
@@ -401,6 +406,8 @@ purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn)
 	if (status)
 		printk("failed to remove client recovery directory %pd\n",
 				child);
+	else
+		fsnotify_modify_dir(&nn->rec_file->f_path);
 	/* Keep trying, success or failure: */
 	return 0;
 }
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 26c6fdb4bf67..7632ab3fd99e 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -364,6 +364,18 @@ nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp,
 }
 
 /*
+ * Helper to emit fsnotify modify_dir event. Call with fph locked.
+ */
+static void nfsd_fsnotify_modify_dir(struct svc_fh *fhp)
+{
+	struct path path;
+
+	path.mnt = fhp->fh_export->ex_path.mnt;
+	path.dentry = fhp->fh_dentry;
+	fsnotify_modify_dir(&path);
+}
+
+/*
  * Set various file attributes.  After this call fhp needs an fh_put.
  */
 __be32
@@ -1207,6 +1219,7 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp,
 		goto out_nfserr;
 
 	err = nfsd_create_setattr(rqstp, resfhp, iap);
+	nfsd_fsnotify_modify_dir(fhp);
 
 	/*
 	 * nfsd_create_setattr already committed the child.  Transactional
@@ -1525,8 +1538,10 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
 
 	host_err = vfs_symlink(d_inode(dentry), dnew, path);
 	err = nfserrno(host_err);
-	if (!err)
+	if (!err) {
+		nfsd_fsnotify_modify_dir(fhp);
 		err = nfserrno(commit_metadata(fhp));
+	}
 	fh_unlock(fhp);
 
 	fh_drop_write(fhp);
@@ -1593,6 +1608,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
 		goto out_dput;
 	host_err = vfs_link(dold, dirp, dnew, NULL);
 	if (!host_err) {
+		nfsd_fsnotify_modify_dir(tfhp);
 		err = nfserrno(commit_metadata(ffhp));
 		if (!err)
 			err = nfserrno(commit_metadata(tfhp));
@@ -1686,6 +1702,8 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
 
 	host_err = vfs_rename(fdir, odentry, tdir, ndentry, NULL, 0);
 	if (!host_err) {
+		nfsd_fsnotify_modify_dir(tfhp);
+		nfsd_fsnotify_modify_dir(ffhp);
 		host_err = commit_metadata(tfhp);
 		if (!host_err)
 			host_err = commit_metadata(ffhp);
@@ -1757,8 +1775,10 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
 		host_err = vfs_unlink(dirp, rdentry, NULL);
 	else
 		host_err = vfs_rmdir(dirp, rdentry);
-	if (!host_err)
+	if (!host_err) {
+		nfsd_fsnotify_modify_dir(fhp);
 		host_err = commit_metadata(fhp);
+	}
 	dput(rdentry);
 
 out_nfserr:
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 7a2d8f0c8ae5..10e413c2216f 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -19,6 +19,7 @@
 #include <linux/file.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
+#include <linux/fsnotify.h>
 #include <linux/sysctl.h>
 #include <linux/poll.h>
 #include <linux/mqueue.h>
@@ -818,6 +819,10 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
 			filp = do_create(ipc_ns, d_inode(root),
 						&path, oflag, mode,
 						u_attr ? &attr : NULL);
+			if (!IS_ERR(filp)) {
+				struct path root_path = {mnt, mnt->mnt_root};
+				fsnotify_modify_dir(&root_path);
+			}
 		}
 	} else {
 		if (d_really_is_negative(path.dentry)) {
@@ -878,6 +883,10 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
 	} else {
 		ihold(inode);
 		err = vfs_unlink(d_inode(dentry->d_parent), dentry, NULL);
+		if (!err) {
+			struct path path = {mnt, dentry->d_parent};
+			fsnotify_modify_dir(&path);
+		}
 	}
 	dput(dentry);
 
diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c
index 0b030c9126d3..93137292b051 100644
--- a/kernel/bpf/inode.c
+++ b/kernel/bpf/inode.c
@@ -16,6 +16,7 @@
 #include <linux/major.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
+#include <linux/fsnotify.h>
 #include <linux/fs.h>
 #include <linux/kdev_t.h>
 #include <linux/parser.h>
@@ -255,6 +256,8 @@ static int bpf_obj_do_pin(const struct filename *pathname, void *raw,
 
 	dentry->d_fsdata = raw;
 	ret = vfs_mknod(dir, dentry, mode, devt);
+	if (ret == 0)
+		fsnotify_modify_dir(&path);
 	dentry->d_fsdata = NULL;
 out:
 	done_path_create(&path, dentry);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index cef79873b09d..5049bd4bd1d8 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -91,6 +91,7 @@
 #include <linux/stat.h>
 #include <linux/dcache.h>
 #include <linux/namei.h>
+#include <linux/fsnotify.h>
 #include <linux/socket.h>
 #include <linux/un.h>
 #include <linux/fcntl.h>
@@ -976,6 +977,7 @@ static int unix_mknod(const char *sun_path, umode_t mode, struct path *res)
 	if (!err) {
 		err = vfs_mknod(d_inode(path.dentry), dentry, mode, 0);
 		if (!err) {
+			fsnotify_modify_dir(&path);
 			res->mnt = mntget(path.mnt);
 			res->dentry = dget(dentry);
 		}
-- 
2.11.1




[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux