Clean follow_dotdot() up a bit
[firefly-linux-kernel-4.4.55.git] / fs / namei.c
index d62fdc875f22800a3d5c1a8c0a2532b0b6d51cc6..3df2ed50ab57270156a8ba90efa77111bfbc5676 100644 (file)
@@ -689,33 +689,20 @@ static __always_inline void follow_dotdot(struct nameidata *nd)
        set_root(nd);
 
        while(1) {
-               struct vfsmount *parent;
                struct dentry *old = nd->path.dentry;
 
                if (nd->path.dentry == nd->root.dentry &&
                    nd->path.mnt == nd->root.mnt) {
                        break;
                }
-               spin_lock(&dcache_lock);
                if (nd->path.dentry != nd->path.mnt->mnt_root) {
-                       nd->path.dentry = dget(nd->path.dentry->d_parent);
-                       spin_unlock(&dcache_lock);
+                       /* rare case of legitimate dget_parent()... */
+                       nd->path.dentry = dget_parent(nd->path.dentry);
                        dput(old);
                        break;
                }
-               spin_unlock(&dcache_lock);
-               spin_lock(&vfsmount_lock);
-               parent = nd->path.mnt->mnt_parent;
-               if (parent == nd->path.mnt) {
-                       spin_unlock(&vfsmount_lock);
+               if (!follow_up(&nd->path))
                        break;
-               }
-               mntget(parent);
-               nd->path.dentry = dget(nd->path.mnt->mnt_mountpoint);
-               spin_unlock(&vfsmount_lock);
-               dput(old);
-               mntput(nd->path.mnt);
-               nd->path.mnt = parent;
        }
        follow_mount(&nd->path);
 }
@@ -822,6 +809,17 @@ fail:
        return PTR_ERR(dentry);
 }
 
+/*
+ * This is a temporary kludge to deal with "automount" symlinks; proper
+ * solution is to trigger them on follow_mount(), so that do_lookup()
+ * would DTRT.  To be killed before 2.6.34-final.
+ */
+static inline int follow_on_final(struct inode *inode, unsigned lookup_flags)
+{
+       return inode && unlikely(inode->i_op->follow_link) &&
+               ((lookup_flags & LOOKUP_FOLLOW) || S_ISDIR(inode->i_mode));
+}
+
 /*
  * Name resolution.
  * This is the basic name resolution function, turning a pathname into
@@ -942,8 +940,7 @@ last_component:
                if (err)
                        break;
                inode = next.dentry->d_inode;
-               if ((lookup_flags & LOOKUP_FOLLOW)
-                   && inode && inode->i_op->follow_link) {
+               if (follow_on_final(inode, lookup_flags)) {
                        err = do_follow_link(&next, nd);
                        if (err)
                                goto return_err;
@@ -1493,7 +1490,7 @@ int may_open(struct path *path, int acc_mode, int flag)
         * An append-only file must be opened in append mode for writing.
         */
        if (IS_APPEND(inode)) {
-               if  ((flag & FMODE_WRITE) && !(flag & O_APPEND))
+               if  ((flag & O_ACCMODE) != O_RDONLY && !(flag & O_APPEND))
                        return -EPERM;
                if (flag & O_TRUNC)
                        return -EPERM;
@@ -1537,7 +1534,7 @@ static int handle_truncate(struct path *path)
  * what get passed to sys_open().
  */
 static int __open_namei_create(struct nameidata *nd, struct path *path,
-                               int flag, int mode)
+                               int open_flag, int mode)
 {
        int error;
        struct dentry *dir = nd->path.dentry;
@@ -1555,7 +1552,7 @@ out_unlock:
        if (error)
                return error;
        /* Don't check for write permission, don't truncate */
-       return may_open(&nd->path, 0, flag & ~O_TRUNC);
+       return may_open(&nd->path, 0, open_flag & ~O_TRUNC);
 }
 
 /*
@@ -1726,7 +1723,7 @@ do_last:
                error = mnt_want_write(nd.path.mnt);
                if (error)
                        goto exit_mutex_unlock;
-               error = __open_namei_create(&nd, &path, flag, mode);
+               error = __open_namei_create(&nd, &path, open_flag, mode);
                if (error) {
                        mnt_drop_write(nd.path.mnt);
                        goto exit;
@@ -1788,7 +1785,7 @@ ok:
                if (error)
                        goto exit;
        }
-       error = may_open(&nd.path, acc_mode, flag);
+       error = may_open(&nd.path, acc_mode, open_flag);
        if (error) {
                if (will_truncate)
                        mnt_drop_write(nd.path.mnt);