]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.18-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 3 Aug 2017 23:03:46 +0000 (16:03 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 3 Aug 2017 23:03:46 +0000 (16:03 -0700)
added patches:
dentry-name-snapshots.patch

queue-3.18/dentry-name-snapshots.patch [new file with mode: 0644]
queue-3.18/series

diff --git a/queue-3.18/dentry-name-snapshots.patch b/queue-3.18/dentry-name-snapshots.patch
new file mode 100644 (file)
index 0000000..17dcd59
--- /dev/null
@@ -0,0 +1,229 @@
+From 49d31c2f389acfe83417083e1208422b4091cd9e Mon Sep 17 00:00:00 2001
+From: Al Viro <viro@zeniv.linux.org.uk>
+Date: Fri, 7 Jul 2017 14:51:19 -0400
+Subject: dentry name snapshots
+
+From: Al Viro <viro@zeniv.linux.org.uk>
+
+commit 49d31c2f389acfe83417083e1208422b4091cd9e upstream.
+
+take_dentry_name_snapshot() takes a safe snapshot of dentry name;
+if the name is a short one, it gets copied into caller-supplied
+structure, otherwise an extra reference to external name is grabbed
+(those are never modified).  In either case the pointer to stable
+string is stored into the same structure.
+
+dentry must be held by the caller of take_dentry_name_snapshot(),
+but may be freely dropped afterwards - the snapshot will stay
+until destroyed by release_dentry_name_snapshot().
+
+Intended use:
+       struct name_snapshot s;
+
+       take_dentry_name_snapshot(&s, dentry);
+       ...
+       access s.name
+       ...
+       release_dentry_name_snapshot(&s);
+
+Replaces fsnotify_oldname_...(), gets used in fsnotify to obtain the name
+to pass down with event.
+
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/dcache.c              |   27 +++++++++++++++++++++++++++
+ fs/debugfs/inode.c       |   10 +++++-----
+ fs/namei.c               |    8 ++++----
+ fs/notify/fsnotify.c     |    8 ++++++--
+ include/linux/dcache.h   |    7 +++++++
+ include/linux/fsnotify.h |   31 -------------------------------
+ 6 files changed, 49 insertions(+), 42 deletions(-)
+
+--- a/fs/dcache.c
++++ b/fs/dcache.c
+@@ -3549,3 +3549,30 @@ void __init vfs_caches_init(unsigned lon
+       bdev_cache_init();
+       chrdev_init();
+ }
++
++void take_dentry_name_snapshot(struct name_snapshot *name, struct dentry *dentry)
++{
++      spin_lock(&dentry->d_lock);
++      if (unlikely(dname_external(dentry))) {
++              struct external_name *p = external_name(dentry);
++              atomic_inc(&p->u.count);
++              spin_unlock(&dentry->d_lock);
++              name->name = p->name;
++      } else {
++              memcpy(name->inline_name, dentry->d_iname, DNAME_INLINE_LEN);
++              spin_unlock(&dentry->d_lock);
++              name->name = name->inline_name;
++      }
++}
++EXPORT_SYMBOL(take_dentry_name_snapshot);
++
++void release_dentry_name_snapshot(struct name_snapshot *name)
++{
++      if (unlikely(name->name != name->inline_name)) {
++              struct external_name *p;
++              p = container_of(name->name, struct external_name, name[0]);
++              if (unlikely(atomic_dec_and_test(&p->u.count)))
++                      kfree_rcu(p, u.head);
++      }
++}
++EXPORT_SYMBOL(release_dentry_name_snapshot);
+--- a/fs/debugfs/inode.c
++++ b/fs/debugfs/inode.c
+@@ -620,7 +620,7 @@ struct dentry *debugfs_rename(struct den
+ {
+       int error;
+       struct dentry *dentry = NULL, *trap;
+-      const char *old_name;
++      struct name_snapshot old_name;
+       trap = lock_rename(new_dir, old_dir);
+       /* Source or destination directories don't exist? */
+@@ -635,19 +635,19 @@ struct dentry *debugfs_rename(struct den
+       if (IS_ERR(dentry) || dentry == trap || dentry->d_inode)
+               goto exit;
+-      old_name = fsnotify_oldname_init(old_dentry->d_name.name);
++      take_dentry_name_snapshot(&old_name, old_dentry);
+       error = simple_rename(old_dir->d_inode, old_dentry, new_dir->d_inode,
+               dentry);
+       if (error) {
+-              fsnotify_oldname_free(old_name);
++              release_dentry_name_snapshot(&old_name);
+               goto exit;
+       }
+       d_move(old_dentry, dentry);
+-      fsnotify_move(old_dir->d_inode, new_dir->d_inode, old_name,
++      fsnotify_move(d_inode(old_dir), d_inode(new_dir), old_name.name,
+               S_ISDIR(old_dentry->d_inode->i_mode),
+               NULL, old_dentry);
+-      fsnotify_oldname_free(old_name);
++      release_dentry_name_snapshot(&old_name);
+       unlock_rename(new_dir, old_dir);
+       dput(dentry);
+       return old_dentry;
+--- a/fs/namei.c
++++ b/fs/namei.c
+@@ -4088,11 +4088,11 @@ int vfs_rename(struct inode *old_dir, st
+ {
+       int error;
+       bool is_dir = d_is_dir(old_dentry);
+-      const unsigned char *old_name;
+       struct inode *source = old_dentry->d_inode;
+       struct inode *target = new_dentry->d_inode;
+       bool new_is_dir = false;
+       unsigned max_links = new_dir->i_sb->s_max_links;
++      struct name_snapshot old_name;
+       if (source == target)
+               return 0;
+@@ -4142,7 +4142,7 @@ int vfs_rename(struct inode *old_dir, st
+       if (error)
+               return error;
+-      old_name = fsnotify_oldname_init(old_dentry->d_name.name);
++      take_dentry_name_snapshot(&old_name, old_dentry);
+       dget(new_dentry);
+       if (!is_dir || (flags & RENAME_EXCHANGE))
+               lock_two_nondirectories(source, target);
+@@ -4203,14 +4203,14 @@ out:
+               mutex_unlock(&target->i_mutex);
+       dput(new_dentry);
+       if (!error) {
+-              fsnotify_move(old_dir, new_dir, old_name, is_dir,
++              fsnotify_move(old_dir, new_dir, old_name.name, is_dir,
+                             !(flags & RENAME_EXCHANGE) ? target : NULL, old_dentry);
+               if (flags & RENAME_EXCHANGE) {
+                       fsnotify_move(new_dir, old_dir, old_dentry->d_name.name,
+                                     new_is_dir, NULL, new_dentry);
+               }
+       }
+-      fsnotify_oldname_free(old_name);
++      release_dentry_name_snapshot(&old_name);
+       return error;
+ }
+--- a/fs/notify/fsnotify.c
++++ b/fs/notify/fsnotify.c
+@@ -105,16 +105,20 @@ int __fsnotify_parent(struct path *path,
+       if (unlikely(!fsnotify_inode_watches_children(p_inode)))
+               __fsnotify_update_child_dentry_flags(p_inode);
+       else if (p_inode->i_fsnotify_mask & mask) {
++              struct name_snapshot name;
++
+               /* we are notifying a parent so come up with the new mask which
+                * specifies these are events which came from a child. */
+               mask |= FS_EVENT_ON_CHILD;
++              take_dentry_name_snapshot(&name, dentry);
+               if (path)
+                       ret = fsnotify(p_inode, mask, path, FSNOTIFY_EVENT_PATH,
+-                                     dentry->d_name.name, 0);
++                                     name.name, 0);
+               else
+                       ret = fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
+-                                     dentry->d_name.name, 0);
++                                     name.name, 0);
++              release_dentry_name_snapshot(&name);
+       }
+       dput(parent);
+--- a/include/linux/dcache.h
++++ b/include/linux/dcache.h
+@@ -527,4 +527,11 @@ static inline struct dentry *d_backing_d
+       return upper;
+ }
++struct name_snapshot {
++      const char *name;
++      char inline_name[DNAME_INLINE_LEN];
++};
++void take_dentry_name_snapshot(struct name_snapshot *, struct dentry *);
++void release_dentry_name_snapshot(struct name_snapshot *);
++
+ #endif        /* __LINUX_DCACHE_H */
+--- a/include/linux/fsnotify.h
++++ b/include/linux/fsnotify.h
+@@ -310,35 +310,4 @@ static inline void fsnotify_change(struc
+       }
+ }
+-#if defined(CONFIG_FSNOTIFY)  /* notify helpers */
+-
+-/*
+- * fsnotify_oldname_init - save off the old filename before we change it
+- */
+-static inline const unsigned char *fsnotify_oldname_init(const unsigned char *name)
+-{
+-      return kstrdup(name, GFP_KERNEL);
+-}
+-
+-/*
+- * fsnotify_oldname_free - free the name we got from fsnotify_oldname_init
+- */
+-static inline void fsnotify_oldname_free(const unsigned char *old_name)
+-{
+-      kfree(old_name);
+-}
+-
+-#else /* CONFIG_FSNOTIFY */
+-
+-static inline const char *fsnotify_oldname_init(const unsigned char *name)
+-{
+-      return NULL;
+-}
+-
+-static inline void fsnotify_oldname_free(const unsigned char *old_name)
+-{
+-}
+-
+-#endif        /*  CONFIG_FSNOTIFY */
+-
+ #endif        /* _LINUX_FS_NOTIFY_H */
index a1595501a4258abe8d890debcabc0176959864d7..075f5374eebadf6c7ca043a97cd03b6b847bbb70 100644 (file)
@@ -29,3 +29,4 @@ net-sctp-fix-race-for-one-to-many-sockets-in-sendmsg-s-auto-associate.patch
 sh_eth-fix-ethtool-operation-crash-when-net-device-is-down.patch
 net-sched-fix-soft-lockup-in-tc_classify.patch
 ipmi-watchdog-fix-watchdog-timeout-set-on-reboot.patch
+dentry-name-snapshots.patch