#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;
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))
break;
/* unknown option */
default:
-invalid_option:
if (!silent) {
printk( KERN_ERR "Unrecognized mount option \"%s\" "
"or missing value", p);
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
}
#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");
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;
}
}
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);
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;
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",
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;
}
/* 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;
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);
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,
};