iio: accel: bma220: Use dev_get_drvdata() directly
[linux-2.6-microblaze.git] / fs / namei.c
index a320371..e99e2a9 100644 (file)
@@ -271,7 +271,7 @@ static int check_acl(struct inode *inode, int mask)
                /* no ->get_acl() calls in RCU mode... */
                if (is_uncached_acl(acl))
                        return -ECHILD;
-               return posix_acl_permission(inode, acl, mask & ~MAY_NOT_BLOCK);
+               return posix_acl_permission(inode, acl, mask);
        }
 
        acl = get_acl(inode, ACL_TYPE_ACCESS);
@@ -288,37 +288,51 @@ static int check_acl(struct inode *inode, int mask)
 }
 
 /*
- * This does the basic permission checking
+ * This does the basic UNIX permission checking.
+ *
+ * Note that the POSIX ACL check cares about the MAY_NOT_BLOCK bit,
+ * for RCU walking.
  */
 static int acl_permission_check(struct inode *inode, int mask)
 {
        unsigned int mode = inode->i_mode;
 
-       if (likely(uid_eq(current_fsuid(), inode->i_uid)))
+       /* Are we the owner? If so, ACL's don't matter */
+       if (likely(uid_eq(current_fsuid(), inode->i_uid))) {
+               mask &= 7;
                mode >>= 6;
-       else {
-               if (IS_POSIXACL(inode) && (mode & S_IRWXG)) {
-                       int error = check_acl(inode, mask);
-                       if (error != -EAGAIN)
-                               return error;
-               }
+               return (mask & ~mode) ? -EACCES : 0;
+       }
 
-               if (in_group_p(inode->i_gid))
-                       mode >>= 3;
+       /* Do we have ACL's? */
+       if (IS_POSIXACL(inode) && (mode & S_IRWXG)) {
+               int error = check_acl(inode, mask);
+               if (error != -EAGAIN)
+                       return error;
        }
 
+       /* Only RWX matters for group/other mode bits */
+       mask &= 7;
+
        /*
-        * If the DACs are ok we don't need any capability check.
+        * Are the group permissions different from
+        * the other permissions in the bits we care
+        * about? Need to check group ownership if so.
         */
-       if ((mask & ~mode & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0)
-               return 0;
-       return -EACCES;
+       if (mask & (mode ^ (mode >> 3))) {
+               if (in_group_p(inode->i_gid))
+                       mode >>= 3;
+       }
+
+       /* Bits in 'mode' clear that we require? */
+       return (mask & ~mode) ? -EACCES : 0;
 }
 
 /**
  * generic_permission -  check for access rights on a Posix-like filesystem
  * @inode:     inode to check access rights for
- * @mask:      right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC, ...)
+ * @mask:      right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC,
+ *             %MAY_NOT_BLOCK ...)
  *
  * Used to check for read/write/execute permissions on a file.
  * We use "fsuid" for this, letting us set arbitrary permissions
@@ -1010,7 +1024,7 @@ static bool safe_hardlink_source(struct inode *inode)
  *
  * Returns 0 if successful, -ve on error.
  */
-static int may_linkat(struct path *link)
+int may_linkat(struct path *link)
 {
        struct inode *inode = link->dentry->d_inode;
 
@@ -2837,16 +2851,24 @@ static int may_open(const struct path *path, int acc_mode, int flag)
        case S_IFDIR:
                if (acc_mode & MAY_WRITE)
                        return -EISDIR;
+               if (acc_mode & MAY_EXEC)
+                       return -EACCES;
                break;
        case S_IFBLK:
        case S_IFCHR:
                if (!may_open_dev(path))
                        return -EACCES;
-               /*FALLTHRU*/
+               fallthrough;
        case S_IFIFO:
        case S_IFSOCK:
+               if (acc_mode & MAY_EXEC)
+                       return -EACCES;
                flag &= ~O_TRUNC;
                break;
+       case S_IFREG:
+               if ((acc_mode & MAY_EXEC) && path_noexec(path))
+                       return -EACCES;
+               break;
        }
 
        error = inode_permission(inode, MAY_OPEN | acc_mode);
@@ -3505,12 +3527,14 @@ EXPORT_SYMBOL(user_path_create);
 
 int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
 {
+       bool is_whiteout = S_ISCHR(mode) && dev == WHITEOUT_DEV;
        int error = may_create(dir, dentry);
 
        if (error)
                return error;
 
-       if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))
+       if ((S_ISCHR(mode) || S_ISBLK(mode)) && !is_whiteout &&
+           !capable(CAP_MKNOD))
                return -EPERM;
 
        if (!dir->i_op->mknod)
@@ -3548,7 +3572,7 @@ static int may_mknod(umode_t mode)
        }
 }
 
-long do_mknodat(int dfd, const char __user *filename, umode_t mode,
+static long do_mknodat(int dfd, const char __user *filename, umode_t mode,
                unsigned int dev)
 {
        struct dentry *dentry;
@@ -3629,7 +3653,7 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 }
 EXPORT_SYMBOL(vfs_mkdir);
 
-long do_mkdirat(int dfd, const char __user *pathname, umode_t mode)
+static long do_mkdirat(int dfd, const char __user *pathname, umode_t mode)
 {
        struct dentry *dentry;
        struct path path;
@@ -3704,17 +3728,16 @@ out:
 }
 EXPORT_SYMBOL(vfs_rmdir);
 
-long do_rmdir(int dfd, const char __user *pathname)
+long do_rmdir(int dfd, struct filename *name)
 {
        int error = 0;
-       struct filename *name;
        struct dentry *dentry;
        struct path path;
        struct qstr last;
        int type;
        unsigned int lookup_flags = 0;
 retry:
-       name = filename_parentat(dfd, getname(pathname), lookup_flags,
+       name = filename_parentat(dfd, name, lookup_flags,
                                &path, &last, &type);
        if (IS_ERR(name))
                return PTR_ERR(name);
@@ -3755,17 +3778,17 @@ exit2:
        mnt_drop_write(path.mnt);
 exit1:
        path_put(&path);
-       putname(name);
        if (retry_estale(error, lookup_flags)) {
                lookup_flags |= LOOKUP_REVAL;
                goto retry;
        }
+       putname(name);
        return error;
 }
 
 SYSCALL_DEFINE1(rmdir, const char __user *, pathname)
 {
-       return do_rmdir(AT_FDCWD, pathname);
+       return do_rmdir(AT_FDCWD, getname(pathname));
 }
 
 /**
@@ -3910,8 +3933,7 @@ SYSCALL_DEFINE3(unlinkat, int, dfd, const char __user *, pathname, int, flag)
                return -EINVAL;
 
        if (flag & AT_REMOVEDIR)
-               return do_rmdir(dfd, pathname);
-
+               return do_rmdir(dfd, getname(pathname));
        return do_unlinkat(dfd, getname(pathname));
 }
 
@@ -3941,7 +3963,7 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
 }
 EXPORT_SYMBOL(vfs_symlink);
 
-long do_symlinkat(const char __user *oldname, int newdfd,
+static long do_symlinkat(const char __user *oldname, int newdfd,
                  const char __user *newname)
 {
        int error;
@@ -4072,7 +4094,7 @@ EXPORT_SYMBOL(vfs_link);
  * with linux 2.0, and to avoid hard-linking to directories
  * and other special files.  --ADM
  */
-int do_linkat(int olddfd, const char __user *oldname, int newdfd,
+static int do_linkat(int olddfd, const char __user *oldname, int newdfd,
              const char __user *newname, int flags)
 {
        struct dentry *new_dentry;
@@ -4345,9 +4367,6 @@ static int do_renameat2(int olddfd, const char __user *oldname, int newdfd,
            (flags & RENAME_EXCHANGE))
                return -EINVAL;
 
-       if ((flags & RENAME_WHITEOUT) && !capable(CAP_MKNOD))
-               return -EPERM;
-
        if (flags & RENAME_EXCHANGE)
                target_flags = 0;
 
@@ -4483,20 +4502,6 @@ SYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newna
        return do_renameat2(AT_FDCWD, oldname, AT_FDCWD, newname, 0);
 }
 
-int vfs_whiteout(struct inode *dir, struct dentry *dentry)
-{
-       int error = may_create(dir, dentry);
-       if (error)
-               return error;
-
-       if (!dir->i_op->mknod)
-               return -EPERM;
-
-       return dir->i_op->mknod(dir, dentry,
-                               S_IFCHR | WHITEOUT_MODE, WHITEOUT_DEV);
-}
-EXPORT_SYMBOL(vfs_whiteout);
-
 int readlink_copy(char __user *buffer, int buflen, const char *link)
 {
        int len = PTR_ERR(link);