Ejemplo n.º 1
0
static void au_br_do_del(struct super_block *sb, aufs_bindex_t bindex,
			 struct au_branch *br)
{
	aufs_bindex_t bend;
	struct au_sbinfo *sbinfo;
	struct dentry *root, *h_root;
	struct inode *inode, *h_inode;
	struct au_hinode *hinode;

	SiMustWriteLock(sb);

	root = sb->s_root;
	inode = root->d_inode;
	sbinfo = au_sbi(sb);
	bend = sbinfo->si_bend;

	h_root = au_h_dptr(root, bindex);
	hinode = au_hi(inode, bindex);
	h_inode = au_igrab(hinode->hi_inode);
	au_hiput(hinode);

	au_sbilist_lock();
	au_br_do_del_brp(sbinfo, bindex, bend);
	au_br_do_del_hdp(au_di(root), bindex, bend);
	au_br_do_del_hip(au_ii(inode), bindex, bend);
	au_sbilist_unlock();

	dput(h_root);
	iput(h_inode);
	au_br_do_free(br);
}
static void au_ren_refresh(struct au_ren_args *a)
{
	aufs_bindex_t bend, bindex;
	struct dentry *d, *h_d;
	struct inode *i, *h_i;
	struct super_block *sb;

	d = a->dst_dentry;
	d_drop(d);
	if (a->h_dst)
		/* already dget-ed by au_ren_or_cpup() */
		au_set_h_dptr(d, a->btgt, a->h_dst);

	i = a->dst_inode;
	if (i) {
		if (!au_ftest_ren(a->flags, ISDIR))
			vfsub_drop_nlink(i);
		else {
			vfsub_dead_dir(i);
			au_cpup_attr_timesizes(i);
		}
		au_update_dbrange(d, /*do_put_zero*/1);
	} else {
		bend = a->btgt;
		for (bindex = au_dbstart(d); bindex < bend; bindex++)
			au_set_h_dptr(d, bindex, NULL);
		bend = au_dbend(d);
		for (bindex = a->btgt + 1; bindex <= bend; bindex++)
			au_set_h_dptr(d, bindex, NULL);
		au_update_dbrange(d, /*do_put_zero*/0);
	}

	d = a->src_dentry;
	au_set_dbwh(d, -1);
	bend = au_dbend(d);
	for (bindex = a->btgt + 1; bindex <= bend; bindex++) {
		h_d = au_h_dptr(d, bindex);
		if (h_d)
			au_set_h_dptr(d, bindex, NULL);
	}
	au_set_dbend(d, a->btgt);

	sb = d->d_sb;
	i = a->src_inode;
	if (au_opt_test(au_mntflags(sb), PLINK) && au_plink_test(i))
		return; /* success */

	bend = au_ibend(i);
	for (bindex = a->btgt + 1; bindex <= bend; bindex++) {
		h_i = au_h_iptr(i, bindex);
		if (h_i) {
			au_xino_write(sb, bindex, h_i->i_ino, /*ino*/0);
			/* ignore this error */
			au_set_h_iptr(i, bindex, NULL, 0);
		}
	}
	au_set_ibend(i, a->btgt);
}
Ejemplo n.º 3
0
int au_refresh_hinode(struct inode *inode, struct dentry *dentry)
{
	int err, e, update;
	unsigned int flags;
	umode_t mode;
	aufs_bindex_t bindex, bend;
	unsigned char isdir;
	struct au_hinode *p;
	struct au_iinfo *iinfo;

	err = au_ii_refresh(inode, &update);
	if (unlikely(err))
		goto out;

	update = 0;
	iinfo = au_ii(inode);
	p = iinfo->ii_hinode + iinfo->ii_bstart;
	mode = (inode->i_mode & S_IFMT);
	isdir = S_ISDIR(mode);
	flags = au_hi_flags(inode, isdir);
	bend = au_dbend(dentry);
	for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) {
		struct inode *h_i;
		struct dentry *h_d;

		h_d = au_h_dptr(dentry, bindex);
		if (!h_d || !h_d->d_inode)
			continue;

		AuDebugOn(mode != (h_d->d_inode->i_mode & S_IFMT));
		if (iinfo->ii_bstart <= bindex && bindex <= iinfo->ii_bend) {
			h_i = au_h_iptr(inode, bindex);
			if (h_i) {
				if (h_i == h_d->d_inode)
					continue;
				err = -EIO;
				break;
			}
		}
		if (bindex < iinfo->ii_bstart)
			iinfo->ii_bstart = bindex;
		if (iinfo->ii_bend < bindex)
			iinfo->ii_bend = bindex;
		au_set_h_iptr(inode, bindex, au_igrab(h_d->d_inode), flags);
		update = 1;
	}
	au_update_ibrange(inode, /*do_put_zero*/0);
	e = au_dy_irefresh(inode);
	if (unlikely(e && !err))
		err = e;
	if (!err)
		au_refresh_hinode_attr(inode, update && isdir);

out:
	AuTraceErr(err);
	return err;
}
Ejemplo n.º 4
0
/*
 * simple tests for the del-entry operations.
 * following the checks in vfs, plus the parent-child relationship.
 */
int au_may_del(struct dentry *dentry, aufs_bindex_t bindex,
	       struct dentry *h_parent, int isdir)
{
	int err;
	umode_t h_mode;
	struct dentry *h_dentry, *h_latest;
	struct inode *h_inode;

	h_dentry = au_h_dptr(dentry, bindex);
	h_inode = h_dentry->d_inode;
	if (dentry->d_inode) {
		err = -ENOENT;
		if (unlikely(!h_inode || !h_inode->i_nlink))
			goto out;

		h_mode = h_inode->i_mode;
		if (!isdir) {
			err = -EISDIR;
			if (unlikely(S_ISDIR(h_mode)))
				goto out;
		} else if (unlikely(!S_ISDIR(h_mode))) {
			err = -ENOTDIR;
			goto out;
		}
	} else {
		/* rename(2) case */
		err = -EIO;
		if (unlikely(h_inode))
			goto out;
	}

	err = -ENOENT;
	/* expected parent dir is locked */
	if (unlikely(h_parent != h_dentry->d_parent))
		goto out;
	err = 0;

	/*
	 * rmdir a dir may break the consistency on some filesystem.
	 * let's try heavy test.
	 */
	err = -EACCES;
	if (unlikely(au_test_h_perm(h_parent->d_inode, MAY_EXEC | MAY_WRITE)))
		goto out;

	h_latest = au_sio_lkup_one(&dentry->d_name, h_parent,
				   au_sbr(dentry->d_sb, bindex));
	err = -EIO;
	if (IS_ERR(h_latest))
		goto out;
	if (h_latest == h_dentry)
		err = 0;
	dput(h_latest);

out:
	return err;
}
Ejemplo n.º 5
0
static int au_wr_dir_cpup(struct dentry *dentry, struct dentry *parent,
			  const unsigned char add_entry, aufs_bindex_t bcpup,
			  aufs_bindex_t bstart)
{
	int err;
	struct dentry *h_parent;
	struct inode *h_dir;

	if (add_entry)
		IMustLock(parent->d_inode);
	else
		di_write_lock_parent(parent);

	err = 0;
	if (!au_h_dptr(parent, bcpup)) {
		if (bstart < bcpup)
			err = au_cpdown_dirs(dentry, bcpup);
		else
			err = au_cpup_dirs(dentry, bcpup);
	}
	if (!err && add_entry) {
		h_parent = au_h_dptr(parent, bcpup);
		h_dir = h_parent->d_inode;
		mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT);
		err = au_lkup_neg(dentry, bcpup);
		/* todo: no unlock here */
		mutex_unlock(&h_dir->i_mutex);

		AuDbg("bcpup %d\n", bcpup);
		if (!err) {
			if (!dentry->d_inode)
				au_set_h_dptr(dentry, bstart, NULL);
			au_update_dbrange(dentry, /*do_put_zero*/0);
		}
	}

	if (!add_entry)
		di_write_unlock(parent);
	if (!err)
		err = bcpup; /* success */

	AuTraceErr(err);
	return err;
}
Ejemplo n.º 6
0
int au_find_dbindex(struct dentry *dentry, struct dentry *h_dentry)
{
	aufs_bindex_t bindex, bend;

	bend = au_dbend(dentry);
	for (bindex = au_dbstart(dentry); bindex <= bend; bindex++)
		if (au_h_dptr(dentry, bindex) == h_dentry)
			return bindex;
	return -1;
}
Ejemplo n.º 7
0
int au_refresh_hinode(struct inode *inode, struct dentry *dentry)
{
	int err, update;
	unsigned int flags;
	aufs_bindex_t bindex, bend;
	unsigned char isdir;
	struct inode *first;
	struct au_hinode *p;
	struct au_iinfo *iinfo;

	err = au_refresh_hinode_self(inode, /*do_attr*/0);
	if (unlikely(err))
		goto out;

	update = 0;
	iinfo = au_ii(inode);
	p = iinfo->ii_hinode + iinfo->ii_bstart;
	first = p->hi_inode;
	isdir = S_ISDIR(inode->i_mode);
	flags = au_hi_flags(inode, isdir);
	bend = au_dbend(dentry);
	for (bindex = au_dbstart(dentry); bindex <= bend; bindex++) {
		struct inode *h_i;
		struct dentry *h_d;

		h_d = au_h_dptr(dentry, bindex);
		if (!h_d || !h_d->d_inode)
			continue;

		if (iinfo->ii_bstart <= bindex && bindex <= iinfo->ii_bend) {
			h_i = au_h_iptr(inode, bindex);
			if (h_i) {
				if (h_i == h_d->d_inode)
					continue;
				err = -EIO;
				break;
			}
		}
		if (bindex < iinfo->ii_bstart)
			iinfo->ii_bstart = bindex;
		if (iinfo->ii_bend < bindex)
			iinfo->ii_bend = bindex;
		au_set_h_iptr(inode, bindex, au_igrab(h_d->d_inode), flags);
		update = 1;
	}
	au_update_brange(inode, /*do_put_zero*/0);

	if (unlikely(err))
		goto out;

	au_refresh_hinode_attr(inode, update && isdir);

 out:
	return err;
}
Ejemplo n.º 8
0
static noinline_for_stack
int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src,
	       struct au_cpup_reg_attr *h_src_attr)
{
	int err, sbits;
	struct iattr ia;
	struct path h_path;
	struct inode *h_isrc, *h_idst;
	struct kstat *h_st;

	h_path.dentry = au_h_dptr(dst, bindex);
	h_idst = h_path.dentry->d_inode;
	h_path.mnt = au_sbr_mnt(dst->d_sb, bindex);
	h_isrc = h_src->d_inode;
	ia.ia_valid = ATTR_FORCE | ATTR_UID | ATTR_GID
		| ATTR_ATIME | ATTR_MTIME
		| ATTR_ATIME_SET | ATTR_MTIME_SET;
	if (h_src_attr && h_src_attr->valid) {
		h_st = &h_src_attr->st;
		ia.ia_uid = h_st->uid;
		ia.ia_gid = h_st->gid;
		ia.ia_atime = h_st->atime;
		ia.ia_mtime = h_st->mtime;
		if (h_idst->i_mode != h_st->mode
		    && !S_ISLNK(h_idst->i_mode)) {
			ia.ia_valid |= ATTR_MODE;
			ia.ia_mode = h_st->mode;
		}
		sbits = !!(h_st->mode & (S_ISUID | S_ISGID));
		au_cpup_attr_flags(h_idst, h_src_attr->iflags);
	} else {
		ia.ia_uid = h_isrc->i_uid;
		ia.ia_gid = h_isrc->i_gid;
		ia.ia_atime = h_isrc->i_atime;
		ia.ia_mtime = h_isrc->i_mtime;
		if (h_idst->i_mode != h_isrc->i_mode
		    && !S_ISLNK(h_idst->i_mode)) {
			ia.ia_valid |= ATTR_MODE;
			ia.ia_mode = h_isrc->i_mode;
		}
		sbits = !!(h_isrc->i_mode & (S_ISUID | S_ISGID));
		au_cpup_attr_flags(h_idst, h_isrc->i_flags);
	}
	err = vfsub_notify_change(&h_path, &ia);

	/* is this nfs only? */
	if (!err && sbits && au_test_nfs(h_path.dentry->d_sb)) {
		ia.ia_valid = ATTR_FORCE | ATTR_MODE;
		ia.ia_mode = h_isrc->i_mode;
		err = vfsub_notify_change(&h_path, &ia);
	}

	return err;
}
static int au_ren_lock(struct au_ren_args *a)
{
	int err;
	unsigned int udba;

	err = 0;
	a->src_h_parent = au_h_dptr(a->src_parent, a->btgt);
	a->src_hdir = au_hi(a->src_dir, a->btgt);
	a->dst_h_parent = au_h_dptr(a->dst_parent, a->btgt);
	a->dst_hdir = au_hi(a->dst_dir, a->btgt);
	a->h_trap = vfsub_lock_rename(a->src_h_parent, a->src_hdir,
				      a->dst_h_parent, a->dst_hdir);
	udba = au_opt_udba(a->src_dentry->d_sb);
	if (unlikely(a->src_hdir->hi_inode != a->src_h_parent->d_inode
		     || a->dst_hdir->hi_inode != a->dst_h_parent->d_inode))
		err = au_busy_or_stale();
	if (!err && au_dbstart(a->src_dentry) == a->btgt)
		err = au_h_verify(a->src_h_dentry, udba,
				  a->src_h_parent->d_inode, a->src_h_parent,
				  a->br);
	if (!err && au_dbstart(a->dst_dentry) == a->btgt)
		err = au_h_verify(a->dst_h_dentry, udba,
				  a->dst_h_parent->d_inode, a->dst_h_parent,
				  a->br);
	if (!err) {
		err = mnt_want_write(a->br->br_mnt);
		if (unlikely(err))
			goto out_unlock;
		au_fset_ren(a->flags, MNT_WRITE);
		goto out; /* success */
	}

	err = au_busy_or_stale();

out_unlock:
	au_ren_unlock(a);
out:
	return err;
}
/* side effect: sets whlist and h_dentry */
static int au_ren_may_dir(struct au_ren_args *a)
{
	int err;
	unsigned int rdhash;
	struct dentry *d;

	d = a->dst_dentry;
	SiMustAnyLock(d->d_sb);

	err = 0;
	if (au_ftest_ren(a->flags, ISDIR) && a->dst_inode) {
		rdhash = au_sbi(d->d_sb)->si_rdhash;
		if (!rdhash)
			rdhash = au_rdhash_est(au_dir_size(/*file*/NULL, d));
		err = au_nhash_alloc(&a->whlist, rdhash, GFP_NOFS);
		if (unlikely(err))
			goto out;

		au_set_dbstart(d, a->dst_bstart);
		err = may_rename_dstdir(d, &a->whlist);
		au_set_dbstart(d, a->btgt);
	}
	a->dst_h_dentry = au_h_dptr(d, au_dbstart(d));
	if (unlikely(err))
		goto out;

	d = a->src_dentry;
	a->src_h_dentry = au_h_dptr(d, au_dbstart(d));
	if (au_ftest_ren(a->flags, ISDIR)) {
		err = may_rename_srcdir(d, a->btgt);
		if (unlikely(err)) {
			au_nhash_wh_free(&a->whlist);
			a->whlist.nh_num = 0;
		}
	}
out:
	return err;
}
Ejemplo n.º 11
0
/*
 * unlink the topmost h_dentry
 * Note: the target file MAY be modified by UDBA between this mutex_unlock() and
 *	mutex_lock() in vfs_unlink(). in this case, such changes may be lost.
 */
static int au_do_unlink(const unsigned char dmsg, struct au_mvd_args *a)
{
	int err;
	struct path h_path;

	h_path.mnt = au_sbr_mnt(a->sb, a->mvd_bsrc);
	h_path.dentry = au_h_dptr(a->dentry, a->mvd_bsrc);
	err = vfsub_unlink(a->mvd_h_src_dir, &h_path, /*force*/0);
	if (unlikely(err))
		AU_MVD_PR(dmsg, "unlink failed\n");

	AuTraceErr(err);
	return err;
}
Ejemplo n.º 12
0
int au_reopen_nondir(struct file *file)
{
	int err;
	struct dentry *dentry;
	aufs_bindex_t bstart, bindex, bend;
	struct file *hidden_file, *h_file_tmp;

	dentry = file->f_dentry;
	LKTRTrace("%.*s\n", DLNPair(dentry));
	DEBUG_ON(S_ISDIR(dentry->d_inode->i_mode)
		 || !au_h_dptr(dentry)->d_inode);
	bstart = dbstart(dentry);

	h_file_tmp = NULL;
	if (fbstart(file) == bstart) {
		hidden_file = au_h_fptr(file);
		if (file->f_mode == hidden_file->f_mode)
			return 0; /* success */
		h_file_tmp = hidden_file;
		get_file(h_file_tmp);
		set_h_fptr(file, bstart, NULL);
	}
	DEBUG_ON(fbstart(file) < bstart
		 || ftofi(file)->fi_hfile[0 + bstart].hf_file);

	hidden_file = hidden_open(dentry, bstart, file->f_flags & ~O_TRUNC);
	//if (LktrCond) {fput(hidden_file); br_put(stobr(dentry->d_sb, bstart));
	//hidden_file = ERR_PTR(-1);}
	err = PTR_ERR(hidden_file);
	if (IS_ERR(hidden_file))
		goto out; // close all?
	err = 0;
	//cpup_file_flags(hidden_file, file);
	set_fbstart(file, bstart);
	set_h_fptr(file, bstart, hidden_file);
	memcpy(&hidden_file->f_ra, &file->f_ra, sizeof(file->f_ra)); //??

	/* close lower files */
	bend = fbend(file);
	for (bindex = bstart + 1; bindex <= bend; bindex++)
		set_h_fptr(file, bindex, NULL);
	set_fbend(file, bstart);

 out:
	if (h_file_tmp)
		fput(h_file_tmp);
	TraceErr(err);
	return err;
}
Ejemplo n.º 13
0
/* make the parent dir on bdst */
static int au_do_mkdir(const unsigned char dmsg, struct au_mvd_args *a)
{
    int err;

    err = 0;
    a->mvd_hdir_src = au_hi(a->dir, a->mvd_bsrc);
    a->mvd_hdir_dst = au_hi(a->dir, a->mvd_bdst);
    a->mvd_h_src_parent = au_h_dptr(a->parent, a->mvd_bsrc);
    a->mvd_h_dst_parent = NULL;
    if (au_dbend(a->parent) >= a->mvd_bdst)
        a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst);
    if (!a->mvd_h_dst_parent) {
        err = au_cpdown_dirs(a->dentry, a->mvd_bdst);
        if (unlikely(err)) {
            AU_MVD_PR(dmsg, "cpdown_dirs failed\n");
            goto out;
        }
        a->mvd_h_dst_parent = au_h_dptr(a->parent, a->mvd_bdst);
    }

out:
    AuTraceErr(err);
    return err;
}
Ejemplo n.º 14
0
static noinline_for_stack
int au_do_h_d_reval(struct dentry *h_dentry, struct nameidata *nd,
		    struct dentry *dentry, aufs_bindex_t bindex)
{
	int err, valid;
	int (*reval)(struct dentry *, struct nameidata *);

	err = 0;
	reval = NULL;
	if (h_dentry->d_op)
		reval = h_dentry->d_op->d_revalidate;
	if (!reval)
		goto out;

	AuDbg("b%d\n", bindex);
	if (au_test_fs_null_nd(h_dentry->d_sb))
		/* it may return tri-state */
		valid = reval(h_dentry, NULL);
	else {
		struct nameidata h_nd;
		int locked;
		struct dentry *parent;

		au_h_nd(&h_nd, nd);
		parent = nd->path.dentry;
		locked = (nd && nd->path.dentry != dentry);
		if (locked)
			di_read_lock_parent(parent, AuLock_IR);
		BUG_ON(bindex > au_dbend(parent));
		h_nd.path.dentry = au_h_dptr(parent, bindex);
		BUG_ON(!h_nd.path.dentry);
		h_nd.path.mnt = au_sbr(parent->d_sb, bindex)->br_mnt;
		path_get(&h_nd.path);
		valid = reval(h_dentry, &h_nd);
		path_put(&h_nd.path);
		if (locked)
			di_read_unlock(parent, AuLock_IR);
	}

	if (unlikely(valid < 0))
		err = valid;
	else if (!valid)
		err = -EINVAL;

out:
	AuTraceErr(err);
	return err;
}
Ejemplo n.º 15
0
static int do_open_dir(struct file *file, int flags, struct file *h_file)
{
	int err;
	aufs_bindex_t bindex, btail;
	struct dentry *dentry, *h_dentry;
	struct vfsmount *mnt;

	FiMustWriteLock(file);
	AuDebugOn(h_file);

	err = 0;
	mnt = file->f_path.mnt;
	dentry = file->f_path.dentry;
	file->f_version = d_inode(dentry)->i_version;
	bindex = au_dbtop(dentry);
	au_set_fbtop(file, bindex);
	btail = au_dbtaildir(dentry);
	au_set_fbbot_dir(file, btail);
	for (; !err && bindex <= btail; bindex++) {
		h_dentry = au_h_dptr(dentry, bindex);
		if (!h_dentry)
			continue;

		err = vfsub_test_mntns(mnt, h_dentry->d_sb);
		if (unlikely(err))
			break;
		h_file = au_h_open(dentry, bindex, flags, file, /*force_wr*/0);
		if (IS_ERR(h_file)) {
			err = PTR_ERR(h_file);
			break;
		}
		au_set_h_fptr(file, bindex, h_file);
	}
	au_update_figen(file);
	/* todo: necessary? */
	/* file->f_ra = h_file->f_ra; */
	if (!err)
		return 0; /* success */

	/* close all */
	for (bindex = au_fbtop(file); bindex <= btail; bindex++)
		au_set_h_fptr(file, bindex, NULL);
	au_set_fbtop(file, -1);
	au_set_fbbot_dir(file, -1);

	return err;
}
Ejemplo n.º 16
0
loff_t au_dir_size(struct file *file, struct dentry *dentry)
{
	loff_t sz;
	aufs_bindex_t bindex, bend;
	struct file *h_file;
	struct dentry *h_dentry;

	sz = 0;
	if (file) {
		AuDebugOn(!file->f_dentry);
		AuDebugOn(!file->f_dentry->d_inode);
		AuDebugOn(!S_ISDIR(file->f_dentry->d_inode->i_mode));

		bend = au_fbend_dir(file);
		for (bindex = au_fbstart(file);
		     bindex <= bend && sz < KMALLOC_MAX_SIZE;
		     bindex++) {
			h_file = au_hf_dir(file, bindex);
			if (h_file
			    && h_file->f_dentry
			    && h_file->f_dentry->d_inode)
				sz += i_size_read(h_file->f_dentry->d_inode);
		}
	} else {
		AuDebugOn(!dentry);
		AuDebugOn(!dentry->d_inode);
		AuDebugOn(!S_ISDIR(dentry->d_inode->i_mode));

		bend = au_dbtaildir(dentry);
		for (bindex = au_dbstart(dentry);
		     bindex <= bend && sz < KMALLOC_MAX_SIZE;
		     bindex++) {
			h_dentry = au_h_dptr(dentry, bindex);
			if (h_dentry && h_dentry->d_inode)
				sz += i_size_read(h_dentry->d_inode);
		}
	}
	if (sz < KMALLOC_MAX_SIZE)
		sz = roundup_pow_of_two(sz);
	if (sz > KMALLOC_MAX_SIZE)
		sz = KMALLOC_MAX_SIZE;
	else if (sz < NAME_MAX) {
		BUILD_BUG_ON(AUFS_RDBLK_DEF < NAME_MAX);
		sz = AUFS_RDBLK_DEF;
	}
	return sz;
}
Ejemplo n.º 17
0
void au_update_dbend(struct dentry *dentry)
{
	aufs_bindex_t bindex, bstart;
	struct dentry *h_dentry;

	bstart = au_dbstart(dentry);
	for (bindex = au_dbend(dentry); bindex >= bstart; bindex--) {
		h_dentry = au_h_dptr(dentry, bindex);
		if (!h_dentry)
			continue;
		if (h_dentry->d_inode) {
			au_set_dbend(dentry, bindex);
			return;
		}
		au_set_h_dptr(dentry, bindex, NULL);
	}
}
Ejemplo n.º 18
0
static int do_open_dir(struct file *file, int flags)
{
	int err;
	aufs_bindex_t bindex, btail;
	struct dentry *dentry, *h_dentry;
	struct file *h_file;

	FiMustWriteLock(file);

	dentry = file->f_dentry;
	err = au_alive_dir(dentry);
	if (unlikely(err))
		goto out;

	file->f_version = dentry->d_inode->i_version;
	bindex = au_dbstart(dentry);
	au_set_fbstart(file, bindex);
	btail = au_dbtaildir(dentry);
	au_set_fbend_dir(file, btail);
	for (; !err && bindex <= btail; bindex++) {
		h_dentry = au_h_dptr(dentry, bindex);
		if (!h_dentry)
			continue;

		h_file = au_h_open(dentry, bindex, flags, file);
		if (IS_ERR(h_file)) {
			err = PTR_ERR(h_file);
			break;
		}
		au_set_h_fptr(file, bindex, h_file);
	}
	au_update_figen(file);
	/* todo: necessary? */
	/* file->f_ra = h_file->f_ra; */
	if (!err)
		return 0; /* success */

	/* close all */
	for (bindex = au_fbstart(file); bindex <= btail; bindex++)
		au_set_h_fptr(file, bindex, NULL);
	au_set_fbstart(file, -1);
	au_set_fbend_dir(file, -1);

out:
	return err;
}
/*
 * when we have to copyup the renaming entry, do it with the rename-target name
 * in order to minimize the cost (the later actual rename is unnecessary).
 * otherwise rename it on the target branch.
 */
static int au_ren_or_cpup(struct au_ren_args *a)
{
	int err;
	struct dentry *d;

	d = a->src_dentry;
	if (au_dbstart(d) == a->btgt) {
		a->h_path.dentry = a->dst_h_dentry;
		if (au_ftest_ren(a->flags, DIROPQ)
		    && au_dbdiropq(d) == a->btgt)
			au_fclr_ren(a->flags, DIROPQ);
		AuDebugOn(au_dbstart(d) != a->btgt);
		err = vfsub_rename(a->src_h_dir, au_h_dptr(d, a->btgt),
				   a->dst_h_dir, &a->h_path);
	} else {
		struct mutex *h_mtx = &a->src_h_dentry->d_inode->i_mutex;
		struct file *h_file;

		au_fset_ren(a->flags, CPUP);
		mutex_lock_nested(h_mtx, AuLsc_I_CHILD);
		au_set_dbstart(d, a->btgt);
		au_set_h_dptr(d, a->btgt, dget(a->dst_h_dentry));
		h_file = au_h_open_pre(d, a->src_bstart);
		if (IS_ERR(h_file)) {
			err = PTR_ERR(h_file);
			h_file = NULL;
		} else
			err = au_sio_cpup_single(d, a->btgt, a->src_bstart, -1,
						 !AuCpup_DTIME, a->dst_parent);
		mutex_unlock(h_mtx);
		au_h_open_post(d, a->src_bstart, h_file);
		if (!err) {
			d = a->dst_dentry;
			au_set_h_dptr(d, a->btgt, NULL);
			au_update_dbstart(d);
		} else {
			au_set_h_dptr(d, a->btgt, NULL);
			au_set_dbstart(d, a->src_bstart);
		}
	}
	if (!err && a->h_dst)
		/* it will be set to dinfo later */
		dget(a->h_dst);

	return err;
}
Ejemplo n.º 20
0
/*
 * extended version of au_h_dptr().
 * returns a hashed and positive (or linkable) h_dentry in bindex, NULL, or
 * error.
 */
struct dentry *au_h_d_alias(struct dentry *dentry, aufs_bindex_t bindex)
{
	struct dentry *h_dentry;
	struct inode *inode, *h_inode;

	inode = dentry->d_inode;
	AuDebugOn(!inode);

	h_dentry = NULL;
	if (au_dbstart(dentry) <= bindex
	    && bindex <= au_dbend(dentry))
		h_dentry = au_h_dptr(dentry, bindex);
	if (h_dentry && !au_d_linkable(h_dentry)) {
		dget(h_dentry);
		goto out; /* success */
	}

	AuDebugOn(bindex < au_ibstart(inode));
	AuDebugOn(au_ibend(inode) < bindex);
	h_inode = au_h_iptr(inode, bindex);
	h_dentry = d_find_alias(h_inode);
	if (h_dentry) {
		if (!IS_ERR(h_dentry)) {
			if (!au_d_linkable(h_dentry))
				goto out; /* success */
			dput(h_dentry);
		} else
			goto out;
	}

	if (au_opt_test(au_mntflags(dentry->d_sb), PLINK)) {
		h_dentry = au_plink_lkup(inode, bindex);
		AuDebugOn(!h_dentry);
		if (!IS_ERR(h_dentry)) {
			if (!au_d_hashed_positive(h_dentry))
				goto out; /* success */
			dput(h_dentry);
			h_dentry = NULL;
		}
	}

out:
	AuDbgDentry(h_dentry);
	return h_dentry;
}
Ejemplo n.º 21
0
static struct dentry *
au_h_dget_any(struct dentry *dentry, aufs_bindex_t *bindex)
{
	struct dentry *h_dentry;
	struct inode *inode, *h_inode;
	struct super_block *sb;
	aufs_bindex_t ib, db;

	/* must be positive dentry */
	inode = dentry->d_inode;
	LKTRTrace("%.*s, i%lu\n", AuDLNPair(dentry), inode->i_ino);

	sb = dentry->d_sb;
	db = au_dbstart(dentry);
	ib = au_ibstart(inode);
	if (db == ib) {
		*bindex = db;
		h_dentry = dget(au_h_dptr(dentry, db));
		if (h_dentry)
			goto out; /* success */
	}

	*bindex = ib;
	h_inode = au_h_iptr(inode, ib);
	h_dentry = d_find_alias(h_inode);
	if (h_dentry)
		goto out; /* success */

#if 0
	if (au_opt_test(au_mntflags(sb), PLINK)
	    && au_plink_test(sb, inode)) {
		h_dentry = au_plink_lkup(sb, ib, inode);
		if (IS_ERR(h_dentry))
			goto out;
		AuDebugOn(!h_dentry->d_inode);
		goto out; /* success */
	}
#endif

	h_dentry = dget(au_hi_wh(inode, ib));

 out:
	AuTraceErrPtr(h_dentry);
	return h_dentry;
}
Ejemplo n.º 22
0
struct file *au_h_open_pre(struct dentry *dentry, aufs_bindex_t bindex,
			   int force_wr)
{
	struct file *h_file;
	struct dentry *h_dentry;

	h_dentry = au_h_dptr(dentry, bindex);
	AuDebugOn(!h_dentry);
	AuDebugOn(!h_dentry->d_inode);

	h_file = NULL;
	if (au_test_hfsplus(h_dentry->d_sb)
	    && S_ISREG(h_dentry->d_inode->i_mode))
		h_file = au_h_open(dentry, bindex,
				   O_RDONLY | O_NOATIME | O_LARGEFILE,
				   /*file*/NULL, force_wr);
	return h_file;
}
Ejemplo n.º 23
0
/*
 * successful returns with iinfo write_locked
 * minus: errno
 * zero: success, matched
 * plus: no error, but unmatched
 */
static int reval_inode(struct inode *inode, struct dentry *dentry)
{
	int err;
	unsigned int gen;
	struct au_iigen iigen;
	aufs_bindex_t bindex, bend;
	struct inode *h_inode, *h_dinode;

	/*
	 * before this function, if aufs got any iinfo lock, it must be only
	 * one, the parent dir.
	 * it can happen by UDBA and the obsoleted inode number.
	 */
	err = -EIO;
	if (unlikely(inode->i_ino == parent_ino(dentry)))
		goto out;

	err = 1;
	ii_write_lock_new_child(inode);
	h_dinode = au_h_dptr(dentry, au_dbstart(dentry))->d_inode;
	bend = au_ibend(inode);
	for (bindex = au_ibstart(inode); bindex <= bend; bindex++) {
		h_inode = au_h_iptr(inode, bindex);
		if (!h_inode || h_inode != h_dinode)
			continue;

		err = 0;
		gen = au_iigen(inode, &iigen);
		if (gen == au_digen(dentry)
		    && !au_ig_ftest(iigen.ig_flags, HALF_REFRESHED))
			break;

		/* fully refresh inode using dentry */
		err = au_refresh_hinode(inode, dentry);
		if (!err)
			au_update_iigen(inode, /*half*/0);
		break;
	}

	if (unlikely(err))
		ii_write_unlock(inode);
out:
	return err;
}
Ejemplo n.º 24
0
/*
 * simple tests for the adding inode operations.
 * following the checks in vfs, plus the parent-child relationship.
 */
int au_may_add(struct dentry *dentry, aufs_bindex_t bindex,
	       struct dentry *h_parent, int isdir)
{
	int err;
	umode_t h_mode;
	struct dentry *h_dentry;
	struct inode *h_inode;

	err = -ENAMETOOLONG;
	if (unlikely(dentry->d_name.len > AUFS_MAX_NAMELEN))
		goto out;

	h_dentry = au_h_dptr(dentry, bindex);
	h_inode = h_dentry->d_inode;
	if (!dentry->d_inode) {
		err = -EEXIST;
		if (unlikely(h_inode))
			goto out;
	} else {
		/* rename(2) case */
		err = -EIO;
		if (unlikely(!h_inode || !h_inode->i_nlink))
			goto out;

		h_mode = h_inode->i_mode;
		if (!isdir) {
			err = -EISDIR;
			if (unlikely(S_ISDIR(h_mode)))
				goto out;
		} else if (unlikely(!S_ISDIR(h_mode))) {
			err = -ENOTDIR;
			goto out;
		}
	}

	err = 0;
	/* expected parent dir is locked */
	if (unlikely(h_parent != h_dentry->d_parent))
		err = -EIO;

out:
	AuTraceErr(err);
	return err;
}
Ejemplo n.º 25
0
static noinline_for_stack
int cpup_iattr(struct dentry *dst, aufs_bindex_t bindex, struct dentry *h_src,
	       struct au_hinode *hdir, struct vfsub_args *vargs)
{
	int err, sbits;
	struct dentry *h_dst;
	struct iattr ia;
	struct inode *h_isrc, *h_idst;

	h_dst = au_h_dptr(dst, bindex);
	LKTRTrace("%.*s\n", AuDLNPair(h_dst));
	h_idst = h_dst->d_inode;
	/* todo? IMustLock(h_idst); */
	h_isrc = h_src->d_inode;
	/* todo? IMustLock(h_isrc); */

	ia.ia_valid = ATTR_FORCE | ATTR_MODE | ATTR_UID | ATTR_GID
		| ATTR_ATIME | ATTR_MTIME
		| ATTR_ATIME_SET | ATTR_MTIME_SET;
	ia.ia_mode = h_isrc->i_mode;
	ia.ia_uid = h_isrc->i_uid;
	ia.ia_gid = h_isrc->i_gid;
	ia.ia_atime = h_isrc->i_atime;
	ia.ia_mtime = h_isrc->i_mtime;
	sbits = !!(ia.ia_mode & (S_ISUID | S_ISGID));
	au_cpup_attr_flags(h_idst, h_isrc);

	vfsub_args_reinit(vargs);
	vfsub_ign_hinode(vargs, IN_ATTRIB, hdir);
	err = vfsub_notify_change(h_dst, &ia, vargs);

	/* is this nfs only? */
	if (!err && sbits && au_test_nfs(h_dst->d_sb)) {
		ia.ia_valid = ATTR_FORCE | ATTR_MODE;
		ia.ia_mode = h_isrc->i_mode;
		vfsub_args_reinit(vargs);
		vfsub_ign_hinode(vargs, IN_ATTRIB, hdir);
		err = vfsub_notify_change(h_dst, &ia, vargs);
	}

	AuTraceErr(err);
	return err;
}
Ejemplo n.º 26
0
/*
 * the lifetime of branch is independent from the entry under sysfs.
 * sysfs handles the lifetime of the entry, and never call ->show() after it is
 * unlinked.
 */
static int sysaufs_si_br(struct seq_file *seq, struct super_block *sb,
			 aufs_bindex_t bindex)
{
	struct path path;
	struct dentry *root;
	struct au_branch *br;

	AuDbg("b%d\n", bindex);

	root = sb->s_root;
	di_read_lock_parent(root, !AuLock_IR);
	br = au_sbr(sb, bindex);
	path.mnt = br->br_mnt;
	path.dentry = au_h_dptr(root, bindex);
	au_seq_path(seq, &path);
	di_read_unlock(root, !AuLock_IR);
	seq_printf(seq, "=%s\n", au_optstr_br_perm(br->br_perm));
	return 0;
}
Ejemplo n.º 27
0
static int reopen_dir(struct file *file)
{
	int err;
	unsigned int flags;
	aufs_bindex_t bindex, btail, bstart;
	struct dentry *dentry, *h_dentry;
	struct file *h_file;

	/* open all lower dirs */
	dentry = file->f_dentry;
	bstart = au_dbstart(dentry);
	for (bindex = au_fbstart(file); bindex < bstart; bindex++)
		au_set_h_fptr(file, bindex, NULL);
	au_set_fbstart(file, bstart);

	btail = au_dbtaildir(dentry);
	for (bindex = au_fbend_dir(file); btail < bindex; bindex--)
		au_set_h_fptr(file, bindex, NULL);
	au_set_fbend_dir(file, btail);

	flags = vfsub_file_flags(file);
	for (bindex = bstart; bindex <= btail; bindex++) {
		h_dentry = au_h_dptr(dentry, bindex);
		if (!h_dentry)
			continue;
		h_file = au_hf_dir(file, bindex);
		if (h_file)
			continue;

		h_file = au_h_open(dentry, bindex, flags, file);
		err = PTR_ERR(h_file);
		if (IS_ERR(h_file))
			goto out; /* close all? */
		au_set_h_fptr(file, bindex, h_file);
	}
	au_update_figen(file);
	/* todo: necessary? */
	/* file->f_ra = h_file->f_ra; */
	err = 0;

out:
	return err;
}
Ejemplo n.º 28
0
loff_t au_dir_size(struct file *file, struct dentry *dentry)
{
	loff_t sz;
	aufs_bindex_t bindex, bbot;
	struct file *h_file;
	struct dentry *h_dentry;

	sz = 0;
	if (file) {
		AuDebugOn(!d_is_dir(file->f_path.dentry));

		bbot = au_fbbot_dir(file);
		for (bindex = au_fbtop(file);
		     bindex <= bbot && sz < KMALLOC_MAX_SIZE;
		     bindex++) {
			h_file = au_hf_dir(file, bindex);
			if (h_file && file_inode(h_file))
				sz += vfsub_f_size_read(h_file);
		}
	} else {
		AuDebugOn(!dentry);
		AuDebugOn(!d_is_dir(dentry));

		bbot = au_dbtaildir(dentry);
		for (bindex = au_dbtop(dentry);
		     bindex <= bbot && sz < KMALLOC_MAX_SIZE;
		     bindex++) {
			h_dentry = au_h_dptr(dentry, bindex);
			if (h_dentry && d_is_positive(h_dentry))
				sz += i_size_read(d_inode(h_dentry));
		}
	}
	if (sz < KMALLOC_MAX_SIZE)
		sz = roundup_pow_of_two(sz);
	if (sz > KMALLOC_MAX_SIZE)
		sz = KMALLOC_MAX_SIZE;
	else if (sz < NAME_MAX) {
		BUILD_BUG_ON(AUFS_RDBLK_DEF < NAME_MAX);
		sz = AUFS_RDBLK_DEF;
	}
	return sz;
}
Ejemplo n.º 29
0
static int au_opt_xino(struct super_block *sb, struct au_opt *opt,
		       struct au_opt_xino **opt_xino,
		       struct au_opts *opts)
{
	int err;
	aufs_bindex_t bend, bindex;
	struct dentry *root, *parent, *h_root;

	err = 0;
	switch (opt->type) {
	case Opt_xino:
		err = au_xino_set(sb, &opt->xino,
				  !!au_ftest_opts(opts->flags, REMOUNT));
		if (unlikely(err))
			break;

		*opt_xino = &opt->xino;
		au_xino_brid_set(sb, -1);

		/* safe d_parent access */
		parent = opt->xino.file->f_dentry->d_parent;
		root = sb->s_root;
		bend = au_sbend(sb);
		for (bindex = 0; bindex <= bend; bindex++) {
			h_root = au_h_dptr(root, bindex);
			if (h_root == parent) {
				au_xino_brid_set(sb, au_sbr_id(sb, bindex));
				break;
			}
		}
		break;

	case Opt_noxino:
		au_xino_clr(sb);
		au_xino_brid_set(sb, -1);
		*opt_xino = (void *)-1;
		break;
	}

	return err;
}
Ejemplo n.º 30
0
/*
 * the lifetime of branch is independent from the entry under sysfs.
 * sysfs handles the lifetime of the entry, and never call ->show() after it is
 * unlinked.
 */
static int sysaufs_si_br(struct seq_file *seq, struct super_block *sb,
			 aufs_bindex_t bindex, int idx)
{
	int err;
	struct path path;
	struct dentry *root;
	struct au_branch *br;
	char *perm;

	AuDbg("b%d\n", bindex);

	err = 0;
	root = sb->s_root;
	di_read_lock_parent(root, !AuLock_IR);
	br = au_sbr(sb, bindex);

	switch (idx) {
	case AuBrSysfs_BR:
		path.mnt = au_br_mnt(br);
		path.dentry = au_h_dptr(root, bindex);
		au_seq_path(seq, &path);
		di_read_unlock(root, !AuLock_IR);
		perm = au_optstr_br_perm(br->br_perm);
		if (perm) {
			err = seq_printf(seq, "=%s\n", perm);
			kfree(perm);
			if (err == -1)
				err = -E2BIG;
		} else
			err = -ENOMEM;
		break;
	case AuBrSysfs_BRID:
		err = seq_printf(seq, "%d\n", br->br_id);
		di_read_unlock(root, !AuLock_IR);
		if (err == -1)
			err = -E2BIG;
		break;
	}

	return err;
}