Example #1
0
static struct dentry *
proc_fdinfo_instantiate(struct inode *dir, struct dentry *dentry,
			struct task_struct *task, const void *ptr)
{
	struct dentry *error = ERR_PTR(-ENOENT);
	unsigned fd = (unsigned long)ptr;
	struct proc_inode *ei;
	struct inode *inode;

	inode = proc_pid_make_inode(dir->i_sb, task);
	if (!inode)
		goto out;

	ei = PROC_I(inode);
	ei->fd = fd;

	inode->i_mode = S_IFREG | S_IRUSR;
	inode->i_fop = &proc_fdinfo_file_operations;

	d_set_d_op(dentry, &tid_fd_dentry_operations);
	d_add(dentry, inode);

	/* Close the race of the process dying before we return the dentry */
	if (tid_fd_revalidate(dentry, 0))
		error = NULL;
 out:
	return error;
}
Example #2
0
static int
dumpfs_read_sb(struct super_block *sb, void *data, int silent)
{
	int	err = 0;
	struct	inode *inode;
	struct	buffer_head *bh;
	struct dumpfs_sb_info	*sbi;
	dumpfs_super_block_t	*ds;	
	char *dev_name = (char *)data;

	if (!dev_name) {
		err = -EINVAL;
		goto out;
	}
	/* 
	 * dev_name is device_name or file that needs to be mounted 
	 * mount -t dumpfs /mnt/filename /mnt/dumpfs, dev_name points
 	 * to /mnt/filename.
 	 */
	/* connect dumpfs superblock later */
	sbi = kzalloc(sizeof(struct dumpfs_sb_info), GFP_KERNEL);
	if (!sbi) {
		err = -ENOMEM;
		goto out;
	}
	sb->s_fs_info = sbi;

	/* read the superblock from the disk */
	if (!(bh = sb_bread(sb, 0))) {
		goto free;
	}
	ds = (dumpfs_super_block_t *)bh->b_data;

	sb->s_magic = ds->s_magic;
	sb->s_time_gran = 1;
	sb->s_op = &dumpfs_sops;
	sbi->s_buf = ds;
	printk(KERN_INFO "sbi->s_buf %p\n", sb->s_fs_info);
	inode = dumpfs_iget(sb, DUMPFS_ROOT_INUM);
	if (IS_ERR(inode)) {
		printk(KERN_INFO "%d \n", __LINE__);
		err = PTR_ERR(inode);
		goto out;
	}
	printk(KERN_INFO "inode %p magic %x\n", inode, ds->s_magic);
	
	sb->s_root = d_make_root(inode);
	if (!sb->s_root) {
		err = -ENOMEM;
		goto free;
	}
	d_rehash(sb->s_root);
	d_set_d_op(sb->s_root, &dumpfs_dops);
	goto out;
free:
	printk(KERN_INFO "Failed free superblock");
	kfree(sb->s_fs_info);
out:
	return (err);
}
Example #3
0
static struct dentry *prlfs_lookup(struct inode *dir, struct dentry *dentry
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0)
			, unsigned int flags
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
			, struct nameidata *nd
#endif
	)
{
	int ret;
	struct prlfs_attr attr;
	struct inode *inode;

	DPRINTK("ENTER\n");
	DPRINTK("dir ino %lld entry name \"%s\"\n",
		 (u64)dir->i_ino, dentry->d_name.name);
	ret = do_prlfs_getattr(dentry, &attr);
	if (ret < 0 ) {
		if (ret == -ENOENT) {
			inode = NULL;
			ret = 0;
		} else
			goto out;
	} else {
		inode = prlfs_get_inode(dentry->d_sb, attr.mode);
		if (inode)
			prlfs_change_attributes(inode, &attr);
	}
	dentry->d_time = jiffies;
	d_add(dentry, inode);
	d_set_d_op(dentry, &prlfs_dentry_ops);
out:
	DPRINTK("EXIT returning %d\n", ret);
	return ERR_PTR(ret);
}
Example #4
0
static int
zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, zpl_umode_t mode)
{
	cred_t *cr = CRED();
	vattr_t *vap;
	struct inode *ip;
	int error;

	crhold(cr);
	vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP);
	zpl_vap_init(vap, dip, mode | S_IFDIR, cr);

	error = -zfsctl_snapdir_mkdir(dip, dname(dentry), vap, &ip, cr, 0);
	if (error == 0) {
		d_clear_d_op(dentry);
		d_set_d_op(dentry, &zpl_dops_snapdirs);
		d_instantiate(dentry, ip);
	}

	kmem_free(vap, sizeof (vattr_t));
	ASSERT3S(error, <=, 0);
	crfree(cr);

	return (error);
}
Example #5
0
zpl_snapdir_lookup(struct inode *dip, struct dentry *dentry,
    unsigned int flags)
#endif

{
	fstrans_cookie_t cookie;
	cred_t *cr = CRED();
	struct inode *ip = NULL;
	int error;

	crhold(cr);
	cookie = spl_fstrans_mark();
	error = -zfsctl_snapdir_lookup(dip, dname(dentry), &ip,
	    0, cr, NULL, NULL);
	ASSERT3S(error, <=, 0);
	spl_fstrans_unmark(cookie);
	crfree(cr);

	if (error && error != -ENOENT)
		return (ERR_PTR(error));

	ASSERT(error == 0 || ip == NULL);
	d_clear_d_op(dentry);
	d_set_d_op(dentry, &zpl_dops_snapdirs);
#ifdef HAVE_AUTOMOUNT
	dentry->d_flags |= DCACHE_NEED_AUTOMOUNT;
#endif

	return (d_splice_alias(ip, dentry));
}
static struct dentry *proc_ns_instantiate(struct inode *dir,
	struct dentry *dentry, struct task_struct *task, const void *ptr)
{
	const struct proc_ns_operations *ns_ops = ptr;
	struct inode *inode;
	struct proc_inode *ei;
	struct dentry *error = ERR_PTR(-ENOENT);
	void *ns;

	inode = proc_pid_make_inode(dir->i_sb, task);
	if (!inode)
		goto out;

	ns = ns_ops->get(task);
	if (!ns)
		goto out_iput;

	ei = PROC_I(inode);
	inode->i_mode = S_IFREG|S_IRUSR;
	inode->i_fop  = &ns_file_operations;
	ei->ns_ops    = ns_ops;
	ei->ns	      = ns;

	d_set_d_op(dentry, &pid_dentry_operations);
	d_add(dentry, inode);
	/* Close the race of the process dying before we return the dentry */
	if (pid_revalidate(dentry, 0))
		error = NULL;
out:
	return error;
out_iput:
	iput(inode);
	goto out;
}
Example #7
0
static int
proc_fd_instantiate(struct inode *dir, struct dentry *dentry,
		    struct task_struct *task, const void *ptr)
{
	unsigned fd = (unsigned long)ptr;
	struct proc_inode *ei;
	struct inode *inode;

	inode = proc_pid_make_inode(dir->i_sb, task);
	if (!inode)
		goto out;

	ei = PROC_I(inode);
	ei->fd = fd;

	inode->i_mode = S_IFLNK;
	inode->i_op = &proc_pid_link_inode_operations;
	inode->i_size = 64;

	ei->op.proc_get_link = proc_fd_link;

	d_set_d_op(dentry, &tid_fd_dentry_operations);
	d_add(dentry, inode);

	/* Close the race of the process dying before we return the dentry */
	if (tid_fd_revalidate(dentry, 0))
		return 0;
 out:
	return -ENOENT;
}
Example #8
0
File: zpl_inode.c Project: dun/zfs
zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
#endif
{
	cred_t *cr = CRED();
	struct inode *ip;
	int error;
	fstrans_cookie_t cookie;

	if (dlen(dentry) > ZFS_MAXNAMELEN)
		return (ERR_PTR(-ENAMETOOLONG));

	crhold(cr);
	cookie = spl_fstrans_mark();
	error = -zfs_lookup(dir, dname(dentry), &ip, 0, cr, NULL, NULL);
	spl_fstrans_unmark(cookie);
	ASSERT3S(error, <=, 0);
	crfree(cr);

	spin_lock(&dentry->d_lock);
	dentry->d_time = jiffies;
#ifndef HAVE_S_D_OP
	d_set_d_op(dentry, &zpl_dentry_operations);
#endif /* HAVE_S_D_OP */
	spin_unlock(&dentry->d_lock);

	if (error) {
		if (error == -ENOENT)
			return (d_splice_alias(NULL, dentry));
		else
			return (ERR_PTR(error));
	}

	return (d_splice_alias(ip, dentry));
}
Example #9
0
/*
 * Lookup the data. This is trivial - if the dentry didn't already
 * exist, we know it is negative.  Set d_op to delete negative dentries.
 */
struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
{
	if (dentry->d_name.len > NAME_MAX)
		return ERR_PTR(-ENAMETOOLONG);
	if (!dentry->d_sb->s_d_op)
		d_set_d_op(dentry, &simple_dentry_operations);
	d_add(dentry, NULL);
	return NULL;
}
Example #10
0
static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
                                      struct nameidata *nd)
{
    struct ctl_table_header *head = grab_header(dir);
    struct ctl_table *table = PROC_I(dir)->sysctl_entry;
    struct ctl_table_header *h = NULL;
    struct qstr *name = &dentry->d_name;
    struct ctl_table *p;
    struct inode *inode;
    struct dentry *err = ERR_PTR(-ENOENT);

    if (IS_ERR(head))
        return ERR_CAST(head);

    if (table && !table->child) {
        WARN_ON(1);
        goto out;
    }

    table = table ? table->child : head->ctl_table;

    p = find_in_table(table, name);
    if (!p) {
        for (h = sysctl_head_next(NULL); h; h = sysctl_head_next(h)) {
            if (h->attached_to != table)
                continue;
            p = find_in_table(h->attached_by, name);
            if (p)
                break;
        }
    }

    if (!p)
        goto out;

    if (gr_handle_sysctl(p, MAY_EXEC))
        goto out;

    err = ERR_PTR(-ENOMEM);
    inode = proc_sys_make_inode(dir->i_sb, h ? h : head, p);
    if (h)
        sysctl_head_finish(h);

    if (!inode)
        goto out;

    err = NULL;
    d_set_d_op(dentry, &proc_sys_dentry_operations);
    d_add(dentry, inode);

out:
    sysctl_head_finish(head);
    return err;
}
Example #11
0
/*
 * Lookup the data. This is trivial - if the dentry didn't already
 * exist, we know it is negative.  Set d_op to delete negative dentries.
 */
struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
{
	static const struct dentry_operations simple_dentry_operations = {
		.d_delete = simple_delete_dentry,
	};

	if (dentry->d_name.len > NAME_MAX)
		return ERR_PTR(-ENAMETOOLONG);
	d_set_d_op(dentry, &simple_dentry_operations);
	d_add(dentry, NULL);
	return NULL;
}
Example #12
0
/**
 * \<\<public\>\> This method is used when initializing a new entry.
 * It follows these steps:
 *
 * - converts the nameformat string and the args into a regular string
 * This will be the name assigned to the dentry
 * - checks whether we have a valid parent directory
 * - check whether an entry with the same name already exists
 * in the parent directory entry(if so, an error is returned)
 * - creates a new inode with the specified super block and operations
 * - creates a new dentry associated with the inode.
 * - sets a entry_operations specific to this particular entry type
 * This supports polymorphism.
 *
 * @param *self - pointer to this instance
 * @param *parent - pointer to the parent entry - has to be a directory
 * @param *mode - file type and access rights for the inode
 * @param *entry_ops - custom operations of the child class
 * @param *i_ops - inode operations
 * @param *f_ops - file operations(also stored in the new inode)
 * @param namefmt - nameformat string (printf style)
 * @param args - arguments to the format string
 * @return 0 upon success
 */
int tcmi_ctlfs_entry_init(struct tcmi_ctlfs_entry *self,
                          struct tcmi_ctlfs_entry *parent,
                          mode_t mode,
                          struct tcmi_ctlfs_ops *entry_ops,
                          const struct inode_operations *i_ops,
                          const struct file_operations *f_ops,
                          const char namefmt[], va_list args)
{
    struct inode *dir;
    struct inode *inode;

    vsnprintf(self->name, sizeof(self->name), namefmt, args);
    mdbg(INFO4, "Initializing a new tcmi_ctlfs_entry, '%s'(%p)", self->name, self);
    if (!parent) {
        mdbg(ERR4, "Can't initialized new entry '%s', no parent specified! ", self->name);
        goto exit0;
    }
    mdbg(INFO4, "Parent entry='%s'", tcmi_ctlfs_entry_name(parent));
    /* */
    dir = parent->dentry->d_inode;
    if (!S_ISDIR(dir->i_mode)) {
        mdbg(ERR3, "Can't initialize new entry '%s', parent entry is not a directory!", self->name);
        goto exit0;
    }


    /* check parent for an entry with 'name' */
    if (tcmi_ctlfs_entry_exists(parent, self->name)) {
        mdbg(ERR3,"Can't initialize new entry '%s', parent entry contains an entry of the same name!",
             self->name);
        goto exit0;
    }

    /* allocate a new inode */
    if (!(inode = tcmi_ctlfs_get_inode(dir, dir->i_sb, mode, i_ops, f_ops))) {
        mdbg(ERR3, "Failed to allocate an inode for '%s'", self->name);
        goto exit0;
    }
    /* allocate a new dentry, associated with the inode */
    if (tcmi_ctlfs_entry_alloc_dentry(self, parent, inode)) {
        mdbg(ERR3, "Failed to allocate a new dentry for %s", self->name);
        goto exit1;
    }
    /* Custom operations of the child class */
    self->entry_ops = entry_ops;
    d_set_d_op(self->dentry, self->dentry->d_op);		//Fix for new kernel, this function set dentry->flags according to dentry->op | by Jiri Rakosnik
    return 0;
    /* error handling */
exit1:
    iput(inode);
exit0:
    return -ENOSPC;
}
Example #13
0
File: dir.c Project: acton393/linux
/*
 * Initialize ceph dentry state.
 */
int ceph_init_dentry(struct dentry *dentry)
{
	struct ceph_dentry_info *di;

	if (dentry->d_fsdata)
		return 0;

	di = kmem_cache_zalloc(ceph_dentry_cachep, GFP_KERNEL);
	if (!di)
		return -ENOMEM;          /* oh well */

	spin_lock(&dentry->d_lock);
	if (dentry->d_fsdata) {
		/* lost a race */
		kmem_cache_free(ceph_dentry_cachep, di);
		goto out_unlock;
	}

	if (ceph_snap(d_inode(dentry->d_parent)) == CEPH_NOSNAP)
		d_set_d_op(dentry, &ceph_dentry_ops);
	else if (ceph_snap(d_inode(dentry->d_parent)) == CEPH_SNAPDIR)
		d_set_d_op(dentry, &ceph_snapdir_dentry_ops);
	else
		d_set_d_op(dentry, &ceph_snap_dentry_ops);

	di->dentry = dentry;
	di->lease_session = NULL;
	di->time = jiffies;
	/* avoid reordering d_fsdata setup so that the check above is safe */
	smp_mb();
	dentry->d_fsdata = di;
	ceph_dentry_lru_add(dentry);
out_unlock:
	spin_unlock(&dentry->d_lock);
	return 0;
}
Example #14
0
int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry)
{
	int err = fscrypt_get_encryption_info(dir);

	if (err)
		return err;

	if (fscrypt_has_encryption_key(dir)) {
		spin_lock(&dentry->d_lock);
		dentry->d_flags |= DCACHE_ENCRYPTED_WITH_KEY;
		spin_unlock(&dentry->d_lock);
	}

	d_set_d_op(dentry, &fscrypt_d_ops);
	return 0;
}
Example #15
0
int reiserfs_lookup_privroot(struct super_block *s)
{
	struct dentry *dentry;
	int err = 0;

	/* If we don't have the privroot located yet - go find it */
	reiserfs_mutex_lock_safe(&s->s_root->d_inode->i_mutex, s);
	dentry = lookup_one_len(PRIVROOT_NAME, s->s_root,
				strlen(PRIVROOT_NAME));
	if (!IS_ERR(dentry)) {
		REISERFS_SB(s)->priv_root = dentry;
		d_set_d_op(dentry, &xattr_lookup_poison_ops);
		if (dentry->d_inode)
			dentry->d_inode->i_flags |= S_PRIVATE;
	} else
		err = PTR_ERR(dentry);
	mutex_unlock(&s->s_root->d_inode->i_mutex);

	return err;
}
Example #16
0
static int proc_ns_instantiate(struct inode *dir,
	struct dentry *dentry, struct task_struct *task, const void *ptr)
{
	const struct proc_ns_operations *ns_ops = ptr;
	struct inode *inode;
	struct proc_inode *ei;

	inode = proc_pid_make_inode(dir->i_sb, task, S_IFLNK | S_IRWXUGO);
	if (!inode)
		goto out;

	ei = PROC_I(inode);
	inode->i_op = &proc_ns_link_inode_operations;
	ei->ns_ops = ns_ops;

	d_set_d_op(dentry, &pid_dentry_operations);
	d_add(dentry, inode);
	/* Close the race of the process dying before we return the dentry */
	if (pid_revalidate(dentry, 0))
		return 0;
out:
	return -ENOENT;
}
Example #17
0
static int proc_sys_fill_cache(struct file *filp, void *dirent,
				filldir_t filldir,
				struct ctl_table_header *head,
				struct ctl_table *table)
{
	struct dentry *child, *dir = filp->f_path.dentry;
	struct inode *inode;
	struct qstr qname;
	ino_t ino = 0;
	unsigned type = DT_UNKNOWN;

	qname.name = table->procname;
	qname.len  = strlen(table->procname);
	qname.hash = full_name_hash(qname.name, qname.len);

	child = d_lookup(dir, &qname);
	if (!child) {
		child = d_alloc(dir, &qname);
		if (child) {
			inode = proc_sys_make_inode(dir->d_sb, head, table);
			if (!inode) {
				dput(child);
				return -ENOMEM;
			} else {
				d_set_d_op(child, &proc_sys_dentry_operations);
				d_add(child, inode);
			}
		} else {
			return -ENOMEM;
		}
	}
	inode = child->d_inode;
	ino  = inode->i_ino;
	type = inode->i_mode >> 12;
	dput(child);
	return !!filldir(dirent, qname.name, qname.len, filp->f_pos, ino, type);
}
Example #18
0
/*
 * 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(NULL, &name);
		if (ret) {
			d_set_d_op(ret, &sdcardfs_ci_dops);
			ret->d_sb = sb;
			ret->d_parent = ret;
		}
	}
	return ret;
}
#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)
{
	int err = 0;
	int debug;
	struct super_block *lower_sb;
	struct path lower_path;
	struct sdcardfs_sb_info *sb_info;
	struct inode *inode;

	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;
	}

	/* 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;

	/* get a new inode and allocate our root dentry */
	inode = sdcardfs_iget(sb, lower_path.dentry->d_inode, 0);
	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_iput;
 	}
	d_set_d_op(sb->s_root, &sdcardfs_ci_dops);

	/* 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);

	/*
	 * 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);

	/* setup permission policy */
	sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL);
	mutex_lock(&sdcardfs_super_list_lock);
	if(sb_info->options.multiuser) {
		setup_derived_state(sb->s_root->d_inode, PERM_PRE_ROOT, sb_info->options.fs_user_id, AID_ROOT, false, sb->s_root->d_inode);
		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);*/
	} else {
		setup_derived_state(sb->s_root->d_inode, PERM_ROOT, sb_info->options.fs_user_id, AID_ROOT, false, sb->s_root->d_inode);
		snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name);
	}
	fix_derived_permission(sb->s_root->d_inode);
	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",
				dev_name, lower_sb->s_type->name);
	goto out; /* all is well */

	/* 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);
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(NULL, &name);
		if (ret) {
			d_set_d_op(ret, &sdcardfs_dops);
			ret->d_sb = sb;
			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;

	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;
	}

	/* setup fs_uid and fs_gid for FAT emulation : wjlee */
	sb_info = sb->s_fs_info;
	sb_info->fs_uid = AID_ROOT;
	sb_info->fs_gid = AID_SDCARD_RW;

	/* 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;
	}


	/* 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_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) {
		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);
out_freesbi:
	kfree(SDCARDFS_SB(sb));
	sb->s_fs_info = NULL;
out_free:
	path_put(&lower_path);

out:
	return err;
}
Example #20
0
/*
 * There is no need to lock the wrapfs_super_info's rwsem as there is no
 * way anyone can have a reference to the superblock at this point in time.
 */
static int wrapfs_read_super(struct super_block *sb, void *raw_data, int silent)
{
	int err = 0, i = 0;
	struct wrapfs_dentry_info *lower_root_info = NULL;
	struct inode *inode = NULL;
	if (!raw_data) {
		printk(KERN_ERR
			"u2fs: read_super: missing data argument\n");
		err = -EINVAL;
		goto out;
	}

	/* allocate superblock private data */

	sb->s_fs_info = kzalloc(sizeof(struct wrapfs_sb_info), GFP_KERNEL);
	if (!WRAPFS_SB(sb)) {
		printk(KERN_CRIT "u2fs: read_super: out of memory\n");
		err = -ENOMEM;
		goto out_free;
	}

	atomic_set(&WRAPFS_SB(sb)->generation, 1);
	WRAPFS_SB(sb)->high_branch_id = -1;
/*      Parsing the Inputs      */
	lower_root_info = wrapfs_parse_options(sb, raw_data);
	if (IS_ERR(lower_root_info)) {
		printk(KERN_ERR
			"u2fs: read_super: error while parsing options"
			"(err = %ld)\n", PTR_ERR(lower_root_info));

		err = PTR_ERR(lower_root_info);
		lower_root_info = NULL;
		goto out_free;
	}

	/* set the lower superblock field of upper superblock */
	for (i = 0; i <= 1; i++) {
		struct dentry *d = lower_root_info->lower_paths[i].dentry;
		atomic_inc(&d->d_sb->s_active);
		wrapfs_set_lower_super_idx(sb, i, d->d_sb);
	}

	/* inherit maxbytes from highest priority branch */
	sb->s_maxbytes = wrapfs_lower_super_idx(sb, 0)->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_op = &wrapfs_sops;

	/* get a new inode and allocate our root dentry */

	inode = wrapfs_new_iget(sb, iunique(sb, 1));
	if (IS_ERR(inode)) {
		err = PTR_ERR(inode);
		goto out_sput;
	}

	sb->s_root = d_alloc_root(inode);
	if (unlikely(!sb->s_root)) {
		err = -ENOMEM;
		goto out_iput;
	}

	d_set_d_op(sb->s_root, &wrapfs_dops);

	/* link the upper and lower dentries */
	sb->s_root->d_fsdata = NULL;
	err = new_dentry_private_data(sb->s_root);
	if (unlikely(err))
		goto out_freeroot;

	/* if get here: cannot have error */
	/* set the lower dentries for s_root */

	for (i = 0; i <= 1 ; i++) {
		struct dentry *d;
		struct vfsmount *m;
		d = lower_root_info->lower_paths[i].dentry;
		m = lower_root_info->lower_paths[i].mnt;
		wrapfs_set_lower_dentry_idx(sb->s_root, i, d);
		wrapfs_set_lower_mnt_idx(sb->s_root, i, m);
	}
	atomic_set(&WRAPFS_D(sb->s_root)->generation, 1);
	if (atomic_read(&inode->i_count) <= 1)
		wrapfs_fill_inode(sb->s_root, inode);
	/*
	* No need to call interpose because we already have a positive
	* dentry, which was instantiated by d_alloc_root.  Just need to
	* d_rehash it.
	*/
	d_rehash(sb->s_root);
	if (!silent)
		printk(KERN_INFO
			"u2fs: mounted on top of type\n");
	goto out;

	/* all is well */
	/* no longer needed: free_dentry_private_data(sb->s_root); */
out_freeroot:
	if (WRAPFS_D(sb->s_root)) {
		kfree(WRAPFS_D(sb->s_root)->lower_paths);
		free_dentry_private_data(sb->s_root);
	}
	dput(sb->s_root);
out_iput:
	iput(inode);
out_sput:
	/* drop refs we took earlier */
	if (lower_root_info && !IS_ERR(lower_root_info)) {
		for (i = 0; i <= 1; i++) {
			struct dentry *d;
			d = lower_root_info->lower_paths[i].dentry;
			atomic_dec(&d->d_sb->s_active);
			path_put(&lower_root_info->lower_paths[i]);
		}
		kfree(lower_root_info->lower_paths);
		kfree(lower_root_info);
		lower_root_info = NULL;
	}
out_free:
	kfree(WRAPFS_SB(sb)->data);
	kfree(WRAPFS_SB(sb));
	sb->s_fs_info = NULL;
out:
	if (lower_root_info && !IS_ERR(lower_root_info)) {
		kfree(lower_root_info->lower_paths);
		kfree(lower_root_info);
	}
	return err;
}
Example #21
0
zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
#endif
{
	cred_t *cr = CRED();
	struct inode *ip;
	int error;
	fstrans_cookie_t cookie;
	pathname_t *ppn = NULL;
	pathname_t pn;
	zfs_sb_t *zsb = dentry->d_sb->s_fs_info;

	if (dlen(dentry) > ZFS_MAXNAMELEN)
		return (ERR_PTR(-ENAMETOOLONG));

	crhold(cr);
	cookie = spl_fstrans_mark();

	/* If we are a case insensitive fs, we need the real name */
	if (zsb->z_case == ZFS_CASE_INSENSITIVE) {
		pn.pn_bufsize = ZFS_MAXNAMELEN;
		pn.pn_buf = kmem_zalloc(ZFS_MAXNAMELEN, KM_SLEEP);
		ppn = &pn;
	}

	error = -zfs_lookup(dir, dname(dentry), &ip, 0, cr, NULL, ppn);
	spl_fstrans_unmark(cookie);
	ASSERT3S(error, <=, 0);
	crfree(cr);

	spin_lock(&dentry->d_lock);
	dentry->d_time = jiffies;
#ifndef HAVE_S_D_OP
	d_set_d_op(dentry, &zpl_dentry_operations);
#endif /* HAVE_S_D_OP */
	spin_unlock(&dentry->d_lock);

	if (error) {
		if (ppn)
			kmem_free(pn.pn_buf, ZFS_MAXNAMELEN);
		if (error == -ENOENT)
			return (d_splice_alias(NULL, dentry));
		else
			return (ERR_PTR(error));
	}

	/*
	 * If we are case insensitive, call the correct function
	 * to install the name.
	 */
	if (ppn) {
		struct dentry *new_dentry;
		struct qstr ci_name;

		ci_name.name = pn.pn_buf;
		ci_name.len = strlen(pn.pn_buf);
		new_dentry = d_add_ci(dentry, ip, &ci_name);
		kmem_free(pn.pn_buf, ZFS_MAXNAMELEN);
		return (new_dentry);
	} else {
		return (d_splice_alias(ip, dentry));
	}
}
Example #22
0
zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
#endif
{
	cred_t *cr = CRED();
	struct inode *ip;
	int error;
	fstrans_cookie_t cookie;
	pathname_t *ppn = NULL;
	pathname_t pn;
	int zfs_flags = 0;
	zfs_sb_t *zsb = dentry->d_sb->s_fs_info;

	if (dlen(dentry) > ZFS_MAX_DATASET_NAME_LEN)
		return (ERR_PTR(-ENAMETOOLONG));

	crhold(cr);
	cookie = spl_fstrans_mark();

	/* If we are a case insensitive fs, we need the real name */
	if (zsb->z_case == ZFS_CASE_INSENSITIVE) {
		zfs_flags = FIGNORECASE;
		pn_alloc(&pn);
		ppn = &pn;
	}

	error = -zfs_lookup(dir, dname(dentry), &ip, zfs_flags, cr, NULL, ppn);
	spl_fstrans_unmark(cookie);
	ASSERT3S(error, <=, 0);
	crfree(cr);

	spin_lock(&dentry->d_lock);
	dentry->d_time = jiffies;
#ifndef HAVE_S_D_OP
	d_set_d_op(dentry, &zpl_dentry_operations);
#endif /* HAVE_S_D_OP */
	spin_unlock(&dentry->d_lock);

	if (error) {
		/*
		 * If we have a case sensitive fs, we do not want to
		 * insert negative entries, so return NULL for ENOENT.
		 * Fall through if the error is not ENOENT. Also free memory.
		 */
		if (ppn) {
			pn_free(ppn);
			if (error == -ENOENT)
				return (NULL);
		}

		if (error == -ENOENT)
			return (d_splice_alias(NULL, dentry));
		else
			return (ERR_PTR(error));
	}

	/*
	 * If we are case insensitive, call the correct function
	 * to install the name.
	 */
	if (ppn) {
		struct dentry *new_dentry;
		struct qstr ci_name;

		ci_name.name = pn.pn_buf;
		ci_name.len = strlen(pn.pn_buf);
		new_dentry = d_add_ci(dentry, ip, &ci_name);
		pn_free(ppn);
		return (new_dentry);
	} else {
		return (d_splice_alias(ip, dentry));
	}
}
Example #23
0
/**
 * This should allocate memory for sf_inode_info, compute a unique inode
 * number, get an inode from vfs, initialize inode info, instantiate
 * dentry.
 *
 * @param parent        inode entry of the directory
 * @param dentry        directory cache entry
 * @param path          path name
 * @param info          file information
 * @param handle        handle
 * @returns 0 on success, Linux error code otherwise
 */
static int sf_instantiate(struct inode *parent, struct dentry *dentry,
                          SHFLSTRING *path, PSHFLFSOBJINFO info, SHFLHANDLE handle)
{
    int err;
    ino_t ino;
    struct inode *inode;
    struct sf_inode_info *sf_new_i;
    struct sf_glob_info *sf_g = GET_GLOB_INFO(parent->i_sb);

    TRACE();
    BUG_ON(!sf_g);

    sf_new_i = kmalloc(sizeof(*sf_new_i), GFP_KERNEL);
    if (!sf_new_i)
    {
        LogRelFunc(("could not allocate inode info.\n"));
        err = -ENOMEM;
        goto fail0;
    }

    ino = iunique(parent->i_sb, 1);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
    inode = iget_locked(parent->i_sb, ino);
#else
    inode = iget(parent->i_sb, ino);
#endif
    if (!inode)
    {
        LogFunc(("iget failed\n"));
        err = -ENOMEM;
        goto fail1;
    }

    sf_init_inode(sf_g, inode, info);
    sf_new_i->path = path;
    SET_INODE_INFO(inode, sf_new_i);

    dentry->d_time = jiffies;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
    d_set_d_op(dentry, &sf_dentry_ops);
#else
    dentry->d_op = &sf_dentry_ops;
#endif
    sf_new_i->force_restat = 1;
    sf_new_i->force_reread = 0;

    d_instantiate(dentry, inode);

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
    unlock_new_inode(inode);
#endif

    /* Store this handle if we leave the handle open. */
    sf_new_i->handle = handle;
    return 0;

fail1:
    kfree(sf_new_i);

fail0:
    return err;

}
Example #24
0
/*
 * 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;
}
Example #25
0
/**
 * This is called when vfs failed to locate dentry in the cache. The
 * job of this function is to allocate inode and link it to dentry.
 * [dentry] contains the name to be looked in the [parent] directory.
 * Failure to locate the name is not a "hard" error, in this case NULL
 * inode is added to [dentry] and vfs should proceed trying to create
 * the entry via other means. NULL(or "positive" pointer) ought to be
 * returned in case of success and "negative" pointer on error
 */
static struct dentry *sf_lookup(struct inode *parent, struct dentry *dentry
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
                                , unsigned int flags
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
                                , struct nameidata *nd
#endif
                               )
{
    int err;
    struct sf_inode_info *sf_i, *sf_new_i;
    struct sf_glob_info *sf_g;
    SHFLSTRING *path;
    struct inode *inode;
    ino_t ino;
    SHFLFSOBJINFO fsinfo;

    TRACE();
    sf_g = GET_GLOB_INFO(parent->i_sb);
    sf_i = GET_INODE_INFO(parent);

    BUG_ON(!sf_g);
    BUG_ON(!sf_i);

    err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
    if (err)
        goto fail0;

    err = sf_stat(__func__, sf_g, path, &fsinfo, 1);
    if (err)
    {
        if (err == -ENOENT)
        {
            /* -ENOENT: add NULL inode to dentry so it later can be
               created via call to create/mkdir/open */
            kfree(path);
            inode = NULL;
        }
        else
            goto fail1;
    }
    else
    {
        sf_new_i = kmalloc(sizeof(*sf_new_i), GFP_KERNEL);
        if (!sf_new_i)
        {
            LogRelFunc(("could not allocate memory for new inode info\n"));
            err = -ENOMEM;
            goto fail1;
        }
        sf_new_i->handle = SHFL_HANDLE_NIL;
        sf_new_i->force_reread = 0;

        ino = iunique(parent->i_sb, 1);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
        inode = iget_locked(parent->i_sb, ino);
#else
        inode = iget(parent->i_sb, ino);
#endif
        if (!inode)
        {
            LogFunc(("iget failed\n"));
            err = -ENOMEM;          /* XXX: ??? */
            goto fail2;
        }

        SET_INODE_INFO(inode, sf_new_i);
        sf_init_inode(sf_g, inode, &fsinfo);
        sf_new_i->path = path;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
        unlock_new_inode(inode);
#endif
    }

    sf_i->force_restat = 0;
    dentry->d_time = jiffies;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
    d_set_d_op(dentry, &sf_dentry_ops);
#else
    dentry->d_op = &sf_dentry_ops;
#endif
    d_add(dentry, inode);
    return NULL;

fail2:
    kfree(sf_new_i);

fail1:
    kfree(path);

fail0:
    return ERR_PTR(err);
}
Example #26
0
/*
 * 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;
}
/*
 * Main driver function for sdcardfskk's lookup.
 *
 * Returns: NULL (ok), ERR_PTR if an error occurred.
 * Fills in lower_parent_path with <dentry,mnt> on success.
 */
static struct dentry *__sdcardfskk_lookup(struct dentry *dentry,
		struct nameidata *nd, 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 sdcardfskk_sb_info *sbi;

	sbi = SDCARDFSKK_SB(dentry->d_sb);
	/* must initialize dentry operations */
	d_set_d_op(dentry, &sdcardfskk_ci_dops);

	if (IS_ROOT(dentry))
		goto out;

	name = dentry->d_name.name;

	/* now start the actual lookup procedure */
	lower_dir_dentry = lower_parent_path->dentry;
	lower_dir_mnt = lower_parent_path->mnt;

	/* 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);
	} else if (sbi->options.lower_fs == LOWER_FS_FAT) {
		err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, 0,
				&lower_nd);
	}

	/* no error: handle positive dentries */
	if (!err) {
		/* check if the dentry is an obb dentry
		 * if true, the lower_inode must be replaced with
		 * the inode of the graft path */

		if(need_graft_path_kitkat(dentry)) {

			/* setup_obb_dentry_kitkat()
 			 * The lower_path will be stored to the dentry's orig_path
			 * 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_kitkat(dentry, &lower_nd.path);

			if(err) {
				/* if the sbi->obbpath is not available, we can optionally
				 * setup the lower_path with its orig_path.
				 * but, the current implementation just returns an error
				 * because the sdcard daemon also regards this case as
				 * a lookup fail. */
				printk(KERN_INFO "sdcardfskk: base obbpath is not available\n");
				sdcardfskk_put_reset_orig_path(dentry);
				goto out;
			}
		}

		sdcardfskk_set_lower_path(dentry, &lower_nd.path);
		err = sdcardfskk_interpose(dentry, dentry->d_sb, &lower_nd.path);
		if (err) /* path_put underlying path on error */
			sdcardfskk_put_reset_lower_path(dentry);
		goto out;
	}

	/*
	 * We don't consider ENOENT an error, and we want to return a
	 * negative dentry.
	 */
	if (err && err != -ENOENT)
		goto out;

	/* instatiate a new negative dentry */
	this.name = name;
	this.len = strlen(name);
	this.hash = full_name_hash(this.name, this.len);
	lower_dentry = d_lookup(lower_dir_dentry, &this);
	if (lower_dentry)
		goto setup_lower;

	lower_dentry = d_alloc(lower_dir_dentry, &this);
	if (!lower_dentry) {
		err = -ENOMEM;
		goto out;
	}
	d_add(lower_dentry, NULL); /* instantiate and hash */

setup_lower:
	lower_path.dentry = lower_dentry;
	lower_path.mnt = mntget(lower_dir_mnt);
	sdcardfskk_set_lower_path(dentry, &lower_path);

	/*
	 * If the intent is to create a file, then don't return an error, so
	 * 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
		err = 0;

out:
	return ERR_PTR(err);
}
/*
 * Main driver function for wrapfs's lookup.
 *
 * Returns: NULL (ok), ERR_PTR if an error occurred.
 * Fills in lower_parent_path with <dentry,mnt> on success.
 */
static struct dentry *__wrapfs_lookup(struct dentry *dentry, 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 path lower_path;
	struct qstr this;

	/* must initialize dentry operations */
	d_set_d_op(dentry, &wrapfs_dops);

	if (IS_ROOT(dentry))
		goto out;

	name = dentry->d_name.name;

	/* now start the actual lookup procedure */
	lower_dir_dentry = lower_parent_path->dentry;
	lower_dir_mnt = lower_parent_path->mnt;

	/* Use vfs_path_lookup to check if the dentry exists or not */
	err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, 0,
			      &lower_path);

	/* no error: handle positive dentries */
	if (!err) {
		wrapfs_set_lower_path(dentry, &lower_path);
		err = wrapfs_interpose(dentry, dentry->d_sb, &lower_path);
		if (err) /* path_put underlying path on error */
			wrapfs_put_reset_lower_path(dentry);
		goto out;
	}

	/*
	 * We don't consider ENOENT an error, and we want to return a
	 * negative dentry.
	 */
	if (err && err != -ENOENT)
		goto out;

	/* instatiate a new negative dentry */
	this.name = name;
	this.len = strlen(name);
	this.hash = full_name_hash(this.name, this.len);
	lower_dentry = d_lookup(lower_dir_dentry, &this);
	if (lower_dentry)
		goto setup_lower;

	lower_dentry = d_alloc(lower_dir_dentry, &this);
	if (!lower_dentry) {
		err = -ENOMEM;
		goto out;
	}
	d_add(lower_dentry, NULL); /* instantiate and hash */

setup_lower:
	lower_path.dentry = lower_dentry;
	lower_path.mnt = mntget(lower_dir_mnt);
	wrapfs_set_lower_path(dentry, &lower_path);

	/*
	 * If the intent is to create a file, then don't return an error, so
	 * the VFS will continue the process of making this negative dentry
	 * into a positive one.
	 */
	if (flags & (LOOKUP_CREATE|LOOKUP_RENAME_TARGET))
		err = 0;

out:
	return ERR_PTR(err);
}
Example #29
0
/*
 * There is no need to lock the wrapfs_super_info's rwsem as there is no
 * way anyone can have a reference to the superblock at this point in time.
 */
static int wrapfs_read_super(struct super_block *sb, void *raw_data, int silent)
{
	int err = 0;
	struct super_block *lower_sb;
	struct path lower_path;
	char *dev_name = (char *) raw_data;
	struct inode *inode;

	if (!dev_name) {
		printk(KERN_ERR
		       "wrapfs: read_super: missing dev_name argument\n");
		err = -EINVAL;
		goto out;
	}

	/* parse lower path */
	err = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
			&lower_path);
	if (err) {
		printk(KERN_ERR	"wrapfs: error accessing "
		       "lower directory '%s'\n", dev_name);
		goto out;
	}

	/* allocate superblock private data */
	sb->s_fs_info = kzalloc(sizeof(struct wrapfs_sb_info), GFP_KERNEL);
	if (!WRAPFS_SB(sb)) {
		printk(KERN_CRIT "wrapfs: read_super: out of memory\n");
		err = -ENOMEM;
		goto out_free;
	}

	/* set the lower superblock field of upper superblock */
	lower_sb = lower_path.dentry->d_sb;
	atomic_inc(&lower_sb->s_active);
	wrapfs_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_op = &wrapfs_sops;

	/* get a new inode and allocate our root dentry */
	inode = wrapfs_iget(sb, lower_path.dentry->d_inode);
	if (IS_ERR(inode)) {
		err = PTR_ERR(inode);
		goto out_sput;
	}
	sb->s_root = d_alloc_root(inode);
	if (!sb->s_root) {
		err = -ENOMEM;
		goto out_iput;
	}
	d_set_d_op(sb->s_root, &wrapfs_dops);

	/* 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;

	/* if get here: cannot have error */

	/* set the lower dentries for s_root */
	wrapfs_set_lower_path(sb->s_root, &lower_path);

	/*
	 * No need to call interpose because we already have a positive
	 * dentry, which was instantiated by d_alloc_root.  Just need to
	 * d_rehash it.
	 */
	d_rehash(sb->s_root);
	if (!silent)
		printk(KERN_INFO
		       "wrapfs: mounted on top of %s type %s\n",
		       dev_name, lower_sb->s_type->name);
	goto out; /* all is well */

	/* 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);
	kfree(WRAPFS_SB(sb));
	sb->s_fs_info = NULL;
out_free:
	path_put(&lower_path);

out:
	return err;
}
Example #30
0
/*
 * Connect a unionfs inode dentry/inode with several lower ones.  This is
 * the classic stackable file system "vnode interposition" action.
 *
 * @sb: unionfs's super_block
 */
struct dentry *unionfs_interpose(struct dentry *dentry, struct super_block *sb,
				 int flag)
{
	int err = 0;
	struct inode *inode;
	int need_fill_inode = 1;
	struct dentry *spliced = NULL;

	verify_locked(dentry);

	/*
	 * We allocate our new inode below by calling unionfs_iget,
	 * which will initialize some of the new inode's fields
	 */

	/*
	 * On revalidate we've already got our own inode and just need
	 * to fix it up.
	 */
	if (flag == INTERPOSE_REVAL) {
		inode = dentry->d_inode;
		UNIONFS_I(inode)->bstart = -1;
		UNIONFS_I(inode)->bend = -1;
		atomic_set(&UNIONFS_I(inode)->generation,
			   atomic_read(&UNIONFS_SB(sb)->generation));

		UNIONFS_I(inode)->lower_inodes =
			kcalloc(sbmax(sb), sizeof(struct inode *), GFP_KERNEL);
		if (unlikely(!UNIONFS_I(inode)->lower_inodes)) {
			err = -ENOMEM;
			goto out;
		}
	} else {
		/* get unique inode number for unionfs */
		inode = unionfs_iget(sb, iunique(sb, UNIONFS_ROOT_INO));
		if (IS_ERR(inode)) {
			err = PTR_ERR(inode);
			goto out;
		}
		if (atomic_read(&inode->i_count) > 1)
			goto skip;
	}

	need_fill_inode = 0;
	unionfs_fill_inode(dentry, inode);

skip:
	/* only (our) lookup wants to do a d_add */
	switch (flag) {
	case INTERPOSE_DEFAULT:
		/* for operations which create new inodes */
		d_add(dentry, inode);
		break;
	case INTERPOSE_REVAL_NEG:
		d_instantiate(dentry, inode);
		break;
	case INTERPOSE_LOOKUP:
		spliced = d_splice_alias(inode, dentry);
		if (spliced && spliced != dentry) {
			/*
			 * d_splice can return a dentry if it was
			 * disconnected and had to be moved.  We must ensure
			 * that the private data of the new dentry is
			 * correct and that the inode info was filled
			 * properly.  Finally we must return this new
			 * dentry.
			 */
			d_set_d_op(spliced, &unionfs_dops);
			spliced->d_fsdata = dentry->d_fsdata;
			dentry->d_fsdata = NULL;
			dentry = spliced;
			if (need_fill_inode) {
				need_fill_inode = 0;
				unionfs_fill_inode(dentry, inode);
			}
			goto out_spliced;
		} else if (!spliced) {
			if (need_fill_inode) {
				need_fill_inode = 0;
				unionfs_fill_inode(dentry, inode);
				goto out_spliced;
			}
		}
		break;
	case INTERPOSE_REVAL:
		/* Do nothing. */
		break;
	default:
		printk(KERN_CRIT "unionfs: invalid interpose flag passed!\n");
		BUG();
	}
	goto out;

out_spliced:
	if (!err)
		return spliced;
out:
	return ERR_PTR(err);
}