FROMLIST: drm/bridge: analogix_dp: Don't read EDID if panel present
[firefly-linux-kernel-4.4.55.git] / fs / sdcardfs / inode.c
index 2528da0d3ae181dbdc030b804da5ce8f45932cbb..68e615045616e33f0f2c637e1f3ace655bb9998b 100644 (file)
  */
 
 #include "sdcardfs.h"
+#include <linux/fs_struct.h>
 
 /* Do not directly use this function. Use OVERRIDE_CRED() instead. */
-const struct cred * override_fsids(struct sdcardfs_sb_info* sbi)
+const struct cred * override_fsids(struct sdcardfs_sb_info* sbi, struct sdcardfs_inode_info *info)
 {
        struct cred * cred;
        const struct cred * old_cred;
+       uid_t uid;
 
        cred = prepare_creds();
        if (!cred)
                return NULL;
 
-       cred->fsuid = make_kuid(&init_user_ns, sbi->options.fs_low_uid);
+       if (info->under_obb)
+               uid = AID_MEDIA_OBB;
+       else
+               uid = multiuser_get_uid(info->userid, sbi->options.fs_low_uid);
+       cred->fsuid = make_kuid(&init_user_ns, uid);
        cred->fsgid = make_kgid(&init_user_ns, sbi->options.fs_low_gid);
 
        old_cred = override_creds(cred);
@@ -53,11 +59,14 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry,
 {
        int err;
        struct dentry *lower_dentry;
+       struct vfsmount *lower_dentry_mnt;
        struct dentry *lower_parent_dentry = NULL;
        struct path lower_path;
        const struct cred *saved_cred = NULL;
+       struct fs_struct *saved_fs;
+       struct fs_struct *copied_fs;
 
-       if(!check_caller_access_to_name(dir, dentry->d_name.name)) {
+       if(!check_caller_access_to_name(dir, &dentry->d_name)) {
                printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n"
                                                 "  dentry: %s, task:%s\n",
                                                 __func__, dentry->d_name.name, current->comm);
@@ -66,15 +75,26 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry,
        }
 
        /* save current_cred and override it */
-       OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred);
+       OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir));
 
        sdcardfs_get_lower_path(dentry, &lower_path);
        lower_dentry = lower_path.dentry;
+       lower_dentry_mnt = lower_path.mnt;
        lower_parent_dentry = lock_parent(lower_dentry);
 
        /* set last 16bytes of mode field to 0664 */
        mode = (mode & S_IFMT) | 00664;
-       err = vfs_create(d_inode(lower_parent_dentry), lower_dentry, mode, want_excl);
+
+       /* temporarily change umask for lower fs write */
+       saved_fs = current->fs;
+       copied_fs = copy_fs_struct(current->fs);
+       if (!copied_fs) {
+               err = -ENOMEM;
+               goto out_unlock;
+       }
+       current->fs = copied_fs;
+       current->fs->umask = 0;
+       err = vfs_create2(lower_dentry_mnt, d_inode(lower_parent_dentry), lower_dentry, mode, want_excl);
        if (err)
                goto out;
 
@@ -83,8 +103,12 @@ static int sdcardfs_create(struct inode *dir, struct dentry *dentry,
                goto out;
        fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir));
        fsstack_copy_inode_size(dir, d_inode(lower_parent_dentry));
+       fixup_lower_ownership(dentry, dentry->d_name.name);
 
 out:
+       current->fs = saved_fs;
+       free_fs_struct(copied_fs);
+out_unlock:
        unlock_dir(lower_parent_dentry);
        sdcardfs_put_lower_path(dentry, &lower_path);
        REVERT_CRED(saved_cred);
@@ -138,12 +162,13 @@ static int sdcardfs_unlink(struct inode *dir, struct dentry *dentry)
 {
        int err;
        struct dentry *lower_dentry;
+       struct vfsmount *lower_mnt;
        struct inode *lower_dir_inode = sdcardfs_lower_inode(dir);
        struct dentry *lower_dir_dentry;
        struct path lower_path;
        const struct cred *saved_cred = NULL;
 
-       if(!check_caller_access_to_name(dir, dentry->d_name.name)) {
+       if(!check_caller_access_to_name(dir, &dentry->d_name)) {
                printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n"
                                                 "  dentry: %s, task:%s\n",
                                                 __func__, dentry->d_name.name, current->comm);
@@ -152,14 +177,15 @@ static int sdcardfs_unlink(struct inode *dir, struct dentry *dentry)
        }
 
        /* save current_cred and override it */
-       OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred);
+       OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir));
 
        sdcardfs_get_lower_path(dentry, &lower_path);
        lower_dentry = lower_path.dentry;
+       lower_mnt = lower_path.mnt;
        dget(lower_dentry);
        lower_dir_dentry = lock_parent(lower_dentry);
 
-       err = vfs_unlink(lower_dir_inode, lower_dentry, NULL);
+       err = vfs_unlink2(lower_mnt, lower_dir_inode, lower_dentry, NULL);
 
        /*
         * Note: unlinking on top of NFS can cause silly-renamed files.
@@ -240,18 +266,19 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
        int err;
        int make_nomedia_in_obb = 0;
        struct dentry *lower_dentry;
+       struct vfsmount *lower_mnt;
        struct dentry *lower_parent_dentry = NULL;
        struct path lower_path;
        struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
        const struct cred *saved_cred = NULL;
        struct sdcardfs_inode_info *pi = SDCARDFS_I(dir);
-       char *page_buf;
-       char *nomedia_dir_name;
-       char *nomedia_fullpath;
-       int fullpath_namelen;
        int touch_err = 0;
+       struct fs_struct *saved_fs;
+       struct fs_struct *copied_fs;
+       struct qstr q_obb = QSTR_LITERAL("obb");
+       struct qstr q_data = QSTR_LITERAL("data");
 
-       if(!check_caller_access_to_name(dir, dentry->d_name.name)) {
+       if(!check_caller_access_to_name(dir, &dentry->d_name)) {
                printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n"
                                                 "  dentry: %s, task:%s\n",
                                                 __func__, dentry->d_name.name, current->comm);
@@ -260,7 +287,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
        }
 
        /* save current_cred and override it */
-       OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred);
+       OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir));
 
        /* check disk space */
        if (!check_min_free_space(dentry, 0, 1)) {
@@ -272,14 +299,28 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
        /* the lower_dentry is negative here */
        sdcardfs_get_lower_path(dentry, &lower_path);
        lower_dentry = lower_path.dentry;
+       lower_mnt = lower_path.mnt;
        lower_parent_dentry = lock_parent(lower_dentry);
 
        /* set last 16bytes of mode field to 0775 */
        mode = (mode & S_IFMT) | 00775;
-       err = vfs_mkdir(d_inode(lower_parent_dentry), lower_dentry, mode);
 
-       if (err)
+       /* temporarily change umask for lower fs write */
+       saved_fs = current->fs;
+       copied_fs = copy_fs_struct(current->fs);
+       if (!copied_fs) {
+               err = -ENOMEM;
+               unlock_dir(lower_parent_dentry);
+               goto out_unlock;
+       }
+       current->fs = copied_fs;
+       current->fs->umask = 0;
+       err = vfs_mkdir2(lower_mnt, d_inode(lower_parent_dentry), lower_dentry, mode);
+
+       if (err) {
+               unlock_dir(lower_parent_dentry);
                goto out;
+       }
 
        /* if it is a local obb dentry, setup it with the base obbpath */
        if(need_graft_path(dentry)) {
@@ -301,58 +342,38 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
        }
 
        err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path, pi->userid);
-       if (err)
+       if (err) {
+               unlock_dir(lower_parent_dentry);
                goto out;
+       }
 
        fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir));
        fsstack_copy_inode_size(dir, d_inode(lower_parent_dentry));
        /* update number of links on parent directory */
        set_nlink(dir, sdcardfs_lower_inode(dir)->i_nlink);
-
-       if ((!sbi->options.multiuser) && (!strcasecmp(dentry->d_name.name, "obb"))
+       fixup_lower_ownership(dentry, dentry->d_name.name);
+       unlock_dir(lower_parent_dentry);
+       if ((!sbi->options.multiuser) && (qstr_case_eq(&dentry->d_name, &q_obb))
                && (pi->perm == PERM_ANDROID) && (pi->userid == 0))
                make_nomedia_in_obb = 1;
 
        /* When creating /Android/data and /Android/obb, mark them as .nomedia */
        if (make_nomedia_in_obb ||
-               ((pi->perm == PERM_ANDROID) && (!strcasecmp(dentry->d_name.name, "data")))) {
-
-               page_buf = (char *)__get_free_page(GFP_KERNEL);
-               if (!page_buf) {
-                       printk(KERN_ERR "sdcardfs: failed to allocate page buf\n");
-                       goto out;
-               }
-
-               nomedia_dir_name = d_absolute_path(&lower_path, page_buf, PAGE_SIZE);
-               if (IS_ERR(nomedia_dir_name)) {
-                       free_page((unsigned long)page_buf);
-                       printk(KERN_ERR "sdcardfs: failed to get .nomedia dir name\n");
-                       goto out;
-               }
-
-               fullpath_namelen = page_buf + PAGE_SIZE - nomedia_dir_name - 1;
-               fullpath_namelen += strlen("/.nomedia");
-               nomedia_fullpath = kzalloc(fullpath_namelen + 1, GFP_KERNEL);
-               if (!nomedia_fullpath) {
-                       free_page((unsigned long)page_buf);
-                       printk(KERN_ERR "sdcardfs: failed to allocate .nomedia fullpath buf\n");
-                       goto out;
-               }
-
-               strcpy(nomedia_fullpath, nomedia_dir_name);
-               free_page((unsigned long)page_buf);
-               strcat(nomedia_fullpath, "/.nomedia");
-               touch_err = touch(nomedia_fullpath, 0664);
+               ((pi->perm == PERM_ANDROID) && (qstr_case_eq(&dentry->d_name, &q_data)))) {
+               REVERT_CRED(saved_cred);
+               OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(d_inode(dentry)));
+               set_fs_pwd(current->fs, &lower_path);
+               touch_err = touch(".nomedia", 0664);
                if (touch_err) {
-                       printk(KERN_ERR "sdcardfs: failed to touch(%s): %d\n",
-                                                       nomedia_fullpath, touch_err);
-                       kfree(nomedia_fullpath);
+                       printk(KERN_ERR "sdcardfs: failed to create .nomedia in %s: %d\n",
+                                                       lower_path.dentry->d_name.name, touch_err);
                        goto out;
                }
-               kfree(nomedia_fullpath);
        }
 out:
-       unlock_dir(lower_parent_dentry);
+       current->fs = saved_fs;
+       free_fs_struct(copied_fs);
+out_unlock:
        sdcardfs_put_lower_path(dentry, &lower_path);
 out_revert:
        REVERT_CRED(saved_cred);
@@ -364,11 +385,12 @@ static int sdcardfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
        struct dentry *lower_dentry;
        struct dentry *lower_dir_dentry;
+       struct vfsmount *lower_mnt;
        int err;
        struct path lower_path;
        const struct cred *saved_cred = NULL;
 
-       if(!check_caller_access_to_name(dir, dentry->d_name.name)) {
+       if(!check_caller_access_to_name(dir, &dentry->d_name)) {
                printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n"
                                                 "  dentry: %s, task:%s\n",
                                                 __func__, dentry->d_name.name, current->comm);
@@ -377,16 +399,17 @@ static int sdcardfs_rmdir(struct inode *dir, struct dentry *dentry)
        }
 
        /* save current_cred and override it */
-       OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred);
+       OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir));
 
        /* sdcardfs_get_real_lower(): in case of remove an user's obb dentry
         * the dentry on the original path should be deleted. */
        sdcardfs_get_real_lower(dentry, &lower_path);
 
        lower_dentry = lower_path.dentry;
+       lower_mnt = lower_path.mnt;
        lower_dir_dentry = lock_parent(lower_dentry);
 
-       err = vfs_rmdir(d_inode(lower_dir_dentry), lower_dentry);
+       err = vfs_rmdir2(lower_mnt, d_inode(lower_dir_dentry), lower_dentry);
        if (err)
                goto out;
 
@@ -450,13 +473,13 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct dentry *lower_new_dentry = NULL;
        struct dentry *lower_old_dir_dentry = NULL;
        struct dentry *lower_new_dir_dentry = NULL;
+       struct vfsmount *lower_mnt = NULL;
        struct dentry *trap = NULL;
-       struct dentry *new_parent = NULL;
        struct path lower_old_path, lower_new_path;
        const struct cred *saved_cred = NULL;
 
-       if(!check_caller_access_to_name(old_dir, old_dentry->d_name.name) ||
-               !check_caller_access_to_name(new_dir, new_dentry->d_name.name)) {
+       if(!check_caller_access_to_name(old_dir, &old_dentry->d_name) ||
+               !check_caller_access_to_name(new_dir, &new_dentry->d_name)) {
                printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n"
                                                 "  new_dentry: %s, task:%s\n",
                                                 __func__, new_dentry->d_name.name, current->comm);
@@ -465,12 +488,13 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        }
 
        /* save current_cred and override it */
-       OVERRIDE_CRED(SDCARDFS_SB(old_dir->i_sb), saved_cred);
+       OVERRIDE_CRED(SDCARDFS_SB(old_dir->i_sb), saved_cred, SDCARDFS_I(new_dir));
 
        sdcardfs_get_real_lower(old_dentry, &lower_old_path);
        sdcardfs_get_lower_path(new_dentry, &lower_new_path);
        lower_old_dentry = lower_old_path.dentry;
        lower_new_dentry = lower_new_path.dentry;
+       lower_mnt = lower_old_path.mnt;
        lower_old_dir_dentry = dget_parent(lower_old_dentry);
        lower_new_dir_dentry = dget_parent(lower_new_dentry);
 
@@ -486,7 +510,8 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                goto out;
        }
 
-       err = vfs_rename(d_inode(lower_old_dir_dentry), lower_old_dentry,
+       err = vfs_rename2(lower_mnt,
+                        d_inode(lower_old_dir_dentry), lower_old_dentry,
                         d_inode(lower_new_dir_dentry), lower_new_dentry,
                         NULL, 0);
        if (err)
@@ -499,25 +524,11 @@ static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (new_dir != old_dir) {
                sdcardfs_copy_and_fix_attrs(old_dir, d_inode(lower_old_dir_dentry));
                fsstack_copy_inode_size(old_dir, d_inode(lower_old_dir_dentry));
-
-               /* update the derived permission of the old_dentry
-                * with its new parent
-                */
-               new_parent = dget_parent(new_dentry);
-               if(new_parent) {
-                       if(d_inode(old_dentry)) {
-                               update_derived_permission_lock(old_dentry);
-                       }
-                       dput(new_parent);
-               }
        }
-       /* At this point, not all dentry information has been moved, so
-        * we pass along new_dentry for the name.*/
-       mutex_lock(&d_inode(old_dentry)->i_mutex);
-       get_derived_permission_new(new_dentry->d_parent, old_dentry, new_dentry);
-       fix_derived_permission(d_inode(old_dentry));
-       get_derive_permissions_recursive(old_dentry);
-       mutex_unlock(&d_inode(old_dentry)->i_mutex);
+       get_derived_permission_new(new_dentry->d_parent, old_dentry, &new_dentry->d_name);
+       fixup_tmp_permissions(d_inode(old_dentry));
+       fixup_lower_ownership(old_dentry, new_dentry->d_name.name);
+       drop_recursive(old_dentry); /* Can't fixup ownership recursively :( */
 out:
        unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
        dput(lower_old_dir_dentry);
@@ -586,16 +597,63 @@ static const char *sdcardfs_follow_link(struct dentry *dentry, void **cookie)
 }
 #endif
 
-static int sdcardfs_permission(struct inode *inode, int mask)
+static int sdcardfs_permission_wrn(struct inode *inode, int mask)
+{
+       WARN(1, "sdcardfs does not support permission. Use permission2.\n");
+       return -EINVAL;
+}
+
+void copy_attrs(struct inode *dest, const struct inode *src)
+{
+       dest->i_mode = src->i_mode;
+       dest->i_uid = src->i_uid;
+       dest->i_gid = src->i_gid;
+       dest->i_rdev = src->i_rdev;
+       dest->i_atime = src->i_atime;
+       dest->i_mtime = src->i_mtime;
+       dest->i_ctime = src->i_ctime;
+       dest->i_blkbits = src->i_blkbits;
+       dest->i_flags = src->i_flags;
+#ifdef CONFIG_FS_POSIX_ACL
+       dest->i_acl = src->i_acl;
+#endif
+#ifdef CONFIG_SECURITY
+       dest->i_security = src->i_security;
+#endif
+}
+
+static int sdcardfs_permission(struct vfsmount *mnt, struct inode *inode, int mask)
 {
        int err;
+       struct inode tmp;
+       struct inode *top = grab_top(SDCARDFS_I(inode));
+
+       if (!top) {
+               release_top(SDCARDFS_I(inode));
+               WARN(1, "Top value was null!\n");
+               return -EINVAL;
+       }
 
        /*
         * Permission check on sdcardfs inode.
         * Calling process should have AID_SDCARD_RW permission
+        * Since generic_permission only needs i_mode, i_uid,
+        * i_gid, and i_sb, we can create a fake inode to pass
+        * this information down in.
+        *
+        * The underlying code may attempt to take locks in some
+        * cases for features we're not using, but if that changes,
+        * locks must be dealt with to avoid undefined behavior.
         */
-       err = generic_permission(inode, mask);
-
+       copy_attrs(&tmp, inode);
+       tmp.i_uid = make_kuid(&init_user_ns, SDCARDFS_I(top)->d_uid);
+       tmp.i_gid = make_kgid(&init_user_ns, get_gid(mnt, SDCARDFS_I(top)));
+       tmp.i_mode = (inode->i_mode & S_IFMT) | get_mode(mnt, SDCARDFS_I(top));
+       release_top(SDCARDFS_I(inode));
+       tmp.i_sb = inode->i_sb;
+       if (IS_POSIXACL(inode))
+               printk(KERN_WARNING "%s: This may be undefined behavior... \n", __func__);
+       err = generic_permission(&tmp, mask);
        /* XXX
         * Original sdcardfs code calls inode_permission(lower_inode,.. )
         * for checking inode permission. But doing such things here seems
@@ -624,30 +682,70 @@ static int sdcardfs_permission(struct inode *inode, int mask)
 
 }
 
-static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia)
+static int sdcardfs_setattr_wrn(struct dentry *dentry, struct iattr *ia)
+{
+       WARN(1, "sdcardfs does not support setattr. User setattr2.\n");
+       return -EINVAL;
+}
+
+static int sdcardfs_setattr(struct vfsmount *mnt, struct dentry *dentry, struct iattr *ia)
 {
        int err;
        struct dentry *lower_dentry;
+       struct vfsmount *lower_mnt;
        struct inode *inode;
        struct inode *lower_inode;
        struct path lower_path;
        struct iattr lower_ia;
        struct dentry *parent;
+       struct inode tmp;
+       struct inode *top;
+       const struct cred *saved_cred = NULL;
 
        inode = d_inode(dentry);
+       top = grab_top(SDCARDFS_I(inode));
+
+       if (!top) {
+               release_top(SDCARDFS_I(inode));
+               return -EINVAL;
+       }
+
+       /*
+        * Permission check on sdcardfs inode.
+        * Calling process should have AID_SDCARD_RW permission
+        * Since generic_permission only needs i_mode, i_uid,
+        * i_gid, and i_sb, we can create a fake inode to pass
+        * this information down in.
+        *
+        * The underlying code may attempt to take locks in some
+        * cases for features we're not using, but if that changes,
+        * locks must be dealt with to avoid undefined behavior.
+        *
+        */
+       copy_attrs(&tmp, inode);
+       tmp.i_uid = make_kuid(&init_user_ns, SDCARDFS_I(top)->d_uid);
+       tmp.i_gid = make_kgid(&init_user_ns, get_gid(mnt, SDCARDFS_I(top)));
+       tmp.i_mode = (inode->i_mode & S_IFMT) | get_mode(mnt, SDCARDFS_I(top));
+       tmp.i_size = i_size_read(inode);
+       release_top(SDCARDFS_I(inode));
+       tmp.i_sb = inode->i_sb;
 
        /*
         * Check if user has permission to change inode.  We don't check if
         * this user can change the lower inode: that should happen when
         * calling notify_change on the lower inode.
         */
-       err = inode_change_ok(inode, ia);
+       /* prepare our own lower struct iattr (with the lower file) */
+       memcpy(&lower_ia, ia, sizeof(lower_ia));
+       /* Allow touch updating timestamps. A previous permission check ensures
+        * we have write access. Changes to mode, owner, and group are ignored*/
+       ia->ia_valid |= ATTR_FORCE;
+       err = inode_change_ok(&tmp, ia);
 
-       /* no vfs_XXX operations required, cred overriding will be skipped. wj*/
        if (!err) {
                /* check the Android group ID */
                parent = dget_parent(dentry);
-               if(!check_caller_access_to_name(d_inode(parent), dentry->d_name.name)) {
+               if(!check_caller_access_to_name(d_inode(parent), &dentry->d_name)) {
                        printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n"
                                                         "  dentry: %s, task:%s\n",
                                                         __func__, dentry->d_name.name, current->comm);
@@ -659,12 +757,14 @@ static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia)
        if (err)
                goto out_err;
 
+       /* save current_cred and override it */
+       OVERRIDE_CRED(SDCARDFS_SB(dentry->d_sb), saved_cred, SDCARDFS_I(inode));
+
        sdcardfs_get_lower_path(dentry, &lower_path);
        lower_dentry = lower_path.dentry;
+       lower_mnt = lower_path.mnt;
        lower_inode = sdcardfs_lower_inode(inode);
 
-       /* prepare our own lower struct iattr (with the lower file) */
-       memcpy(&lower_ia, ia, sizeof(lower_ia));
        if (ia->ia_valid & ATTR_FILE)
                lower_ia.ia_file = sdcardfs_lower_file(ia->ia_file);
 
@@ -681,7 +781,7 @@ static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia)
        if (current->mm)
                down_write(&current->mm->mmap_sem);
        if (ia->ia_valid & ATTR_SIZE) {
-               err = inode_newsize_ok(inode, ia->ia_size);
+               err = inode_newsize_ok(&tmp, ia->ia_size);
                if (err) {
                        if (current->mm)
                                up_write(&current->mm->mmap_sem);
@@ -704,7 +804,7 @@ static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia)
         * tries to open(), unlink(), then ftruncate() a file.
         */
        mutex_lock(&d_inode(lower_dentry)->i_mutex);
-       err = notify_change(lower_dentry, &lower_ia, /* note: lower_ia */
+       err = notify_change2(lower_mnt, lower_dentry, &lower_ia, /* note: lower_ia */
                        NULL);
        mutex_unlock(&d_inode(lower_dentry)->i_mutex);
        if (current->mm)
@@ -723,10 +823,35 @@ static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia)
 
 out:
        sdcardfs_put_lower_path(dentry, &lower_path);
+       REVERT_CRED(saved_cred);
 out_err:
        return err;
 }
 
+static int sdcardfs_fillattr(struct vfsmount *mnt, struct inode *inode, struct kstat *stat)
+{
+       struct sdcardfs_inode_info *info = SDCARDFS_I(inode);
+       struct inode *top = grab_top(info);
+       if (!top)
+               return -EINVAL;
+
+       stat->dev = inode->i_sb->s_dev;
+       stat->ino = inode->i_ino;
+       stat->mode = (inode->i_mode  & S_IFMT) | get_mode(mnt, SDCARDFS_I(top));
+       stat->nlink = inode->i_nlink;
+       stat->uid = make_kuid(&init_user_ns, SDCARDFS_I(top)->d_uid);
+       stat->gid = make_kgid(&init_user_ns, get_gid(mnt, SDCARDFS_I(top)));
+       stat->rdev = inode->i_rdev;
+       stat->size = i_size_read(inode);
+       stat->atime = inode->i_atime;
+       stat->mtime = inode->i_mtime;
+       stat->ctime = inode->i_ctime;
+       stat->blksize = (1 << inode->i_blkbits);
+       stat->blocks = inode->i_blocks;
+       release_top(info);
+       return 0;
+}
+
 static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
                 struct kstat *stat)
 {
@@ -735,9 +860,10 @@ static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
        struct inode *lower_inode;
        struct path lower_path;
        struct dentry *parent;
+       int err;
 
        parent = dget_parent(dentry);
-       if(!check_caller_access_to_name(d_inode(parent), dentry->d_name.name)) {
+       if(!check_caller_access_to_name(d_inode(parent), &dentry->d_name)) {
                printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n"
                                                 "  dentry: %s, task:%s\n",
                                                 __func__, dentry->d_name.name, current->comm);
@@ -752,19 +878,17 @@ static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
        lower_dentry = lower_path.dentry;
        lower_inode = sdcardfs_lower_inode(inode);
 
-
        sdcardfs_copy_and_fix_attrs(inode, lower_inode);
        fsstack_copy_inode_size(inode, lower_inode);
 
-
-       generic_fillattr(inode, stat);
+       err = sdcardfs_fillattr(mnt, inode, stat);
        sdcardfs_put_lower_path(dentry, &lower_path);
-       return 0;
+       return err;
 }
 
 const struct inode_operations sdcardfs_symlink_iops = {
-       .permission     = sdcardfs_permission,
-       .setattr        = sdcardfs_setattr,
+       .permission2    = sdcardfs_permission,
+       .setattr2       = sdcardfs_setattr,
        /* XXX Following operations are implemented,
         *     but FUSE(sdcard) or FAT does not support them
         *     These methods are *NOT* perfectly tested.
@@ -777,14 +901,14 @@ const struct inode_operations sdcardfs_symlink_iops = {
 const struct inode_operations sdcardfs_dir_iops = {
        .create         = sdcardfs_create,
        .lookup         = sdcardfs_lookup,
-#if 0
-       .permission     = sdcardfs_permission,
-#endif
+       .permission     = sdcardfs_permission_wrn,
+       .permission2    = sdcardfs_permission,
        .unlink         = sdcardfs_unlink,
        .mkdir          = sdcardfs_mkdir,
        .rmdir          = sdcardfs_rmdir,
        .rename         = sdcardfs_rename,
-       .setattr        = sdcardfs_setattr,
+       .setattr        = sdcardfs_setattr_wrn,
+       .setattr2       = sdcardfs_setattr,
        .getattr        = sdcardfs_getattr,
        /* XXX Following operations are implemented,
         *     but FUSE(sdcard) or FAT does not support them
@@ -796,7 +920,9 @@ const struct inode_operations sdcardfs_dir_iops = {
 };
 
 const struct inode_operations sdcardfs_main_iops = {
-       .permission     = sdcardfs_permission,
-       .setattr        = sdcardfs_setattr,
+       .permission     = sdcardfs_permission_wrn,
+       .permission2    = sdcardfs_permission,
+       .setattr        = sdcardfs_setattr_wrn,
+       .setattr2       = sdcardfs_setattr,
        .getattr        = sdcardfs_getattr,
 };