ignore: defconfig
[profile/ivi/kernel-x86-ivi.git] / fs / inode.c
index b33ba8e..e846a32 100644 (file)
@@ -773,15 +773,11 @@ static struct inode *find_inode(struct super_block *sb,
 
 repeat:
        hlist_for_each_entry(inode, head, i_hash) {
-               spin_lock(&inode->i_lock);
-               if (inode->i_sb != sb) {
-                       spin_unlock(&inode->i_lock);
+               if (inode->i_sb != sb)
                        continue;
-               }
-               if (!test(inode, data)) {
-                       spin_unlock(&inode->i_lock);
+               if (!test(inode, data))
                        continue;
-               }
+               spin_lock(&inode->i_lock);
                if (inode->i_state & (I_FREEING|I_WILL_FREE)) {
                        __wait_on_freeing_inode(inode);
                        goto repeat;
@@ -804,15 +800,11 @@ static struct inode *find_inode_fast(struct super_block *sb,
 
 repeat:
        hlist_for_each_entry(inode, head, i_hash) {
-               spin_lock(&inode->i_lock);
-               if (inode->i_ino != ino) {
-                       spin_unlock(&inode->i_lock);
+               if (inode->i_ino != ino)
                        continue;
-               }
-               if (inode->i_sb != sb) {
-                       spin_unlock(&inode->i_lock);
+               if (inode->i_sb != sb)
                        continue;
-               }
+               spin_lock(&inode->i_lock);
                if (inode->i_state & (I_FREEING|I_WILL_FREE)) {
                        __wait_on_freeing_inode(inode);
                        goto repeat;
@@ -951,6 +943,42 @@ void unlock_new_inode(struct inode *inode)
 EXPORT_SYMBOL(unlock_new_inode);
 
 /**
+ * lock_two_nondirectories - take two i_mutexes on non-directory objects
+ * @inode1: first inode to lock
+ * @inode2: second inode to lock
+ */
+void lock_two_nondirectories(struct inode *inode1, struct inode *inode2)
+{
+       WARN_ON_ONCE(S_ISDIR(inode1->i_mode));
+       if (inode1 == inode2 || !inode2) {
+               mutex_lock(&inode1->i_mutex);
+               return;
+       }
+       WARN_ON_ONCE(S_ISDIR(inode2->i_mode));
+       if (inode1 < inode2) {
+               mutex_lock(&inode1->i_mutex);
+               mutex_lock_nested(&inode2->i_mutex, I_MUTEX_NONDIR2);
+       } else {
+               mutex_lock(&inode2->i_mutex);
+               mutex_lock_nested(&inode1->i_mutex, I_MUTEX_NONDIR2);
+       }
+}
+EXPORT_SYMBOL(lock_two_nondirectories);
+
+/**
+ * unlock_two_nondirectories - release locks from lock_two_nondirectories()
+ * @inode1: first inode to unlock
+ * @inode2: second inode to unlock
+ */
+void unlock_two_nondirectories(struct inode *inode1, struct inode *inode2)
+{
+       mutex_unlock(&inode1->i_mutex);
+       if (inode2 && inode2 != inode1)
+               mutex_unlock(&inode2->i_mutex);
+}
+EXPORT_SYMBOL(unlock_two_nondirectories);
+
+/**
  * iget5_locked - obtain an inode from a mounted file system
  * @sb:                super block of file system
  * @hashval:   hash value (usually inode number) to get
@@ -1575,7 +1603,11 @@ static int __remove_suid(struct dentry *dentry, int kill)
        struct iattr newattrs;
 
        newattrs.ia_valid = ATTR_FORCE | kill;
-       return notify_change(dentry, &newattrs);
+       /*
+        * Note we call this on write, so notify_change will not
+        * encounter any conflicting delegations:
+        */
+       return notify_change(dentry, &newattrs, NULL);
 }
 
 int file_remove_suid(struct file *file)
@@ -1808,14 +1840,18 @@ EXPORT_SYMBOL(inode_init_owner);
  * inode_owner_or_capable - check current task permissions to inode
  * @inode: inode being checked
  *
- * Return true if current either has CAP_FOWNER to the inode, or
- * owns the file.
+ * Return true if current either has CAP_FOWNER in a namespace with the
+ * inode owner uid mapped, or owns the file.
  */
 bool inode_owner_or_capable(const struct inode *inode)
 {
+       struct user_namespace *ns;
+
        if (uid_eq(current_fsuid(), inode->i_uid))
                return true;
-       if (inode_capable(inode, CAP_FOWNER))
+
+       ns = current_user_ns();
+       if (ns_capable(ns, CAP_FOWNER) && kuid_has_mapping(ns, inode->i_uid))
                return true;
        return false;
 }