Revert "Bluetooth: Store advertising handle so it can be re-enabled"
[platform/kernel/linux-rpi.git] / fs / namei.c
index 94565bd..e728ba0 100644 (file)
@@ -3021,20 +3021,14 @@ static struct dentry *lock_two_directories(struct dentry *p1, struct dentry *p2)
        p = d_ancestor(p2, p1);
        if (p) {
                inode_lock_nested(p2->d_inode, I_MUTEX_PARENT);
-               inode_lock_nested(p1->d_inode, I_MUTEX_CHILD);
+               inode_lock_nested(p1->d_inode, I_MUTEX_PARENT2);
                return p;
        }
 
        p = d_ancestor(p1, p2);
-       if (p) {
-               inode_lock_nested(p1->d_inode, I_MUTEX_PARENT);
-               inode_lock_nested(p2->d_inode, I_MUTEX_CHILD);
-               return p;
-       }
-
-       lock_two_inodes(p1->d_inode, p2->d_inode,
-                       I_MUTEX_PARENT, I_MUTEX_PARENT2);
-       return NULL;
+       inode_lock_nested(p1->d_inode, I_MUTEX_PARENT);
+       inode_lock_nested(p2->d_inode, I_MUTEX_PARENT2);
+       return p;
 }
 
 /*
@@ -4733,11 +4727,12 @@ SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname
  *
  *     a) we can get into loop creation.
  *     b) race potential - two innocent renames can create a loop together.
- *        That's where 4.4 screws up. Current fix: serialization on
+ *        That's where 4.4BSD screws up. Current fix: serialization on
  *        sb->s_vfs_rename_mutex. We might be more accurate, but that's another
  *        story.
- *     c) we have to lock _four_ objects - parents and victim (if it exists),
- *        and source.
+ *     c) we may have to lock up to _four_ objects - parents and victim (if it exists),
+ *        and source (if it's a non-directory or a subdirectory that moves to
+ *        different parent).
  *        And that - after we got ->i_mutex on parents (until then we don't know
  *        whether the target exists).  Solution: try to be smart with locking
  *        order for inodes.  We rely on the fact that tree topology may change
@@ -4769,6 +4764,7 @@ int vfs_rename(struct renamedata *rd)
        bool new_is_dir = false;
        unsigned max_links = new_dir->i_sb->s_max_links;
        struct name_snapshot old_name;
+       bool lock_old_subdir, lock_new_subdir;
 
        if (source == target)
                return 0;
@@ -4822,15 +4818,32 @@ int vfs_rename(struct renamedata *rd)
        take_dentry_name_snapshot(&old_name, old_dentry);
        dget(new_dentry);
        /*
-        * Lock all moved children. Moved directories may need to change parent
-        * pointer so they need the lock to prevent against concurrent
-        * directory changes moving parent pointer. For regular files we've
-        * historically always done this. The lockdep locking subclasses are
-        * somewhat arbitrary but RENAME_EXCHANGE in particular can swap
-        * regular files and directories so it's difficult to tell which
-        * subclasses to use.
+        * Lock children.
+        * The source subdirectory needs to be locked on cross-directory
+        * rename or cross-directory exchange since its parent changes.
+        * The target subdirectory needs to be locked on cross-directory
+        * exchange due to parent change and on any rename due to becoming
+        * a victim.
+        * Non-directories need locking in all cases (for NFS reasons);
+        * they get locked after any subdirectories (in inode address order).
+        *
+        * NOTE: WE ONLY LOCK UNRELATED DIRECTORIES IN CROSS-DIRECTORY CASE.
+        * NEVER, EVER DO THAT WITHOUT ->s_vfs_rename_mutex.
         */
-       lock_two_inodes(source, target, I_MUTEX_NORMAL, I_MUTEX_NONDIR2);
+       lock_old_subdir = new_dir != old_dir;
+       lock_new_subdir = new_dir != old_dir || !(flags & RENAME_EXCHANGE);
+       if (is_dir) {
+               if (lock_old_subdir)
+                       inode_lock_nested(source, I_MUTEX_CHILD);
+               if (target && (!new_is_dir || lock_new_subdir))
+                       inode_lock(target);
+       } else if (new_is_dir) {
+               if (lock_new_subdir)
+                       inode_lock_nested(target, I_MUTEX_CHILD);
+               inode_lock(source);
+       } else {
+               lock_two_nondirectories(source, target);
+       }
 
        error = -EPERM;
        if (IS_SWAPFILE(source) || (target && IS_SWAPFILE(target)))
@@ -4878,8 +4891,9 @@ int vfs_rename(struct renamedata *rd)
                        d_exchange(old_dentry, new_dentry);
        }
 out:
-       inode_unlock(source);
-       if (target)
+       if (!is_dir || lock_old_subdir)
+               inode_unlock(source);
+       if (target && (!new_is_dir || lock_new_subdir))
                inode_unlock(target);
        dput(new_dentry);
        if (!error) {