FROMLIST: drm/bridge: analogix_dp: Don't read EDID if panel present
[firefly-linux-kernel-4.4.55.git] / fs / sdcardfs / main.c
index 9d04ae8ceb467eeeab0f5acdd3e5c8c8f7a89897..7a8eae29e44dcfde56ae2971bc08d07776224cac 100644 (file)
 #include <linux/parser.h>
 
 enum {
-       Opt_uid,
+       Opt_fsuid,
+       Opt_fsgid,
        Opt_gid,
-       Opt_wgid,
        Opt_debug,
-       Opt_split,
-       Opt_derive,
-       Opt_lower_fs,
+       Opt_mask,
+       Opt_multiuser, // May need?
+       Opt_userid,
        Opt_reserved_mb,
        Opt_err,
 };
 
 static const match_table_t sdcardfs_tokens = {
-       {Opt_uid, "uid=%u"},
+       {Opt_fsuid, "fsuid=%u"},
+       {Opt_fsgid, "fsgid=%u"},
        {Opt_gid, "gid=%u"},
-       {Opt_wgid, "wgid=%u"},
        {Opt_debug, "debug"},
-       {Opt_split, "split"},
-       {Opt_derive, "derive=%s"},
-       {Opt_lower_fs, "lower_fs=%s"},
+       {Opt_mask, "mask=%u"},
+       {Opt_userid, "userid=%d"},
+       {Opt_multiuser, "multiuser"},
        {Opt_reserved_mb, "reserved_mb=%u"},
        {Opt_err, NULL}
 };
 
 static int parse_options(struct super_block *sb, char *options, int silent,
-                               int *debug, struct sdcardfs_mount_options *opts)
+                               int *debug, struct sdcardfs_vfsmount_options *vfsopts,
+                               struct sdcardfs_mount_options *opts)
 {
        char *p;
        substring_t args[MAX_OPT_ARGS];
        int option;
-       char *string_option;
 
        /* by default, we use AID_MEDIA_RW as uid, gid */
        opts->fs_low_uid = AID_MEDIA_RW;
        opts->fs_low_gid = AID_MEDIA_RW;
-       /* by default, we use AID_SDCARD_RW as write_gid */
-       opts->write_gid = AID_SDCARD_RW;
-       /* default permission policy
-        * (DERIVE_NONE | DERIVE_LEGACY | DERIVE_UNIFIED) */
-       opts->derive = DERIVE_NONE;
-       opts->split_perms = 0;
-       /* by default, we use LOWER_FS_EXT4 as lower fs type */
-       opts->lower_fs = LOWER_FS_EXT4;
+       vfsopts->mask = 0;
+       opts->multiuser = false;
+       opts->fs_user_id = 0;
+       vfsopts->gid = 0;
        /* by default, 0MB is reserved */
        opts->reserved_mb = 0;
 
@@ -85,49 +81,33 @@ static int parse_options(struct super_block *sb, char *options, int silent,
                case Opt_debug:
                        *debug = 1;
                        break;
-               case Opt_uid:
+               case Opt_fsuid:
                        if (match_int(&args[0], &option))
                                return 0;
                        opts->fs_low_uid = option;
                        break;
-               case Opt_gid:
+               case Opt_fsgid:
                        if (match_int(&args[0], &option))
                                return 0;
                        opts->fs_low_gid = option;
                        break;
-               case Opt_wgid:
+               case Opt_gid:
                        if (match_int(&args[0], &option))
                                return 0;
-                       opts->write_gid = option;
+                       vfsopts->gid = option;
                        break;
-               case Opt_split:
-                       opts->split_perms=1;
+               case Opt_userid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       opts->fs_user_id = option;
                        break;
-               case Opt_derive:
-                       string_option = match_strdup(&args[0]);
-                       if (!strcmp("none", string_option)) {
-                               opts->derive = DERIVE_NONE;
-                       } else if (!strcmp("legacy", string_option)) {
-                               opts->derive = DERIVE_LEGACY;
-                       } else if (!strcmp("unified", string_option)) {
-                               opts->derive = DERIVE_UNIFIED;
-                       } else {
-                               kfree(string_option);
-                               goto invalid_option;
-                       }
-                       kfree(string_option);
+               case Opt_mask:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       vfsopts->mask = option;
                        break;
-               case Opt_lower_fs:
-                       string_option = match_strdup(&args[0]);
-                       if (!strcmp("ext4", string_option)) {
-                               opts->lower_fs = LOWER_FS_EXT4;
-                       } else if (!strcmp("fat", string_option)) {
-                               opts->lower_fs = LOWER_FS_FAT;
-                       } else {
-                               kfree(string_option);
-                               goto invalid_option;
-                       }
-                       kfree(string_option);
+               case Opt_multiuser:
+                       opts->multiuser = true;
                        break;
                case Opt_reserved_mb:
                        if (match_int(&args[0], &option))
@@ -136,7 +116,6 @@ static int parse_options(struct super_block *sb, char *options, int silent,
                        break;
                /* unknown option */
                default:
-invalid_option:
                        if (!silent) {
                                printk( KERN_ERR "Unrecognized mount option \"%s\" "
                                                "or missing value", p);
@@ -156,6 +135,65 @@ invalid_option:
        return 0;
 }
 
+int parse_options_remount(struct super_block *sb, char *options, int silent,
+                               struct sdcardfs_vfsmount_options *vfsopts)
+{
+       char *p;
+       substring_t args[MAX_OPT_ARGS];
+       int option;
+       int debug;
+
+       if (!options)
+               return 0;
+
+       while ((p = strsep(&options, ",")) != NULL) {
+               int token;
+               if (!*p)
+                       continue;
+
+               token = match_token(p, sdcardfs_tokens, args);
+
+               switch (token) {
+               case Opt_debug:
+                       debug = 1;
+                       break;
+               case Opt_gid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       vfsopts->gid = option;
+
+                       break;
+               case Opt_mask:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       vfsopts->mask = option;
+                       break;
+               case Opt_multiuser:
+               case Opt_userid:
+               case Opt_fsuid:
+               case Opt_fsgid:
+               case Opt_reserved_mb:
+                       printk( KERN_WARNING "Option \"%s\" can't be changed during remount\n", p);
+                       break;
+               /* unknown option */
+               default:
+                       if (!silent) {
+                               printk( KERN_ERR "Unrecognized mount option \"%s\" "
+                                               "or missing value", p);
+                       }
+                       return -EINVAL;
+               }
+       }
+
+       if (debug) {
+               printk( KERN_INFO "sdcardfs : options - debug:%d\n", debug);
+               printk( KERN_INFO "sdcardfs : options - gid:%d\n", vfsopts->gid);
+               printk( KERN_INFO "sdcardfs : options - mask:%d\n", vfsopts->mask);
+       }
+
+       return 0;
+}
+
 #if 0
 /*
  * our custom d_alloc_root work-alike
@@ -184,19 +222,24 @@ static struct dentry *sdcardfs_d_alloc_root(struct super_block *sb)
 }
 #endif
 
+DEFINE_MUTEX(sdcardfs_super_list_lock);
+LIST_HEAD(sdcardfs_super_list);
+EXPORT_SYMBOL_GPL(sdcardfs_super_list_lock);
+EXPORT_SYMBOL_GPL(sdcardfs_super_list);
+
 /*
  * There is no need to lock the sdcardfs_super_info's rwsem as there is no
  * way anyone can have a reference to the superblock at this point in time.
  */
-static int sdcardfs_read_super(struct super_block *sb, const char *dev_name,
-                                               void *raw_data, int silent)
+static int sdcardfs_read_super(struct vfsmount *mnt, struct super_block *sb,
+               const char *dev_name, void *raw_data, int silent)
 {
        int err = 0;
        int debug;
        struct super_block *lower_sb;
        struct path lower_path;
        struct sdcardfs_sb_info *sb_info;
-       void *pkgl_id;
+       struct sdcardfs_vfsmount_options *mnt_opt = mnt->data;
        struct inode *inode;
 
        printk(KERN_INFO "sdcardfs version 2.0\n");
@@ -210,13 +253,13 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name,
 
        printk(KERN_INFO "sdcardfs: dev_name -> %s\n", dev_name);
        printk(KERN_INFO "sdcardfs: options -> %s\n", (char *)raw_data);
+       printk(KERN_INFO "sdcardfs: mnt -> %p\n", mnt);
 
        /* parse lower path */
        err = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
                        &lower_path);
        if (err) {
-               printk(KERN_ERR "sdcardfs: error accessing "
-                      "lower directory '%s'\n", dev_name);
+               printk(KERN_ERR "sdcardfs: error accessing lower directory '%s'\n", dev_name);
                goto out;
        }
 
@@ -229,22 +272,13 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name,
        }
 
        sb_info = sb->s_fs_info;
-
        /* parse options */
-       err = parse_options(sb, raw_data, silent, &debug, &sb_info->options);
+       err = parse_options(sb, raw_data, silent, &debug, mnt_opt, &sb_info->options);
        if (err) {
                printk(KERN_ERR "sdcardfs: invalid options\n");
                goto out_freesbi;
        }
 
-       if (sb_info->options.derive != DERIVE_NONE) {
-               pkgl_id = packagelist_create(sb_info->options.write_gid);
-               if(IS_ERR(pkgl_id))
-                       goto out_freesbi;
-               else
-                       sb_info->pkgl_id = pkgl_id;
-       }
-
        /* set the lower superblock field of upper superblock */
        lower_sb = lower_path.dentry->d_sb;
        atomic_inc(&lower_sb->s_active);
@@ -263,7 +297,7 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name,
        sb->s_op = &sdcardfs_sops;
 
        /* get a new inode and allocate our root dentry */
-       inode = sdcardfs_iget(sb, lower_path.dentry->d_inode);
+       inode = sdcardfs_iget(sb, d_inode(lower_path.dentry), 0);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
                goto out_sput;
@@ -292,41 +326,22 @@ static int sdcardfs_read_super(struct super_block *sb, const char *dev_name,
        d_rehash(sb->s_root);
 
        /* setup permission policy */
-       switch(sb_info->options.derive) {
-               case DERIVE_NONE:
-                       setup_derived_state(sb->s_root->d_inode,
-                                       PERM_ROOT, 0, AID_ROOT, AID_SDCARD_RW, 00775);
-                       sb_info->obbpath_s = NULL;
-                       break;
-               case DERIVE_LEGACY:
-                       /* Legacy behavior used to support internal multiuser layout which
-                        * places user_id at the top directory level, with the actual roots
-                        * just below that. Shared OBB path is also at top level. */
-                       setup_derived_state(sb->s_root->d_inode,
-                                       PERM_LEGACY_PRE_ROOT, 0, AID_ROOT, AID_SDCARD_R, 00771);
-                       /* initialize the obbpath string and lookup the path
-                        * sb_info->obb_path will be deactivated by path_put
-                        * on sdcardfs_put_super */
-                       sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL);
-                       snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name);
-                       err =  prepare_dir(sb_info->obbpath_s,
+       sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL);
+       mutex_lock(&sdcardfs_super_list_lock);
+       if(sb_info->options.multiuser) {
+               setup_derived_state(d_inode(sb->s_root), PERM_PRE_ROOT, sb_info->options.fs_user_id, AID_ROOT, false, d_inode(sb->s_root));
+               snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name);
+               /*err =  prepare_dir(sb_info->obbpath_s,
                                        sb_info->options.fs_low_uid,
-                                       sb_info->options.fs_low_gid, 00755);
-                       if(err)
-                               printk(KERN_ERR "sdcardfs: %s: %d, error on creating %s\n",
-                                               __func__,__LINE__, sb_info->obbpath_s);
-                       break;
-               case DERIVE_UNIFIED:
-                       /* Unified multiuser layout which places secondary user_id under
-                        * /Android/user and shared OBB path under /Android/obb. */
-                       setup_derived_state(sb->s_root->d_inode,
-                                       PERM_ROOT, 0, AID_ROOT, AID_SDCARD_R, 00771);
-
-                       sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL);
-                       snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name);
-                       break;
+                                       sb_info->options.fs_low_gid, 00755);*/
+       } else {
+               setup_derived_state(d_inode(sb->s_root), PERM_ROOT, sb_info->options.fs_user_id, AID_ROOT, false, d_inode(sb->s_root));
+               snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name);
        }
-       fix_derived_permission(sb->s_root->d_inode);
+       fixup_tmp_permissions(d_inode(sb->s_root));
+       sb_info->sb = sb;
+       list_add(&sb_info->list, &sdcardfs_super_list);
+       mutex_unlock(&sdcardfs_super_list_lock);
 
        if (!silent)
                printk(KERN_INFO "sdcardfs: mounted on top of %s type %s\n",
@@ -341,7 +356,6 @@ out_iput:
 out_sput:
        /* drop refs we took earlier */
        atomic_dec(&lower_sb->s_active);
-       packagelist_destroy(sb_info->pkgl_id);
 out_freesbi:
        kfree(SDCARDFS_SB(sb));
        sb->s_fs_info = NULL;
@@ -353,9 +367,9 @@ out:
 }
 
 /* A feature which supports mount_nodev() with options */
-static struct dentry *mount_nodev_with_options(struct file_system_type *fs_type,
-        int flags, const char *dev_name, void *data,
-        int (*fill_super)(struct super_block *, const char *, void *, int))
+static struct dentry *mount_nodev_with_options(struct vfsmount *mnt,
+       struct file_system_type *fs_type, int flags, const char *dev_name, void *data,
+        int (*fill_super)(struct vfsmount *, struct super_block *, const char *, void *, int))
 
 {
        int error;
@@ -366,7 +380,7 @@ static struct dentry *mount_nodev_with_options(struct file_system_type *fs_type,
 
        s->s_flags = flags;
 
-       error = fill_super(s, dev_name, data, flags & MS_SILENT ? 1 : 0);
+       error = fill_super(mnt, s, dev_name, data, flags & MS_SILENT ? 1 : 0);
        if (error) {
                deactivate_locked_super(s);
                return ERR_PTR(error);
@@ -375,22 +389,47 @@ static struct dentry *mount_nodev_with_options(struct file_system_type *fs_type,
        return dget(s->s_root);
 }
 
-struct dentry *sdcardfs_mount(struct file_system_type *fs_type, int flags,
+static struct dentry *sdcardfs_mount(struct vfsmount *mnt,
+               struct file_system_type *fs_type, int flags,
                            const char *dev_name, void *raw_data)
 {
        /*
         * dev_name is a lower_path_name,
         * raw_data is a option string.
         */
-       return mount_nodev_with_options(fs_type, flags, dev_name,
-                                       raw_data, sdcardfs_read_super);
+       return mount_nodev_with_options(mnt, fs_type, flags, dev_name,
+                                               raw_data, sdcardfs_read_super);
+}
+
+static struct dentry *sdcardfs_mount_wrn(struct file_system_type *fs_type, int flags,
+                   const char *dev_name, void *raw_data)
+{
+       WARN(1, "sdcardfs does not support mount. Use mount2.\n");
+       return ERR_PTR(-EINVAL);
+}
+
+void *sdcardfs_alloc_mnt_data(void) {
+       return kmalloc(sizeof(struct sdcardfs_vfsmount_options), GFP_KERNEL);
+}
+
+void sdcardfs_kill_sb(struct super_block *sb) {
+       struct sdcardfs_sb_info *sbi;
+       if (sb->s_magic == SDCARDFS_SUPER_MAGIC) {
+               sbi = SDCARDFS_SB(sb);
+               mutex_lock(&sdcardfs_super_list_lock);
+               list_del(&sbi->list);
+               mutex_unlock(&sdcardfs_super_list_lock);
+       }
+       generic_shutdown_super(sb);
 }
 
 static struct file_system_type sdcardfs_fs_type = {
        .owner          = THIS_MODULE,
        .name           = SDCARDFS_NAME,
-       .mount          = sdcardfs_mount,
-       .kill_sb        = generic_shutdown_super,
+       .mount          = sdcardfs_mount_wrn,
+       .mount2         = sdcardfs_mount,
+       .alloc_mnt_data = sdcardfs_alloc_mnt_data,
+       .kill_sb        = sdcardfs_kill_sb,
        .fs_flags       = 0,
 };