config SDCARD_FS
tristate "sdcard file system"
- depends on EXPERIMENTAL
default n
help
Sdcardfs is based on Wrapfs file system.
* 0: tell VFS to invalidate dentry
* 1: dentry is valid
*/
-static int sdcardfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags)
{
int err = 1;
struct path parent_lower_path, lower_path;
struct dentry *lower_cur_parent_dentry = NULL;
struct dentry *lower_dentry = NULL;
- if (nd && nd->flags & LOOKUP_RCU)
+ if (flags & LOOKUP_RCU)
return -ECHILD;
spin_lock(&dentry->d_lock);
return err;
}
-static int sdcardfs_readdir(struct file *file, void *dirent, filldir_t filldir)
+static int sdcardfs_readdir(struct file *file, struct dir_context *ctx)
{
int err = 0;
struct file *lower_file = NULL;
lower_file = sdcardfs_lower_file(file);
lower_file->f_pos = file->f_pos;
- err = vfs_readdir(lower_file, filldir, dirent);
+ err = iterate_dir(lower_file, ctx);
file->f_pos = lower_file->f_pos;
if (err >= 0) /* copy the atime */
fsstack_copy_attr_atime(dentry->d_inode,
*/
file_accessed(file);
vma->vm_ops = &sdcardfs_vm_ops;
- vma->vm_flags |= VM_CAN_NONLINEAR;
file->f_mapping->a_ops = &sdcardfs_aops; /* set our aops */
if (!SDCARDFS_F(file)->lower_vm_ops) /* save for our ->fault */
/* open lower object and link sdcardfs's file struct to lower's */
sdcardfs_get_lower_path(file->f_path.dentry, &lower_path);
- lower_file = dentry_open(lower_path.dentry, lower_path.mnt,
- file->f_flags, current_cred());
+ lower_file = dentry_open(&lower_path, file->f_flags, current_cred());
+ path_put(&lower_path);
if (IS_ERR(lower_file)) {
err = PTR_ERR(lower_file);
lower_file = sdcardfs_lower_file(file);
return 0;
}
-static int
-sdcardfs_fsync(struct file *file, int datasync)
+static int sdcardfs_fsync(struct file *file, loff_t start, loff_t end,
+ int datasync)
{
int err;
struct file *lower_file;
struct path lower_path;
struct dentry *dentry = file->f_path.dentry;
+ err = generic_file_fsync(file, start, end, datasync);
+ if (err)
+ goto out;
+
lower_file = sdcardfs_lower_file(file);
sdcardfs_get_lower_path(dentry, &lower_path);
- err = vfs_fsync(lower_file, datasync);
+ err = vfs_fsync_range(lower_file, start, end, datasync);
sdcardfs_put_lower_path(dentry, &lower_path);
-
+out:
return err;
}
const struct file_operations sdcardfs_dir_fops = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
- .readdir = sdcardfs_readdir,
+ .iterate = sdcardfs_readdir,
.unlocked_ioctl = sdcardfs_unlocked_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = sdcardfs_compat_ioctl,
+++ /dev/null
-/*
- * Statically sized hash table implementation
- * (C) 2012 Sasha Levin <levinsasha928@gmail.com>
- */
-
-#ifndef _LINUX_HASHTABLE_H
-#define _LINUX_HASHTABLE_H
-
-#include <linux/list.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/hash.h>
-#include <linux/rculist.h>
-
-#define DEFINE_HASHTABLE(name, bits) \
- struct hlist_head name[1 << (bits)] = \
- { [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT }
-
-#define DECLARE_HASHTABLE(name, bits) \
- struct hlist_head name[1 << (bits)]
-
-#define HASH_SIZE(name) (ARRAY_SIZE(name))
-#define HASH_BITS(name) ilog2(HASH_SIZE(name))
-
-/* Use hash_32 when possible to allow for fast 32bit hashing in 64bit kernels. */
-#define hash_min(val, bits) \
- (sizeof(val) <= 4 ? hash_32(val, bits) : hash_long(val, bits))
-
-static inline void __hash_init(struct hlist_head *ht, unsigned int sz)
-{
- unsigned int i;
-
- for (i = 0; i < sz; i++)
- INIT_HLIST_HEAD(&ht[i]);
-}
-
-/**
- * hash_init - initialize a hash table
- * @hashtable: hashtable to be initialized
- *
- * Calculates the size of the hashtable from the given parameter, otherwise
- * same as hash_init_size.
- *
- * This has to be a macro since HASH_BITS() will not work on pointers since
- * it calculates the size during preprocessing.
- */
-#define hash_init(hashtable) __hash_init(hashtable, HASH_SIZE(hashtable))
-
-/**
- * hash_add - add an object to a hashtable
- * @hashtable: hashtable to add to
- * @node: the &struct hlist_node of the object to be added
- * @key: the key of the object to be added
- */
-#define hash_add(hashtable, node, key) \
- hlist_add_head(node, &hashtable[hash_min(key, HASH_BITS(hashtable))])
-
-/**
- * hash_add_rcu - add an object to a rcu enabled hashtable
- * @hashtable: hashtable to add to
- * @node: the &struct hlist_node of the object to be added
- * @key: the key of the object to be added
- */
-#define hash_add_rcu(hashtable, node, key) \
- hlist_add_head_rcu(node, &hashtable[hash_min(key, HASH_BITS(hashtable))])
-
-/**
- * hash_hashed - check whether an object is in any hashtable
- * @node: the &struct hlist_node of the object to be checked
- */
-static inline bool hash_hashed(struct hlist_node *node)
-{
- return !hlist_unhashed(node);
-}
-
-static inline bool __hash_empty(struct hlist_head *ht, unsigned int sz)
-{
- unsigned int i;
-
- for (i = 0; i < sz; i++)
- if (!hlist_empty(&ht[i]))
- return false;
-
- return true;
-}
-
-/**
- * hash_empty - check whether a hashtable is empty
- * @hashtable: hashtable to check
- *
- * This has to be a macro since HASH_BITS() will not work on pointers since
- * it calculates the size during preprocessing.
- */
-#define hash_empty(hashtable) __hash_empty(hashtable, HASH_SIZE(hashtable))
-
-/**
- * hash_del - remove an object from a hashtable
- * @node: &struct hlist_node of the object to remove
- */
-static inline void hash_del(struct hlist_node *node)
-{
- hlist_del_init(node);
-}
-
-/**
- * hash_del_rcu - remove an object from a rcu enabled hashtable
- * @node: &struct hlist_node of the object to remove
- */
-static inline void hash_del_rcu(struct hlist_node *node)
-{
- hlist_del_init_rcu(node);
-}
-
-/**
- * hash_for_each - iterate over a hashtable
- * @name: hashtable to iterate
- * @bkt: integer to use as bucket loop cursor
- * @obj: the type * to use as a loop cursor for each entry
- * @member: the name of the hlist_node within the struct
- */
-#define hash_for_each(name, bkt, obj, member, pos) \
- for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\
- (bkt)++)\
- hlist_for_each_entry(obj, pos, &name[bkt], member)
-
-/**
- * hash_for_each_rcu - iterate over a rcu enabled hashtable
- * @name: hashtable to iterate
- * @bkt: integer to use as bucket loop cursor
- * @obj: the type * to use as a loop cursor for each entry
- * @member: the name of the hlist_node within the struct
- */
-#define hash_for_each_rcu(name, bkt, obj, member) \
- for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\
- (bkt)++)\
- hlist_for_each_entry_rcu(obj, &name[bkt], member)
-
-/**
- * hash_for_each_safe - iterate over a hashtable safe against removal of
- * hash entry
- * @name: hashtable to iterate
- * @bkt: integer to use as bucket loop cursor
- * @tmp: a &struct used for temporary storage
- * @obj: the type * to use as a loop cursor for each entry
- * @member: the name of the hlist_node within the struct
- */
-#define hash_for_each_safe(name, bkt, tmp, obj, member, pos) \
- for ((bkt) = 0, obj = NULL; (bkt) < HASH_SIZE(name);\
- (bkt)++)\
- hlist_for_each_entry_safe(obj, pos, tmp, &name[bkt], member)
-
-/**
- * hash_for_each_possible - iterate over all possible objects hashing to the
- * same bucket
- * @name: hashtable to iterate
- * @obj: the type * to use as a loop cursor for each entry
- * @member: the name of the hlist_node within the struct
- * @key: the key of the objects to iterate over
- */
-#define hash_for_each_possible(name, obj, member, key, pos) \
- hlist_for_each_entry(obj, pos, &name[hash_min(key, HASH_BITS(name))], member)
-
-/**
- * hash_for_each_possible_rcu - iterate over all possible objects hashing to the
- * same bucket in an rcu enabled hashtable
- * in a rcu enabled hashtable
- * @name: hashtable to iterate
- * @obj: the type * to use as a loop cursor for each entry
- * @member: the name of the hlist_node within the struct
- * @key: the key of the objects to iterate over
- */
-#define hash_for_each_possible_rcu(name, obj, member, key) \
- hlist_for_each_entry_rcu(obj, &name[hash_min(key, HASH_BITS(name))],\
- member)
-
-/**
- * hash_for_each_possible_safe - iterate over all possible objects hashing to the
- * same bucket safe against removals
- * @name: hashtable to iterate
- * @obj: the type * to use as a loop cursor for each entry
- * @tmp: a &struct used for temporary storage
- * @member: the name of the hlist_node within the struct
- * @key: the key of the objects to iterate over
- */
-#define hash_for_each_possible_safe(name, obj, tmp, member, key) \
- hlist_for_each_entry_safe(obj, tmp,\
- &name[hash_min(key, HASH_BITS(name))], member)
-
-
-#endif
}
static int sdcardfs_create(struct inode *dir, struct dentry *dentry,
- int mode, struct nameidata *nd)
+ umode_t mode, bool want_excl)
{
int err = 0;
struct dentry *lower_dentry;
struct dentry *lower_parent_dentry = NULL;
- struct path lower_path, saved_path;
+ struct path lower_path;
struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
const struct cred *saved_cred = NULL;
lower_dentry = lower_path.dentry;
lower_parent_dentry = lock_parent(lower_dentry);
- err = mnt_want_write(lower_path.mnt);
- if (err)
- goto out_unlock;
-
- pathcpy(&saved_path, &nd->path);
- pathcpy(&nd->path, &lower_path);
-
/* set last 16bytes of mode field to 0664 */
mode = (mode & S_IFMT) | 00664;
- err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode, nd);
-
- pathcpy(&nd->path, &saved_path);
+ err = vfs_create(lower_parent_dentry->d_inode, lower_dentry, mode, want_excl);
if (err)
goto out;
fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode);
out:
- mnt_drop_write(lower_path.mnt);
-out_unlock:
unlock_dir(lower_parent_dentry);
sdcardfs_put_lower_path(dentry, &lower_path);
REVERT_CRED(saved_cred);
lower_new_dentry = lower_new_path.dentry;
lower_dir_dentry = lock_parent(lower_new_dentry);
- err = mnt_want_write(lower_new_path.mnt);
- if (err)
- goto out_unlock;
-
err = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode,
lower_new_dentry);
if (err || !lower_new_dentry->d_inode)
goto out;
fsstack_copy_attr_times(dir, lower_new_dentry->d_inode);
fsstack_copy_inode_size(dir, lower_new_dentry->d_inode);
- old_dentry->d_inode->i_nlink =
- sdcardfs_lower_inode(old_dentry->d_inode)->i_nlink;
+ set_nlink(old_dentry->d_inode,
+ sdcardfs_lower_inode(old_dentry->d_inode)->i_nlink);
i_size_write(new_dentry->d_inode, file_size_save);
out:
- mnt_drop_write(lower_new_path.mnt);
-out_unlock:
unlock_dir(lower_dir_dentry);
sdcardfs_put_lower_path(old_dentry, &lower_old_path);
sdcardfs_put_lower_path(new_dentry, &lower_new_path);
dget(lower_dentry);
lower_dir_dentry = lock_parent(lower_dentry);
- err = mnt_want_write(lower_path.mnt);
- if (err)
- goto out_unlock;
err = vfs_unlink(lower_dir_inode, lower_dentry);
/*
goto out;
fsstack_copy_attr_times(dir, lower_dir_inode);
fsstack_copy_inode_size(dir, lower_dir_inode);
- dentry->d_inode->i_nlink =
- sdcardfs_lower_inode(dentry->d_inode)->i_nlink;
+ set_nlink(dentry->d_inode,
+ sdcardfs_lower_inode(dentry->d_inode)->i_nlink);
dentry->d_inode->i_ctime = dir->i_ctime;
d_drop(dentry); /* this is needed, else LTP fails (VFS won't do it) */
out:
- mnt_drop_write(lower_path.mnt);
-out_unlock:
unlock_dir(lower_dir_dentry);
dput(lower_dentry);
sdcardfs_put_lower_path(dentry, &lower_path);
lower_dentry = lower_path.dentry;
lower_parent_dentry = lock_parent(lower_dentry);
- err = mnt_want_write(lower_path.mnt);
- if (err)
- goto out_unlock;
err = vfs_symlink(lower_parent_dentry->d_inode, lower_dentry, symname);
if (err)
goto out;
fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode);
out:
- mnt_drop_write(lower_path.mnt);
-out_unlock:
unlock_dir(lower_parent_dentry);
sdcardfs_put_lower_path(dentry, &lower_path);
REVERT_CRED();
return 0;
}
-static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{
int err = 0;
int make_nomedia_in_obb = 0;
lower_dentry = lower_path.dentry;
lower_parent_dentry = lock_parent(lower_dentry);
- err = mnt_want_write(lower_path.mnt);
- if (err)
- goto out_unlock;
-
/* set last 16bytes of mode field to 0775 */
mode = (mode & S_IFMT) | 00775;
err = vfs_mkdir(lower_parent_dentry->d_inode, lower_dentry, mode);
fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir));
fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode);
/* update number of links on parent directory */
- dir->i_nlink = sdcardfs_lower_inode(dir)->i_nlink;
+ set_nlink(dir, sdcardfs_lower_inode(dir)->i_nlink);
if ((sbi->options.derive == DERIVE_UNIFIED) && (!strcasecmp(dentry->d_name.name, "obb"))
&& (pi->perm == PERM_ANDROID) && (pi->userid == 0))
kfree(nomedia_fullpath);
}
out:
- mnt_drop_write(lower_path.mnt);
-out_unlock:
unlock_dir(lower_parent_dentry);
sdcardfs_put_lower_path(dentry, &lower_path);
out_revert:
lower_dentry = lower_path.dentry;
lower_dir_dentry = lock_parent(lower_dentry);
- err = mnt_want_write(lower_path.mnt);
- if (err)
- goto out_unlock;
err = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry);
if (err)
goto out;
clear_nlink(dentry->d_inode);
fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode);
- dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;
+ set_nlink(dir, lower_dir_dentry->d_inode->i_nlink);
out:
- mnt_drop_write(lower_path.mnt);
-out_unlock:
unlock_dir(lower_dir_dentry);
sdcardfs_put_real_lower(dentry, &lower_path);
REVERT_CRED(saved_cred);
}
#if 0
-static int sdcardfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
+static int sdcardfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
dev_t dev)
{
int err = 0;
lower_dentry = lower_path.dentry;
lower_parent_dentry = lock_parent(lower_dentry);
- err = mnt_want_write(lower_path.mnt);
- if (err)
- goto out_unlock;
err = vfs_mknod(lower_parent_dentry->d_inode, lower_dentry, mode, dev);
if (err)
goto out;
fsstack_copy_inode_size(dir, lower_parent_dentry->d_inode);
out:
- mnt_drop_write(lower_path.mnt);
-out_unlock:
unlock_dir(lower_parent_dentry);
sdcardfs_put_lower_path(dentry, &lower_path);
REVERT_CRED();
goto out;
}
- err = mnt_want_write(lower_old_path.mnt);
- if (err)
- goto out;
- err = mnt_want_write(lower_new_path.mnt);
- if (err)
- goto out_drop_old_write;
-
err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry,
lower_new_dir_dentry->d_inode, lower_new_dentry);
if (err)
- goto out_err;
+ goto out;
/* Copy attrs from lower dir, but i_uid/i_gid */
fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode);
}
}
-out_err:
- mnt_drop_write(lower_new_path.mnt);
-out_drop_old_write:
- mnt_drop_write(lower_old_path.mnt);
out:
unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
dput(lower_old_dir_dentry);
}
#endif
-static int sdcardfs_permission(struct inode *inode, int mask, unsigned int flags)
+static int sdcardfs_permission(struct inode *inode, int mask)
{
int err;
- if (flags & IPERM_FLAG_RCU)
- return -ECHILD;
-
/*
* Permission check on sdcardfs inode.
* Calling process should have AID_SDCARD_RW permission
*/
- err = generic_permission(inode, mask, 0, inode->i_op->check_acl);
+ err = generic_permission(inode, mask);
/* XXX
* Original sdcardfs code calls inode_permission(lower_inode,.. )
const struct inode_operations sdcardfs_dir_iops = {
.create = sdcardfs_create,
.lookup = sdcardfs_lookup,
+#if 0
.permission = sdcardfs_permission,
+#endif
.unlink = sdcardfs_unlink,
.mkdir = sdcardfs_mkdir,
.rmdir = sdcardfs_rmdir,
return 0;
}
-static struct inode *sdcardfs_iget(struct super_block *sb,
- struct inode *lower_inode)
+struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode)
{
struct sdcardfs_inode_info *info;
struct inode *inode; /* the new inode to return */
* Fills in lower_parent_path with <dentry,mnt> on success.
*/
static struct dentry *__sdcardfs_lookup(struct dentry *dentry,
- struct nameidata *nd, struct path *lower_parent_path)
+ unsigned int flags, struct path *lower_parent_path)
{
int err = 0;
struct vfsmount *lower_dir_mnt;
struct dentry *lower_dir_dentry = NULL;
struct dentry *lower_dentry;
const char *name;
- struct nameidata lower_nd;
struct path lower_path;
struct qstr this;
struct sdcardfs_sb_info *sbi;
/* Use vfs_path_lookup to check if the dentry exists or not */
if (sbi->options.lower_fs == LOWER_FS_EXT4) {
err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name,
- LOOKUP_CASE_INSENSITIVE, &lower_nd);
+ LOOKUP_CASE_INSENSITIVE, &lower_path);
} else if (sbi->options.lower_fs == LOWER_FS_FAT) {
err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, 0,
- &lower_nd);
+ &lower_path);
}
/* no error: handle positive dentries */
* and the base obbpath will be copyed to the lower_path variable.
* if an error returned, there's no change in the lower_path
* returns: -ERRNO if error (0: no error) */
- err = setup_obb_dentry(dentry, &lower_nd.path);
+ err = setup_obb_dentry(dentry, &lower_path);
if(err) {
/* if the sbi->obbpath is not available, we can optionally
}
}
- sdcardfs_set_lower_path(dentry, &lower_nd.path);
- err = sdcardfs_interpose(dentry, dentry->d_sb, &lower_nd.path);
+ sdcardfs_set_lower_path(dentry, &lower_path);
+ err = sdcardfs_interpose(dentry, dentry->d_sb, &lower_path);
if (err) /* path_put underlying path on error */
sdcardfs_put_reset_lower_path(dentry);
goto out;
* the VFS will continue the process of making this negative dentry
* into a positive one.
*/
- if (nd) {
- if (nd->flags & (LOOKUP_CREATE|LOOKUP_RENAME_TARGET))
- err = 0;
- } else
+ if (flags & (LOOKUP_CREATE|LOOKUP_RENAME_TARGET))
err = 0;
out:
* @nd : nameidata of parent inode
*/
struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry,
- struct nameidata *nd)
+ unsigned int flags)
{
struct dentry *ret = NULL, *parent;
struct path lower_parent_path;
goto out;
}
- ret = __sdcardfs_lookup(dentry, nd, &lower_parent_path);
+ ret = __sdcardfs_lookup(dentry, flags, &lower_parent_path);
if (IS_ERR(ret))
{
goto out;
return 0;
}
+#if 0
/*
* our custom d_alloc_root work-alike
*
}
return ret;
}
+#endif
/*
* There is no need to lock the sdcardfs_super_info's rwsem as there is no
struct path lower_path;
struct sdcardfs_sb_info *sb_info;
void *pkgl_id;
+ struct inode *inode;
printk(KERN_INFO "sdcardfs version 2.0\n");
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);
+ /* get a new inode and allocate our root dentry */
+ inode = sdcardfs_iget(sb, lower_path.dentry->d_inode);
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ goto out_sput;
+ }
+ sb->s_root = d_make_root(inode);
if (!sb->s_root) {
err = -ENOMEM;
- goto out_sput;
+ goto out_iput;
}
+ d_set_d_op(sb->s_root, &sdcardfs_ci_dops);
/* link the upper and lower dentries */
sb->s_root->d_fsdata = NULL;
/* 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, 00664);
- 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);
+ /*
+ * No need to call interpose because we already have a positive
+ * dentry, which was instantiated by d_make_root. Just need to
+ * d_rehash it.
+ */
+ d_rehash(sb->s_root);
- if (!silent)
- printk(KERN_INFO "sdcardfs: mounted on top of %s type %s\n",
- dev_name, lower_sb->s_type->name);
- goto out;
+ /* 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, 00664);
+ 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;
}
- /* else error: fall through */
+ 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; /* all is well */
- free_dentry_private_data(sb->s_root);
+ /* no longer needed: free_dentry_private_data(sb->s_root); */
out_freeroot:
dput(sb->s_root);
+out_iput:
+ iput(inode);
out_sput:
/* drop refs we took earlier */
atomic_dec(&lower_sb->s_active);
{
int error;
- struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
+ struct super_block *s = sget(fs_type, NULL, set_anon_super, flags, NULL);
if (IS_ERR(s))
return ERR_CAST(s);
.name = SDCARDFS_NAME,
.mount = sdcardfs_mount,
.kill_sb = generic_shutdown_super,
- .fs_flags = FS_REVAL_DOT,
+ .fs_flags = 0,
};
static int __init init_sdcardfs_fs(void)
#include "sdcardfs.h"
#include "strtok.h"
-#include "hashtable.h"
+#include <linux/hashtable.h>
#include <linux/syscalls.h>
#include <linux/kthread.h>
#include <linux/inotify.h>
#define STRING_BUF_SIZE (512)
struct hashtable_entry {
- struct hlist_node hlist;
- void *key;
+ struct hlist_node hlist;
+ void *key;
int value;
};
}
static int contain_appid_key(struct packagelist_data *pkgl_dat, void *appid) {
- struct hashtable_entry *hash_cur;
- struct hlist_node *h_n;
+ struct hashtable_entry *hash_cur;
+
+ hash_for_each_possible(pkgl_dat->appid_with_rw, hash_cur, hlist, (unsigned int)appid)
- hash_for_each_possible(pkgl_dat->appid_with_rw, hash_cur, hlist, (unsigned int)appid, h_n)
- if (appid == hash_cur->key)
- return 1;
+ if (appid == hash_cur->key)
+ return 1;
return 0;
}
{
struct packagelist_data *pkgl_dat = (struct packagelist_data *)pkgl_id;
struct hashtable_entry *hash_cur;
- struct hlist_node *h_n;
unsigned int hash = str_hash((void *)app_name);
appid_t ret_id;
//printk(KERN_INFO "sdcardfs: %s: %s, %u\n", __func__, (char *)app_name, hash);
mutex_lock(&pkgl_dat->hashtable_lock);
- hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash, h_n) {
+ hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) {
//printk(KERN_INFO "sdcardfs: %s: %s\n", __func__, (char *)hash_cur->key);
if (!strcasecmp(app_name, hash_cur->key)) {
ret_id = (appid_t)hash_cur->value;
static int insert_str_to_int(struct packagelist_data *pkgl_dat, void *key, int value) {
struct hashtable_entry *hash_cur;
struct hashtable_entry *new_entry;
- struct hlist_node *h_n;
unsigned int hash = str_hash(key);
//printk(KERN_INFO "sdcardfs: %s: %s: %d, %u\n", __func__, (char *)key, value, hash);
- hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash, h_n) {
+ hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) {
if (!strcasecmp(key, hash_cur->key)) {
hash_cur->value = value;
return 0;
static int insert_int_to_null(struct packagelist_data *pkgl_dat, void *key, int value) {
struct hashtable_entry *hash_cur;
struct hashtable_entry *new_entry;
- struct hlist_node *h_n;
//printk(KERN_INFO "sdcardfs: %s: %d: %d\n", __func__, (int)key, value);
hash_for_each_possible(pkgl_dat->appid_with_rw, hash_cur, hlist,
- (unsigned int)key, h_n) {
+ (unsigned int)key) {
if (key == hash_cur->key) {
hash_cur->value = value;
return 0;
static void remove_all_hashentrys(struct packagelist_data *pkgl_dat)
{
struct hashtable_entry *hash_cur;
- struct hlist_node *h_n;
struct hlist_node *h_t;
int i;
- hash_for_each_safe(pkgl_dat->package_to_appid, i, h_t, hash_cur, hlist, h_n)
+ hash_for_each_safe(pkgl_dat->package_to_appid, i, h_t, hash_cur, hlist)
remove_str_to_int(hash_cur);
- hash_for_each_safe(pkgl_dat->appid_with_rw, i, h_t, hash_cur, hlist, h_n)
- remove_int_to_null(hash_cur);
+ hash_for_each_safe(pkgl_dat->appid_with_rw, i, h_t, hash_cur, hlist)
+ remove_int_to_null(hash_cur);
hash_init(pkgl_dat->package_to_appid);
hash_init(pkgl_dat->appid_with_rw);
extern int new_dentry_private_data(struct dentry *dentry);
extern void free_dentry_private_data(struct dentry *dentry);
extern struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry,
- struct nameidata *nd);
+ unsigned int flags);
+extern struct inode *sdcardfs_iget(struct super_block *sb,
+ struct inode *lower_inode);
extern int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb,
struct path *lower_path);
int err;
struct dentry *dent;
struct iattr attrs;
- struct nameidata nd;
+ struct path parent;
- err = kern_path_parent(path_s, &nd);
- if (err) {
- if (err == -EEXIST)
- err = 0;
- goto out;
- }
-
- dent = lookup_create(&nd, 1);
+ dent = kern_path_locked(path_s, &parent);
if (IS_ERR(dent)) {
err = PTR_ERR(dent);
if (err == -EEXIST)
goto out_unlock;
}
- err = vfs_mkdir(nd.path.dentry->d_inode, dent, mode);
+ err = vfs_mkdir(parent.dentry->d_inode, dent, mode);
if (err) {
if (err == -EEXIST)
err = 0;
out_unlock:
/* parent dentry locked by lookup_create */
- mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
- path_put(&nd.path);
-
-out:
+ mutex_unlock(&parent.dentry->d_inode->i_mutex);
+ path_put(&parent);
return err;
}
struct inode *lower_inode;
truncate_inode_pages(&inode->i_data, 0);
- end_writeback(inode);
+ clear_inode(inode);
/*
* Decrement a reference to a lower_inode, which was incremented
* by our read_inode when it was created initially.
lower_sb->s_op->umount_begin(lower_sb);
}
-static int sdcardfs_show_options(struct seq_file *m, struct vfsmount *mnt)
+static int sdcardfs_show_options(struct seq_file *m, struct dentry *root)
{
- struct sdcardfs_sb_info *sbi = SDCARDFS_SB(mnt->mnt_sb);
+ struct sdcardfs_sb_info *sbi = SDCARDFS_SB(root->d_sb);
struct sdcardfs_mount_options *opts = &sbi->options;
if (opts->fs_low_uid != 0)