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

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

diff --git a/queue-4.12/dentry-name-snapshots.patch b/queue-4.12/dentry-name-snapshots.patch
new file mode 100644 (file)
index 0000000..16125a1
--- /dev/null
@@ -0,0 +1,232 @@
+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   |    6 ++++++
+ include/linux/fsnotify.h |   31 -------------------------------
+ 6 files changed, 48 insertions(+), 42 deletions(-)
+
+--- a/fs/dcache.c
++++ b/fs/dcache.c
+@@ -277,6 +277,33 @@ static inline int dname_external(const s
+       return dentry->d_name.name != dentry->d_iname;
+ }
++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);
++
+ static inline void __d_set_inode_and_type(struct dentry *dentry,
+                                         struct inode *inode,
+                                         unsigned type_flags)
+--- a/fs/debugfs/inode.c
++++ b/fs/debugfs/inode.c
+@@ -766,7 +766,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? */
+@@ -781,19 +781,19 @@ struct dentry *debugfs_rename(struct den
+       if (IS_ERR(dentry) || dentry == trap || d_really_is_positive(dentry))
+               goto exit;
+-      old_name = fsnotify_oldname_init(old_dentry->d_name.name);
++      take_dentry_name_snapshot(&old_name, old_dentry);
+       error = simple_rename(d_inode(old_dir), old_dentry, d_inode(new_dir),
+                             dentry, 0);
+       if (error) {
+-              fsnotify_oldname_free(old_name);
++              release_dentry_name_snapshot(&old_name);
+               goto exit;
+       }
+       d_move(old_dentry, dentry);
+-      fsnotify_move(d_inode(old_dir), d_inode(new_dir), old_name,
++      fsnotify_move(d_inode(old_dir), d_inode(new_dir), old_name.name,
+               d_is_dir(old_dentry),
+               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
+@@ -4362,11 +4362,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;
+@@ -4413,7 +4413,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);
+@@ -4468,14 +4468,14 @@ out:
+               inode_unlock(target);
+       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
+@@ -161,16 +161,20 @@ int __fsnotify_parent(const struct 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
+@@ -591,5 +591,11 @@ static inline struct inode *d_real_inode
+       return d_backing_inode(d_real((struct dentry *) dentry, NULL, 0));
+ }
++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
+@@ -293,35 +293,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 958483e7c6d4485cf9ea42891181419b3ff8bbbd..b669f5408d9e51ae9293295132f1c4688035790c 100644 (file)
@@ -27,3 +27,4 @@ drm-nouveau-bar-gf100-fix-access-to-upper-half-of-bar2.patch
 drm-i915-fix-scaler-init-during-crtc-hw-state-readout.patch
 isdn-i4l-fix-buffer-overflow.patch
 ipmi-watchdog-fix-watchdog-timeout-set-on-reboot.patch
+dentry-name-snapshots.patch