ANDROID: vfs: Add setattr2 for filesystems with per mount permissions
authorDaniel Rosenberg <drosen@google.com>
Wed, 26 Oct 2016 23:33:11 +0000 (16:33 -0700)
committerAmit Pundir <amit.pundir@linaro.org>
Fri, 3 Feb 2017 09:34:29 +0000 (15:04 +0530)
This allows filesystems to use their mount private data to
influence the permssions they use in setattr2. It has
been separated into a new call to avoid disrupting current
setattr users.

Change-Id: I19959038309284448f1b7f232d579674ef546385
Signed-off-by: Daniel Rosenberg <drosen@google.com>
fs/attr.c
fs/coredump.c
fs/inode.c
fs/namei.c
fs/open.c
fs/utimes.c
include/linux/fs.h

index d62f674a605ff687972507ffce003bc08121b81d..11be2265a2d55cb0688231698770b29ee357b0f1 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -187,7 +187,7 @@ EXPORT_SYMBOL(setattr_copy);
  * the file open for write, as there can be no conflicting delegation in
  * that case.
  */
-int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **delegated_inode)
+int notify_change2(struct vfsmount *mnt, struct dentry * dentry, struct iattr * attr, struct inode **delegated_inode)
 {
        struct inode *inode = dentry->d_inode;
        umode_t mode = inode->i_mode;
@@ -277,7 +277,9 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
        if (error)
                return error;
 
-       if (inode->i_op->setattr)
+       if (mnt && inode->i_op->setattr2)
+               error = inode->i_op->setattr2(mnt, dentry, attr);
+       else if (inode->i_op->setattr)
                error = inode->i_op->setattr(dentry, attr);
        else
                error = simple_setattr(dentry, attr);
@@ -290,4 +292,10 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
 
        return error;
 }
+EXPORT_SYMBOL(notify_change2);
+
+int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **delegated_inode)
+{
+       return notify_change2(NULL, dentry, attr, delegated_inode);
+}
 EXPORT_SYMBOL(notify_change);
index 5d15c4975ba14f31b32439259780ee8e42681e40..fe0a28da18a6992dbf834440d41a8a5c75d29b53 100644 (file)
@@ -720,7 +720,7 @@ void do_coredump(const siginfo_t *siginfo)
                        goto close_fail;
                if (!(cprm.file->f_mode & FMODE_CAN_WRITE))
                        goto close_fail;
-               if (do_truncate(cprm.file->f_path.dentry, 0, 0, cprm.file))
+               if (do_truncate2(cprm.file->f_path.mnt, cprm.file->f_path.dentry, 0, 0, cprm.file))
                        goto close_fail;
        }
 
index 2c16b758831dd08715c3c6e270c97f00b6bed10c..6a7234f0afeac74ea1dfadd8373f923bea167a90 100644 (file)
@@ -1721,7 +1721,7 @@ int dentry_needs_remove_privs(struct dentry *dentry)
 }
 EXPORT_SYMBOL(dentry_needs_remove_privs);
 
-static int __remove_privs(struct dentry *dentry, int kill)
+static int __remove_privs(struct vfsmount *mnt, struct dentry *dentry, int kill)
 {
        struct iattr newattrs;
 
@@ -1730,7 +1730,7 @@ static int __remove_privs(struct dentry *dentry, int kill)
         * Note we call this on write, so notify_change will not
         * encounter any conflicting delegations:
         */
-       return notify_change(dentry, &newattrs, NULL);
+       return notify_change2(mnt, dentry, &newattrs, NULL);
 }
 
 /*
@@ -1752,7 +1752,7 @@ int file_remove_privs(struct file *file)
        if (kill < 0)
                return kill;
        if (kill)
-               error = __remove_privs(dentry, kill);
+               error = __remove_privs(file->f_path.mnt, dentry, kill);
        if (!error)
                inode_has_no_xattr(inode);
 
index 3885e445d95142db081578b9fbc41e295edb5d2a..200a35ebf817494dba48d6e718e442240e8cfc1c 100644 (file)
@@ -2767,7 +2767,7 @@ static int handle_truncate(struct file *filp)
        if (!error)
                error = security_path_truncate(path);
        if (!error) {
-               error = do_truncate(path->dentry, 0,
+               error = do_truncate2(path->mnt, path->dentry, 0,
                                    ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
                                    filp);
        }
index df1a8c2cd56ae7e610e1f265e1c83e93020cecb8..e70cca15c976108e2a384f83fa6798a4fbc300b3 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -34,8 +34,8 @@
 
 #include "internal.h"
 
-int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
-       struct file *filp)
+int do_truncate2(struct vfsmount *mnt, struct dentry *dentry, loff_t length,
+               unsigned int time_attrs, struct file *filp)
 {
        int ret;
        struct iattr newattrs;
@@ -60,10 +60,15 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
 
        mutex_lock(&dentry->d_inode->i_mutex);
        /* Note any delegations or leases have already been broken: */
-       ret = notify_change(dentry, &newattrs, NULL);
+       ret = notify_change2(mnt, dentry, &newattrs, NULL);
        mutex_unlock(&dentry->d_inode->i_mutex);
        return ret;
 }
+int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
+       struct file *filp)
+{
+       return do_truncate2(NULL, dentry, length, time_attrs, filp);
+}
 
 long vfs_truncate(struct path *path, loff_t length)
 {
@@ -108,7 +113,7 @@ long vfs_truncate(struct path *path, loff_t length)
        if (!error)
                error = security_path_truncate(path);
        if (!error)
-               error = do_truncate(path->dentry, length, 0, NULL);
+               error = do_truncate2(mnt, path->dentry, length, 0, NULL);
 
 put_write_and_out:
        put_write_access(inode);
@@ -157,6 +162,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
 {
        struct inode *inode;
        struct dentry *dentry;
+       struct vfsmount *mnt;
        struct fd f;
        int error;
 
@@ -173,6 +179,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
                small = 0;
 
        dentry = f.file->f_path.dentry;
+       mnt = f.file->f_path.mnt;
        inode = dentry->d_inode;
        error = -EINVAL;
        if (!S_ISREG(inode->i_mode) || !(f.file->f_mode & FMODE_WRITE))
@@ -192,7 +199,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
        if (!error)
                error = security_path_truncate(&f.file->f_path);
        if (!error)
-               error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, f.file);
+               error = do_truncate2(mnt, dentry, length, ATTR_MTIME|ATTR_CTIME, f.file);
        sb_end_write(inode->i_sb);
 out_putf:
        fdput(f);
@@ -522,7 +529,7 @@ retry_deleg:
                goto out_unlock;
        newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
        newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
-       error = notify_change(path->dentry, &newattrs, &delegated_inode);
+       error = notify_change2(path->mnt, path->dentry, &newattrs, &delegated_inode);
 out_unlock:
        mutex_unlock(&inode->i_mutex);
        if (delegated_inode) {
@@ -602,7 +609,7 @@ retry_deleg:
        mutex_lock(&inode->i_mutex);
        error = security_path_chown(path, uid, gid);
        if (!error)
-               error = notify_change(path->dentry, &newattrs, &delegated_inode);
+               error = notify_change2(path->mnt, path->dentry, &newattrs, &delegated_inode);
        mutex_unlock(&inode->i_mutex);
        if (delegated_inode) {
                error = break_deleg_wait(&delegated_inode);
index cb771c30d10231186d405b63155d02abadb0ce7e..a35e909cf8e395b6dd760b4b5a3188c4181de82a 100644 (file)
@@ -91,7 +91,7 @@ static int utimes_common(struct path *path, struct timespec *times)
        }
 retry_deleg:
        mutex_lock(&inode->i_mutex);
-       error = notify_change(path->dentry, &newattrs, &delegated_inode);
+       error = notify_change2(path->mnt, path->dentry, &newattrs, &delegated_inode);
        mutex_unlock(&inode->i_mutex);
        if (delegated_inode) {
                error = break_deleg_wait(&delegated_inode);
index eded3090afced59e15448a6f0ef048a2d962f89b..7f6de206cc5c242160d1148874a1c3ba1b70d4e9 100644 (file)
@@ -1697,6 +1697,7 @@ struct inode_operations {
        int (*rename2) (struct inode *, struct dentry *,
                        struct inode *, struct dentry *, unsigned int);
        int (*setattr) (struct dentry *, struct iattr *);
+       int (*setattr2) (struct vfsmount *, struct dentry *, struct iattr *);
        int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
        int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
        ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
@@ -2262,6 +2263,8 @@ struct filename {
 extern long vfs_truncate(struct path *, loff_t);
 extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
                       struct file *filp);
+extern int do_truncate2(struct vfsmount *, struct dentry *, loff_t start,
+                       unsigned int time_attrs, struct file *filp);
 extern int vfs_fallocate(struct file *file, int mode, loff_t offset,
                        loff_t len);
 extern long do_sys_open(int dfd, const char __user *filename, int flags,
@@ -2486,6 +2489,7 @@ extern void emergency_remount(void);
 extern sector_t bmap(struct inode *, sector_t);
 #endif
 extern int notify_change(struct dentry *, struct iattr *, struct inode **);
+extern int notify_change2(struct vfsmount *, struct dentry *, struct iattr *, struct inode **);
 extern int inode_permission(struct inode *, int);
 extern int inode_permission2(struct vfsmount *, struct inode *, int);
 extern int __inode_permission(struct inode *, int);