/* final actions when unmounting a file system */ static void sdcardfs_put_super(struct super_block *sb) { struct sdcardfs_sb_info *spd; struct super_block *s; spd = SDCARDFS_SB(sb); if (!spd) return; if(spd->obbpath_s) { kfree(spd->obbpath_s); path_put(&spd->obbpath); } /* decrement lower super references */ s = sdcardfs_lower_super(sb); sdcardfs_set_lower_super(sb, NULL); atomic_dec(&s->s_active); if(spd->pkgl_id) packagelist_destroy(spd->pkgl_id); kfree(spd); sb->s_fs_info = NULL; }
/* * our custom d_alloc_root work-alike * * we can't use d_alloc_root if we want to use our own interpose function * unchanged, so we simply call our own "fake" d_alloc_root */ static struct dentry *sdcardfs_d_alloc_root(struct super_block *sb) { struct dentry *ret = NULL; //struct sdcardfs_sb_info *sbi = SDCARDFS_SB(sb); struct dentry *(*__d_alloc_new)(struct super_block *, const struct qstr *) = (void *)kallsyms_lookup_name("__d_alloc"); if (sb) { static const struct qstr name = { .name = "/", .len = 1 }; ret = __d_alloc_new(sb, &name); if (ret) { d_set_d_op(ret, &sdcardfs_ci_dops); ret->d_parent = ret; } } return ret; } /* * 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) { int err = 0; int debug; struct super_block *lower_sb; struct path lower_path; struct sdcardfs_sb_info *sb_info; void *pkgl_id; printk(KERN_INFO "sdcardfs version 2.0\n"); if (!dev_name) { printk(KERN_ERR "sdcardfs: read_super: missing dev_name argument\n"); err = -EINVAL; goto out; } printk(KERN_INFO "sdcardfs: dev_name -> %s\n", dev_name); printk(KERN_INFO "sdcardfs: options -> %s\n", (char *)raw_data); /* 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); goto out; } /* allocate superblock private data */ sb->s_fs_info = kzalloc(sizeof(struct sdcardfs_sb_info), GFP_KERNEL); if (!SDCARDFS_SB(sb)) { printk(KERN_CRIT "sdcardfs: read_super: out of memory\n"); err = -ENOMEM; goto out_free; } sb_info = sb->s_fs_info; /* parse options */ err = parse_options(sb, raw_data, silent, &debug, &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); sdcardfs_set_lower_super(sb, lower_sb); /* inherit maxbytes from lower file system */ sb->s_maxbytes = lower_sb->s_maxbytes; /* * Our c/m/atime granularity is 1 ns because we may stack on file * systems whose granularity is as good. */ sb->s_time_gran = 1; sb->s_magic = SDCARDFS_SUPER_MAGIC; sb->s_op = &sdcardfs_sops; /* see comment next to the definition of sdcardfs_d_alloc_root */ sb->s_root = sdcardfs_d_alloc_root(sb); if (!sb->s_root) { err = -ENOMEM; goto out_sput; } /* link the upper and lower dentries */ sb->s_root->d_fsdata = NULL; err = new_dentry_private_data(sb->s_root); if (err) goto out_freeroot; /* set the lower dentries for s_root */ sdcardfs_set_lower_path(sb->s_root, &lower_path); /* call interpose to create the upper level inode */ err = sdcardfs_interpose(sb->s_root, sb, &lower_path); if (!err) { /* 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->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; } fix_derived_permission(sb->s_root->d_inode); if (!silent) printk(KERN_INFO "sdcardfs: mounted on top of %s type %s\n", dev_name, lower_sb->s_type->name); goto out; } /* else error: fall through */ free_dentry_private_data(sb->s_root); out_freeroot: dput(sb->s_root); 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; out_free: path_put(&lower_path); out: return err; }
/* * our custom d_alloc_root work-alike * * we can't use d_alloc_root if we want to use our own interpose function * unchanged, so we simply call our own "fake" d_alloc_root */ static struct dentry *sdcardfs_d_alloc_root(struct super_block *sb) { struct dentry *ret = NULL; if (sb) { static const struct qstr name = { .name = "/", .len = 1 }; ret = __d_alloc(sb, &name); if (ret) { d_set_d_op(ret, &sdcardfs_ci_dops); ret->d_parent = ret; } } return ret; } /* * 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) { int err = 0; int debug; struct super_block *lower_sb; struct path lower_path; struct sdcardfs_sb_info *sb_info; void *pkgl_id; printk(KERN_INFO "sdcardfs: version %s\n", SDCARDFS_VERSION); if (!dev_name) { printk(KERN_ERR "sdcardfs: read_super: missing dev_name argument\n"); err = -EINVAL; goto out; } printk(KERN_INFO "sdcardfs: dev_name -> %s\n", dev_name); printk(KERN_INFO "sdcardfs: options -> %s\n", (char *)raw_data); /* 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); goto out; } /* allocate superblock private data */ sb->s_fs_info = kzalloc(sizeof(struct sdcardfs_sb_info), GFP_KERNEL); if (!SDCARDFS_SB(sb)) { printk(KERN_CRIT "sdcardfs: read_super: out of memory\n"); err = -ENOMEM; goto out_free; } sb_info = sb->s_fs_info; /* parse options */ err = parse_options(sb, raw_data, silent, &debug, &sb_info->options); if (err) { printk(KERN_ERR "sdcardfs: invalid options or out of memory\n"); goto out_freesbi; } pkgl_id = packagelist_create(); 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); sdcardfs_set_lower_super(sb, lower_sb); /* inherit maxbytes from lower file system */ sb->s_maxbytes = lower_sb->s_maxbytes; /* * Our c/m/atime granularity is 1 ns because we may stack on file * systems whose granularity is as good. */ sb->s_time_gran = 1; sb->s_magic = SDCARDFS_SUPER_MAGIC; if (sb_info->options.type != TYPE_NONE) sb->s_op = &sdcardfs_multimount_sops; else sb->s_op = &sdcardfs_sops; /* see comment next to the definition of sdcardfs_d_alloc_root */ sb->s_root = sdcardfs_d_alloc_root(sb); if (!sb->s_root) { err = -ENOMEM; goto out_sput; } /* link the upper and lower dentries */ sb->s_root->d_fsdata = NULL; err = new_dentry_private_data(sb->s_root); if (err) goto out_freeroot; /* set the lower dentries for s_root */ sdcardfs_set_lower_path(sb->s_root, &lower_path); /* call interpose to create the upper level inode */ err = sdcardfs_interpose(sb->s_root, sb, &lower_path); if (!err) { /* setup permission policy */ if(sb_info->options.multi_user){ setup_derived_state(sb->s_root->d_inode, PERM_PRE_ROOT, sb_info->options.userid, AID_ROOT, sb_info->options.gid, false); 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->options.fs_low_uid, sb_info->options.fs_low_gid, 00775); } else { setup_derived_state(sb->s_root->d_inode, PERM_ROOT, sb_info->options.userid, AID_ROOT, sb_info->options.gid, false); sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL); snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name); } fix_derived_permission(sb->s_root->d_inode); sb_info->devpath = kzalloc(PATH_MAX, GFP_KERNEL); if(sb_info->devpath && dev_name) strncpy(sb_info->devpath, dev_name, strlen(dev_name)); if (!silent && !err) printk(KERN_INFO "sdcardfs: mounted on top of %s type %s\n", dev_name, lower_sb->s_type->name); goto out; } /* else error: fall through */ free_dentry_private_data(sb->s_root); out_freeroot: dput(sb->s_root); 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; out_free: path_put(&lower_path); out: return err; }