Пример #1
0
		  /* || bindex > au_sbend(dentry->d_sb) */);
	d = au_di(dentry)->di_hdentry[0 + bindex].hd_dentry;
	AuDebugOn(d && (atomic_read(&d->d_count) <= 0));
	return d;
}

aufs_bindex_t au_dbtail(struct dentry *dentry)
{
	aufs_bindex_t bend, bwh;

	bend = au_dbend(dentry);
	if (0 <= bend) {
		bwh = au_dbwh(dentry);
		if (!bwh)
			return bwh;
		if (0 < bwh && bwh < bend)
			return bwh - 1;
	}
	return bend;
}

aufs_bindex_t au_dbtaildir(struct dentry *dentry)
{
	aufs_bindex_t bend, bopq;

	AuDebugOn(dentry->d_inode
		  && dentry->d_inode->i_mode
		  && !S_ISDIR(dentry->d_inode->i_mode));

	bend = au_dbtail(dentry);
	if (0 <= bend) {
		bopq = au_dbdiropq(dentry);
		AuDebugOn(bend < bopq);
		if (0 <= bopq && bopq < bend)
			bend = bopq;
	}
	return bend;
}

#if 0 /* reserved for future use */
aufs_bindex_t au_dbtail_generic(struct dentry *dentry)
{
	struct inode *inode;

	inode = dentry->d_inode;
	if (inode && S_ISDIR(inode->i_mode))
		return au_dbtaildir(dentry);
	else
		return au_dbtail(dentry);
}
Пример #2
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;
}
Пример #3
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;
}
Пример #4
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;
}
Пример #5
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;
}
Пример #6
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;
}
/*
 * test if @dentry dir can be rename source or not.
 * if it can, return 0 and @children is filled.
 * success means,
 * - it is a logically empty dir.
 * - or, it exists on writable branch and has no children including whiteouts
 *       on the lower branch.
 */
static int may_rename_srcdir(struct dentry *dentry, aufs_bindex_t btgt)
{
	int err;
	unsigned int rdhash;
	aufs_bindex_t bstart;

	bstart = au_dbstart(dentry);
	if (bstart != btgt) {
		struct au_nhash whlist;

		SiMustAnyLock(dentry->d_sb);
		rdhash = au_sbi(dentry->d_sb)->si_rdhash;
		if (!rdhash)
			rdhash = au_rdhash_est(au_dir_size(/*file*/NULL,
							   dentry));
		err = au_nhash_alloc(&whlist, rdhash, GFP_NOFS);
		if (unlikely(err))
			goto out;
		err = au_test_empty(dentry, &whlist);
		au_nhash_wh_free(&whlist);
		goto out;
	}

	if (bstart == au_dbtaildir(dentry))
		return 0; /* success */

	err = au_test_empty_lower(dentry);

out:
	if (err == -ENOTEMPTY) {
		AuWarn1("renaming dir who has child(ren) on multiple branches,"
			" is not supported\n");
		err = -EXDEV;
	}
	return err;
}
Пример #8
0
static int set_inode(struct inode *inode, struct dentry *dentry)
{
	int err;
	unsigned int flags;
	umode_t mode;
	aufs_bindex_t bindex, bstart, btail;
	unsigned char isdir;
	struct dentry *h_dentry;
	struct inode *h_inode;
	struct au_iinfo *iinfo;

	IiMustWriteLock(inode);

	err = 0;
	isdir = 0;
	bstart = au_dbstart(dentry);
	h_inode = au_h_dptr(dentry, bstart)->d_inode;
	mode = h_inode->i_mode;
	switch (mode & S_IFMT) {
	case S_IFREG:
		btail = au_dbtail(dentry);
		inode->i_op = &aufs_iop;
		inode->i_fop = &aufs_file_fop;
		inode->i_mapping->a_ops = &aufs_aop;
		break;
	case S_IFDIR:
		isdir = 1;
		btail = au_dbtaildir(dentry);
		inode->i_op = &aufs_dir_iop;
		inode->i_fop = &aufs_dir_fop;
		break;
	case S_IFLNK:
		btail = au_dbtail(dentry);
		inode->i_op = &aufs_symlink_iop;
		break;
	case S_IFBLK:
	case S_IFCHR:
	case S_IFIFO:
	case S_IFSOCK:
		btail = au_dbtail(dentry);
		inode->i_op = &aufs_iop;
		au_init_special_fop(inode, mode, h_inode->i_rdev);
		break;
	default:
		AuIOErr("Unknown file type 0%o\n", mode);
		err = -EIO;
		goto out;
	}

	/* do not set inotify for whiteouted dirs (SHWH mode) */
	flags = au_hi_flags(inode, isdir);
	if (au_opt_test(au_mntflags(dentry->d_sb), SHWH)
	    && au_ftest_hi(flags, HINOTIFY)
	    && dentry->d_name.len > AUFS_WH_PFX_LEN
	    && !memcmp(dentry->d_name.name, AUFS_WH_PFX, AUFS_WH_PFX_LEN))
		au_fclr_hi(flags, HINOTIFY);
	iinfo = au_ii(inode);
	iinfo->ii_bstart = bstart;
	iinfo->ii_bend = btail;
	for (bindex = bstart; bindex <= btail; bindex++) {
		h_dentry = au_h_dptr(dentry, bindex);
		if (h_dentry)
			au_set_h_iptr(inode, bindex,
				      au_igrab(h_dentry->d_inode), flags);
	}
	au_cpup_attr_all(inode, /*force*/1);

 out:
	return err;
}
Пример #9
0
/* todo: remove this */
static int h_d_revalidate(struct dentry *dentry, struct inode *inode,
			  struct nameidata *nd, int do_udba)
{
	int err;
	umode_t mode, h_mode;
	aufs_bindex_t bindex, btail, bstart, ibs, ibe;
	unsigned char plus, unhashed, is_root, h_plus;
	struct inode *h_inode, *h_cached_inode;
	struct dentry *h_dentry;
	struct qstr *name, *h_name;

	err = 0;
	plus = 0;
	mode = 0;
	ibs = -1;
	ibe = -1;
	unhashed = !!d_unhashed(dentry);
	is_root = !!IS_ROOT(dentry);
	name = &dentry->d_name;

	/*
	 * Theoretically, REVAL test should be unnecessary in case of INOTIFY.
	 * But inotify doesn't fire some necessary events,
	 *	IN_ATTRIB for atime/nlink/pageio
	 *	IN_DELETE for NFS dentry
	 * Let's do REVAL test too.
	 */
	if (do_udba && inode) {
		mode = (inode->i_mode & S_IFMT);
		plus = (inode->i_nlink > 0);
		ibs = au_ibstart(inode);
		ibe = au_ibend(inode);
	}

	bstart = au_dbstart(dentry);
	btail = bstart;
	if (inode && S_ISDIR(inode->i_mode))
		btail = au_dbtaildir(dentry);
	for (bindex = bstart; bindex <= btail; bindex++) {
		h_dentry = au_h_dptr(dentry, bindex);
		if (!h_dentry)
			continue;

		AuDbg("b%d, %.*s\n", bindex, AuDLNPair(h_dentry));
		h_name = &h_dentry->d_name;
		if (unlikely(do_udba
			     && !is_root
			     && (unhashed != !!d_unhashed(h_dentry)
				 || name->len != h_name->len
				 || memcmp(name->name, h_name->name, name->len))
			    )) {
			AuDbg("unhash 0x%x 0x%x, %.*s %.*s\n",
				  unhashed, d_unhashed(h_dentry),
				  AuDLNPair(dentry), AuDLNPair(h_dentry));
			goto err;
		}

		err = au_do_h_d_reval(h_dentry, nd, dentry, bindex);
		if (unlikely(err))
			/* do not goto err, to keep the errno */
			break;

		/* todo: plink too? */
		if (!do_udba)
			continue;

		/* UDBA tests */
		h_inode = h_dentry->d_inode;
		if (unlikely(!!inode != !!h_inode))
			goto err;

		h_plus = plus;
		h_mode = mode;
		h_cached_inode = h_inode;
		if (h_inode) {
			h_mode = (h_inode->i_mode & S_IFMT);
			h_plus = (h_inode->i_nlink > 0);
		}
		if (inode && ibs <= bindex && bindex <= ibe)
			h_cached_inode = au_h_iptr(inode, bindex);

		if (unlikely(plus != h_plus
			     || mode != h_mode
			     || h_cached_inode != h_inode))
			goto err;
		continue;

	err:
		err = -EINVAL;
		break;
	}

	return err;
}
Пример #10
0
/*
 * returns the number of lower positive dentries,
 * otherwise an error.
 * can be called at unlinking with @type is zero.
 */
int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type,
		   struct nameidata *nd)
{
	int npositive, err;
	aufs_bindex_t bindex, btail, bdiropq;
	unsigned char isdir;
	struct qstr whname;
	struct au_do_lookup_args args = {
		.flags	= 0,
		.type	= type,
		.nd	= nd
	};
	const struct qstr *name = &dentry->d_name;
	struct dentry *parent;
	struct inode *inode;

	err = au_test_shwh(dentry->d_sb, name);
	if (unlikely(err))
		goto out;

	err = au_wh_name_alloc(&whname, name);
	if (unlikely(err))
		goto out;

	inode = dentry->d_inode;
	isdir = !!(inode && S_ISDIR(inode->i_mode));
	if (!type)
		au_fset_lkup(args.flags, ALLOW_NEG);

	npositive = 0;
	parent = dget_parent(dentry);
	btail = au_dbtaildir(parent);
	for (bindex = bstart; bindex <= btail; bindex++) {
		struct dentry *h_parent, *h_dentry;
		struct inode *h_inode, *h_dir;

		h_dentry = au_h_dptr(dentry, bindex);
		if (h_dentry) {
			if (h_dentry->d_inode)
				npositive++;
			if (type != S_IFDIR)
				break;
			continue;
		}
		h_parent = au_h_dptr(parent, bindex);
		if (!h_parent)
			continue;
		h_dir = h_parent->d_inode;
		if (!h_dir || !S_ISDIR(h_dir->i_mode))
			continue;

		mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT);
		h_dentry = au_do_lookup(h_parent, dentry, bindex, &whname,
					&args);
		mutex_unlock(&h_dir->i_mutex);
		err = PTR_ERR(h_dentry);
		if (IS_ERR(h_dentry))
			goto out_parent;
		au_fclr_lkup(args.flags, ALLOW_NEG);

		if (au_dbwh(dentry) >= 0)
			break;
		if (!h_dentry)
			continue;
		h_inode = h_dentry->d_inode;
		if (!h_inode)
			continue;
		npositive++;
		if (!args.type)
			args.type = h_inode->i_mode & S_IFMT;
		if (args.type != S_IFDIR)
			break;
		else if (isdir) {
			/* the type of lower may be different */
			bdiropq = au_dbdiropq(dentry);
			if (bdiropq >= 0 && bdiropq <= bindex)
				break;
		}
	}

	if (npositive) {
		AuLabel(positive);
		au_update_dbstart(dentry);
	}
	err = npositive;
	if (unlikely(!au_opt_test(au_mntflags(dentry->d_sb), UDBA_NONE)
		     && au_dbstart(dentry) < 0)) {
		err = -EIO;
		AuIOErr("both of real entry and whiteout found, %.*s, err %d\n",
			AuDLNPair(dentry), err);
	}

out_parent:
	dput(parent);
	kfree(whname.name);
out:
	return err;
}

struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent,
			       struct au_branch *br)
{
	struct dentry *dentry;
	int wkq_err;

	if (!au_test_h_perm_sio(parent->d_inode, MAY_EXEC))
		dentry = au_lkup_one(name, parent, br, /*nd*/NULL);
	else {
		struct au_lkup_one_args args = {
			.errp		= &dentry,
			.name		= name,
			.h_parent	= parent,
			.br		= br,
			.nd		= NULL
		};

		wkq_err = au_wkq_wait(au_call_lkup_one, &args);
		if (unlikely(wkq_err))
			dentry = ERR_PTR(wkq_err);
	}

	return dentry;
}

/*
 * lookup @dentry on @bindex which should be negative.
 */
int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex)
{
	int err;
	struct dentry *parent, *h_parent, *h_dentry;

	parent = dget_parent(dentry);
	h_parent = au_h_dptr(parent, bindex);
	h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent,
				   au_sbr(dentry->d_sb, bindex));
	err = PTR_ERR(h_dentry);
	if (IS_ERR(h_dentry))
		goto out;
	if (unlikely(h_dentry->d_inode)) {
		err = -EIO;
		AuIOErr("%.*s should be negative on b%d.\n",
			AuDLNPair(h_dentry), bindex);
		dput(h_dentry);
		goto out;
	}

	err = 0;
	if (bindex < au_dbstart(dentry))
		au_set_dbstart(dentry, bindex);
	if (au_dbend(dentry) < bindex)
		au_set_dbend(dentry, bindex);
	au_set_h_dptr(dentry, bindex, h_dentry);

out:
	dput(parent);
	return err;
}
Пример #11
0
/* most free space */
static void au_mfs(struct dentry *dentry, struct dentry *parent)
{
	struct super_block *sb;
	struct au_branch *br;
	struct au_wbr_mfs *mfs;
	struct dentry *h_parent;
	aufs_bindex_t bindex, bend;
	int err;
	unsigned long long b, bavail;
	struct path h_path;
	/* reduce the stack usage */
	struct kstatfs *st;

	st = kmalloc(sizeof(*st), GFP_NOFS);
	if (unlikely(!st)) {
		AuWarn1("failed updating mfs(%d), ignored\n", -ENOMEM);
		return;
	}

	bavail = 0;
	sb = dentry->d_sb;
	mfs = &au_sbi(sb)->si_wbr_mfs;
	MtxMustLock(&mfs->mfs_lock);
	mfs->mfs_bindex = -EROFS;
	mfs->mfsrr_bytes = 0;
	if (!parent) {
		bindex = 0;
		bend = au_sbend(sb);
	} else {
		bindex = au_dbstart(parent);
		bend = au_dbtaildir(parent);
	}

	for (; bindex <= bend; bindex++) {
		if (parent) {
			h_parent = au_h_dptr(parent, bindex);
			if (!h_parent || !h_parent->d_inode)
				continue;
		}
		br = au_sbr(sb, bindex);
		if (au_br_rdonly(br))
			continue;

		/* sb->s_root for NFS is unreliable */
		h_path.mnt = au_br_mnt(br);
		h_path.dentry = h_path.mnt->mnt_root;
		err = vfs_statfs(&h_path, st);
		if (unlikely(err)) {
			AuWarn1("failed statfs, b%d, %d\n", bindex, err);
			continue;
		}

		/* when the available size is equal, select the lower one */
		BUILD_BUG_ON(sizeof(b) < sizeof(st->f_bavail)
			     || sizeof(b) < sizeof(st->f_bsize));
		b = st->f_bavail * st->f_bsize;
		br->br_wbr->wbr_bytes = b;
		if (b >= bavail) {
			bavail = b;
			mfs->mfs_bindex = bindex;
			mfs->mfs_jiffy = jiffies;
		}
	}

	mfs->mfsrr_bytes = bavail;
	AuDbg("b%d\n", mfs->mfs_bindex);
	kfree(st);
}
Пример #12
0
/* todo: remove this */
static int h_d_revalidate(struct dentry *dentry, struct inode *inode,
			  unsigned int flags, int do_udba)
{
	int err;
	umode_t mode, h_mode;
	aufs_bindex_t bindex, btail, bstart, ibs, ibe;
	unsigned char plus, unhashed, is_root, h_plus, h_nfs, tmpfile;
	struct inode *h_inode, *h_cached_inode;
	struct dentry *h_dentry;
	struct qstr *name, *h_name;

	err = 0;
	plus = 0;
	mode = 0;
	ibs = -1;
	ibe = -1;
	unhashed = !!d_unhashed(dentry);
	is_root = !!IS_ROOT(dentry);
	name = &dentry->d_name;
	tmpfile = au_di(dentry)->di_tmpfile;

	/*
	 * Theoretically, REVAL test should be unnecessary in case of
	 * {FS,I}NOTIFY.
	 * But {fs,i}notify doesn't fire some necessary events,
	 *	IN_ATTRIB for atime/nlink/pageio
	 * Let's do REVAL test too.
	 */
	if (do_udba && inode) {
		mode = (inode->i_mode & S_IFMT);
		plus = (inode->i_nlink > 0);
		ibs = au_ibstart(inode);
		ibe = au_ibend(inode);
	}

	bstart = au_dbstart(dentry);
	btail = bstart;
	if (inode && S_ISDIR(inode->i_mode))
		btail = au_dbtaildir(dentry);
	for (bindex = bstart; bindex <= btail; bindex++) {
		h_dentry = au_h_dptr(dentry, bindex);
		if (!h_dentry)
			continue;

		AuDbg("b%d, %pd\n", bindex, h_dentry);
		h_nfs = !!au_test_nfs(h_dentry->d_sb);
		spin_lock(&h_dentry->d_lock);
		h_name = &h_dentry->d_name;
		if (unlikely(do_udba
			     && !is_root
			     && ((!h_nfs
				  && (unhashed != !!d_unhashed(h_dentry)
				      || (!tmpfile
					  && !au_qstreq(name, h_name))
					  ))
				 || (h_nfs
				     && !(flags & LOOKUP_OPEN)
				     && (h_dentry->d_flags
					 & DCACHE_NFSFS_RENAMED)))
			    )) {
			int h_unhashed;

			h_unhashed = d_unhashed(h_dentry);
			spin_unlock(&h_dentry->d_lock);
			AuDbg("unhash 0x%x 0x%x, %pd %pd\n",
			      unhashed, h_unhashed, dentry, h_dentry);
			goto err;
		}
		spin_unlock(&h_dentry->d_lock);

		err = au_do_h_d_reval(h_dentry, flags, dentry, bindex);
		if (unlikely(err))
			/* do not goto err, to keep the errno */
			break;

		/* todo: plink too? */
		if (!do_udba)
			continue;

		/* UDBA tests */
		if (unlikely(!!inode != d_is_positive(h_dentry)))
			goto err;

		h_inode = NULL;
		if (d_is_positive(h_dentry))
			h_inode = d_inode(h_dentry);
		h_plus = plus;
		h_mode = mode;
		h_cached_inode = h_inode;
		if (h_inode) {
			h_mode = (h_inode->i_mode & S_IFMT);
			h_plus = (h_inode->i_nlink > 0);
		}
		if (inode && ibs <= bindex && bindex <= ibe)
			h_cached_inode = au_h_iptr(inode, bindex);

		if (!h_nfs) {
			if (unlikely(plus != h_plus && !tmpfile))
				goto err;
		} else {
			if (unlikely(!(h_dentry->d_flags & DCACHE_NFSFS_RENAMED)
				     && !is_root
				     && !IS_ROOT(h_dentry)
				     && unhashed != d_unhashed(h_dentry)))
				goto err;
		}
		if (unlikely(mode != h_mode
			     || h_cached_inode != h_inode))
			goto err;
		continue;

err:
		err = -EINVAL;
		break;
	}

	AuTraceErr(err);
	return err;
}
Пример #13
0
/*
 * returns the number of lower positive dentries,
 * otherwise an error.
 * can be called at unlinking with @type is zero.
 */
int au_lkup_dentry(struct dentry *dentry, aufs_bindex_t bstart, mode_t type)
{
	int npositive, err;
	aufs_bindex_t bindex, btail, bdiropq;
	unsigned char isdir, dirperm1;
	struct qstr whname;
	struct au_do_lookup_args args = {
		.flags		= 0,
		.type		= type
	};
	const struct qstr *name = &dentry->d_name;
	struct dentry *parent;
	struct super_block *sb;

	sb = dentry->d_sb;
	err = au_test_shwh(sb, name);
	if (unlikely(err))
		goto out;

	err = au_wh_name_alloc(&whname, name);
	if (unlikely(err))
		goto out;

	isdir = !!d_is_dir(dentry);
	if (!type)
		au_fset_lkup(args.flags, ALLOW_NEG);
	dirperm1 = !!au_opt_test(au_mntflags(sb), DIRPERM1);

	npositive = 0;
	parent = dget_parent(dentry);
	btail = au_dbtaildir(parent);
	for (bindex = bstart; bindex <= btail; bindex++) {
		struct dentry *h_parent, *h_dentry;
		struct inode *h_inode, *h_dir;

		h_dentry = au_h_dptr(dentry, bindex);
		if (h_dentry) {
			if (d_is_positive(h_dentry))
				npositive++;
			if (type != S_IFDIR)
				break;
			continue;
		}
		h_parent = au_h_dptr(parent, bindex);
		if (!h_parent || !d_is_dir(h_parent))
			continue;

		h_dir = d_inode(h_parent);
		mutex_lock_nested(&h_dir->i_mutex, AuLsc_I_PARENT);
		h_dentry = au_do_lookup(h_parent, dentry, bindex, &whname,
					&args);
		mutex_unlock(&h_dir->i_mutex);
		err = PTR_ERR(h_dentry);
		if (IS_ERR(h_dentry))
			goto out_parent;
		if (h_dentry)
			au_fclr_lkup(args.flags, ALLOW_NEG);
		if (dirperm1)
			au_fset_lkup(args.flags, IGNORE_PERM);

		if (au_dbwh(dentry) >= 0)
			break;
		if (!h_dentry)
			continue;
		if (d_is_negative(h_dentry))
			continue;
		h_inode = d_inode(h_dentry);
		npositive++;
		if (!args.type)
			args.type = h_inode->i_mode & S_IFMT;
		if (args.type != S_IFDIR)
			break;
		else if (isdir) {
			/* the type of lower may be different */
			bdiropq = au_dbdiropq(dentry);
			if (bdiropq >= 0 && bdiropq <= bindex)
				break;
		}
	}

	if (npositive) {
		AuLabel(positive);
		au_update_dbstart(dentry);
	}
	err = npositive;
	if (unlikely(!au_opt_test(au_mntflags(sb), UDBA_NONE)
		     && au_dbstart(dentry) < 0)) {
		err = -EIO;
		AuIOErr("both of real entry and whiteout found, %pd, err %d\n",
			dentry, err);
	}

out_parent:
	dput(parent);
	kfree(whname.name);
out:
	return err;
}

struct dentry *au_sio_lkup_one(struct qstr *name, struct dentry *parent)
{
	struct dentry *dentry;
	int wkq_err;

	if (!au_test_h_perm_sio(d_inode(parent), MAY_EXEC))
		dentry = vfsub_lkup_one(name, parent);
	else {
		struct vfsub_lkup_one_args args = {
			.errp	= &dentry,
			.name	= name,
			.parent	= parent
		};

		wkq_err = au_wkq_wait(vfsub_call_lkup_one, &args);
		if (unlikely(wkq_err))
			dentry = ERR_PTR(wkq_err);
	}

	return dentry;
}

/*
 * lookup @dentry on @bindex which should be negative.
 */
int au_lkup_neg(struct dentry *dentry, aufs_bindex_t bindex, int wh)
{
	int err;
	struct dentry *parent, *h_parent, *h_dentry;
	struct au_branch *br;

	parent = dget_parent(dentry);
	h_parent = au_h_dptr(parent, bindex);
	br = au_sbr(dentry->d_sb, bindex);
	if (wh)
		h_dentry = au_whtmp_lkup(h_parent, br, &dentry->d_name);
	else
		h_dentry = au_sio_lkup_one(&dentry->d_name, h_parent);
	err = PTR_ERR(h_dentry);
	if (IS_ERR(h_dentry))
		goto out;
	if (unlikely(d_is_positive(h_dentry))) {
		err = -EIO;
		AuIOErr("%pd should be negative on b%d.\n", h_dentry, bindex);
		dput(h_dentry);
		goto out;
	}

	err = 0;
	if (bindex < au_dbstart(dentry))
		au_set_dbstart(dentry, bindex);
	if (au_dbend(dentry) < bindex)
		au_set_dbend(dentry, bindex);
	au_set_h_dptr(dentry, bindex, h_dentry);

out:
	dput(parent);
	return err;
}
Пример #14
0
static struct dentry *
aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len,
		  int fh_type)
{
	struct dentry *dentry;
	__u32 *fh = fid->raw;
	ino_t ino, dir_ino;
	aufs_bindex_t bindex;
	struct au_nfsd_si_lock nsi_lock = {
		.force_lock	= 0
	};

	dentry = ERR_PTR(-ESTALE);
	/* it should never happen, but the file handle is unreliable */
	if (unlikely(fh_len < Fh_tail))
		goto out;
	nsi_lock.sigen = fh[Fh_sigen];
	nsi_lock.br_id = fh[Fh_br_id];

	/* branch id may be wrapped around */
	bindex = si_nfsd_read_lock(sb, &nsi_lock);
	if (unlikely(bindex < 0))
		goto out;
	nsi_lock.force_lock = 1;

	/* is this inode still cached? */
	ino = decode_ino(fh + Fh_ino);
	/* it should never happen */
	if (unlikely(ino == AUFS_ROOT_INO))
		goto out;

	dir_ino = decode_ino(fh + Fh_dir_ino);
	dentry = decode_by_ino(sb, ino, dir_ino);
	if (IS_ERR(dentry))
		goto out_unlock;
	if (dentry)
		goto accept;

	/* is the parent dir cached? */
	dentry = decode_by_dir_ino(sb, ino, dir_ino, &nsi_lock);
	if (IS_ERR(dentry))
		goto out_unlock;
	if (dentry)
		goto accept;

	/* lookup path */
	dentry = decode_by_path(sb, bindex, ino, fh, fh_len, &nsi_lock);
	if (IS_ERR(dentry))
		goto out_unlock;
	if (unlikely(!dentry))
		/* todo?: make it ESTALE */
		goto out_unlock;

 accept:
	if (dentry->d_inode->i_generation == fh[Fh_igen])
		goto out_unlock; /* success */

	dput(dentry);
	dentry = ERR_PTR(-ESTALE);
 out_unlock:
	si_read_unlock(sb);
 out:
	AuTraceErrPtr(dentry);
	return dentry;
}

#if 0 /* reserved for future use */
/* support subtreecheck option */
static struct dentry *aufs_fh_to_parent(struct super_block *sb, struct fid *fid,
					int fh_len, int fh_type)
{
	struct dentry *parent;
	__u32 *fh = fid->raw;
	ino_t dir_ino;

	dir_ino = decode_ino(fh + Fh_dir_ino);
	parent = decode_by_ino(sb, dir_ino, 0);
	if (IS_ERR(parent))
		goto out;
	if (!parent)
		parent = decode_by_path(sb, au_br_index(sb, fh[Fh_br_id]),
					dir_ino, fh, fh_len);

 out:
	AuTraceErrPtr(parent);
	return parent;
}
#endif

/* ---------------------------------------------------------------------- */

static int aufs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len,
			  int connectable)
{
	int err;
	aufs_bindex_t bindex, bend;
	struct super_block *sb, *h_sb;
	struct inode *inode;
	struct dentry *parent, *h_parent;
	struct au_branch *br;

	AuDebugOn(au_test_anon(dentry));

	parent = NULL;
	err = -ENOSPC;
	if (unlikely(*max_len <= Fh_tail)) {
		AuWarn1("NFSv2 client (max_len %d)?\n", *max_len);
		goto out;
	}

	err = FILEID_ROOT;
	if (IS_ROOT(dentry)) {
		AuDebugOn(dentry->d_inode->i_ino != AUFS_ROOT_INO);
		goto out;
	}

	err = -EIO;
	h_parent = NULL;
	sb = dentry->d_sb;
	aufs_read_lock(dentry, AuLock_FLUSH | AuLock_IR);
	parent = dget_parent(dentry);
	di_read_lock_parent(parent, !AuLock_IR);
	inode = dentry->d_inode;
	AuDebugOn(!inode);
#ifdef CONFIG_AUFS_DEBUG
	if (unlikely(!au_opt_test(au_mntflags(sb), XINO)))
		AuWarn1("NFS-exporting requires xino\n");
#endif

	bend = au_dbtaildir(parent);
	for (bindex = au_dbstart(parent); bindex <= bend; bindex++) {
		h_parent = au_h_dptr(parent, bindex);
		if (h_parent) {
			dget(h_parent);
			break;
		}
	}
	if (unlikely(!h_parent))
		goto out_unlock;

	err = -EPERM;
	br = au_sbr(sb, bindex);
	h_sb = br->br_mnt->mnt_sb;
	if (unlikely(!h_sb->s_export_op)) {
		AuErr1("%s branch is not exportable\n", au_sbtype(h_sb));
		goto out_dput;
	}

	fh[Fh_br_id] = br->br_id;
	fh[Fh_sigen] = au_sigen(sb);
	encode_ino(fh + Fh_ino, inode->i_ino);
	encode_ino(fh + Fh_dir_ino, parent->d_inode->i_ino);
	fh[Fh_igen] = inode->i_generation;

	*max_len -= Fh_tail;
	fh[Fh_h_type] = exportfs_encode_fh(h_parent, (void *)(fh + Fh_tail),
					   max_len,
					   /*connectable or subtreecheck*/0);
	err = fh[Fh_h_type];
	*max_len += Fh_tail;
	/* todo: macros? */
	if (err != 255)
		err = 99;
	else
		AuWarn1("%s encode_fh failed\n", au_sbtype(h_sb));

 out_dput:
	dput(h_parent);
 out_unlock:
	di_read_unlock(parent, !AuLock_IR);
	dput(parent);
	aufs_read_unlock(dentry, AuLock_IR);
 out:
	if (unlikely(err < 0))
		err = 255;
	return err;
}
Пример #15
0
static struct dentry *
aufs_decode_fh(struct super_block *sb, __u32 *fh, int fh_len, int fh_type,
	       int (*acceptable)(void *context, struct dentry *de),
	       void *context)
{
	struct dentry *dentry;
	ino_t ino, dir_ino;
	aufs_bindex_t bindex;
	struct au_nfsd_si_lock nsi_lock = {
		.sigen		= fh[Fh_sigen],
		.br_id		= fh[Fh_br_id],
		.force_lock	= 0
	};

	LKTRTrace("%d, fh{br_id %u, sigen %u, i%u, diri%u, g%u}\n",
		  fh_type, fh[Fh_br_id], fh[Fh_sigen], fh[Fh_ino],
		  fh[Fh_dir_ino], fh[Fh_igen]);
	AuDebugOn(fh_len < Fh_tail);

	dentry = ERR_PTR(-ESTALE);
	/* branch id may be wrapped around */
	bindex = si_nfsd_read_lock(sb, &nsi_lock);
	if (unlikely(bindex < 0))
		goto out;
	nsi_lock.force_lock = 1;

	/* is this inode still cached? */
	ino = decode_ino(fh + Fh_ino);
	AuDebugOn(ino == AUFS_ROOT_INO);
	dir_ino = decode_ino(fh + Fh_dir_ino);
	dentry = decode_by_ino(sb, ino, dir_ino);
	if (IS_ERR(dentry))
		goto out_unlock;
	if (dentry)
		goto accept;

	/* is the parent dir cached? */
	dentry = decode_by_dir_ino(sb, ino, dir_ino, &nsi_lock);
	if (IS_ERR(dentry))
		goto out_unlock;
	if (dentry)
		goto accept;

	/* lookup path */
	dentry = decode_by_path(sb, bindex, ino, fh, fh_len, &nsi_lock);
	if (IS_ERR(dentry))
		goto out_unlock;
	if (unlikely(!dentry))
		goto out_unlock;

 accept:
	LKTRLabel(accept);
	if (dentry->d_inode->i_generation == fh[Fh_igen]
	    && acceptable(context, dentry))
		goto out_unlock; /* success */

	LKTRLabel(stale);
	dput(dentry);
	dentry = ERR_PTR(-ESTALE);
 out_unlock:
	LKTRLabel(out_unlock);
	si_read_unlock(sb);
 out:
	LKTRLabel(out);
	if (0 && IS_ERR(dentry))
		dentry = ERR_PTR(-ESTALE);
	AuTraceErrPtr(dentry);
	return dentry;
}

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
static struct dentry *
aufs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len,
		  int fh_type)
{
	return aufs_decode_fh(sb, fid->raw, fh_len, fh_type, h_acceptable,
			      /*context*/NULL);
}
#endif /* KERNEL_VERSION */

/* ---------------------------------------------------------------------- */

static int aufs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len,
			  int connectable)
{
	int err;
	aufs_bindex_t bindex, bend;
	struct super_block *sb, *h_sb;
	struct inode *inode;
	struct dentry *parent, *h_parent;
	struct au_branch *br;

	LKTRTrace("%.*s, max %d, conn %d\n",
		  AuDLNPair(dentry), *max_len, connectable);
	AuDebugOn(au_test_anon(dentry));

	parent = NULL;
	err = -ENOSPC;
	if (unlikely(*max_len <= Fh_tail)) {
		AuWarn1("NFSv2 client (max_len %d)?\n", *max_len);
		goto out;
	}

	err = 0; //FILEID_ROOT;
	if (IS_ROOT(dentry)) {
		AuDebugOn(dentry->d_inode->i_ino != AUFS_ROOT_INO);
		goto out;
	}

	err = -EIO;
	h_parent = NULL;
	sb = dentry->d_sb;
	aufs_read_lock(dentry, AuLock_FLUSH | AuLock_IR);
	parent = dget_parent(dentry);
	di_read_lock_parent(parent, !AuLock_IR);
	inode = dentry->d_inode;
	AuDebugOn(!inode);
#ifdef CONFIG_AUFS_DEBUG
	{
		unsigned int mnt_flags = au_mntflags(sb);

		if (unlikely(!au_opt_test_xino(mnt_flags)))
			AuWarn1("NFS-exporting requires xino\n");
		if (unlikely(0 && !au_opt_test(mnt_flags, UDBA_INOTIFY)))
			AuWarn1("udba=inotify is recommended "
				"for NFS-exporting\n");
	}
#endif

	bend = au_dbtaildir(parent);
	for (bindex = au_dbstart(parent); bindex <= bend; bindex++) {
		h_parent = au_h_dptr(parent, bindex);
		if (h_parent) {
			dget(h_parent);
			break;
		}
	}
	if (unlikely(!h_parent))
		goto out_unlock;
	LKTRTrace("b%d\n", bindex);

	err = -EPERM;
	br = au_sbr(sb, bindex);
	h_sb = br->br_mnt->mnt_sb;
	if (unlikely(!h_sb->s_export_op)) {
		AuErr1("%s branch is not exportable\n", au_sbtype(h_sb));
		goto out_dput;
	}

	fh[Fh_br_id] = br->br_id;
	fh[Fh_sigen] = au_sigen(sb);
	encode_ino(fh + Fh_ino, inode->i_ino);
	encode_ino(fh + Fh_dir_ino, parent->d_inode->i_ino);
	fh[Fh_igen] = inode->i_generation;

#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
	/* it should be set at exporting time */
	if (unlikely(!h_sb->s_export_op->find_exported_dentry)) {
		AuWarn("set default find_exported_dentry for %s\n",
		       au_sbtype(h_sb));
		h_sb->s_export_op->find_exported_dentry = find_exported_dentry;
	}
#endif

	*max_len -= Fh_tail;
	fh[Fh_h_type] = au_call_encode_fh(h_parent, fh + Fh_tail, max_len,
					  /*connectable or subtreecheck*/0);
	err = fh[Fh_h_type];
	*max_len += Fh_tail;
	/* todo: macros? */
	if (err != 255)
		err = 99;
	else
		AuWarn1("%s encode_fh failed\n", au_sbtype(h_sb));

 out_dput:
	dput(h_parent);
 out_unlock:
	di_read_unlock(parent, !AuLock_IR);
	dput(parent);
	aufs_read_unlock(dentry, AuLock_IR);
 out:
	AuTraceErr(err);
	if (unlikely(err < 0))
		err = 255;
	return err;
}