Пример #1
0
static int simple_reval_dpath(struct dentry *dentry, unsigned int sigen)
{
	int err;
	struct dentry *parent;
	struct inode *inode;

	inode = dentry->d_inode;
	if (au_digen(dentry) == sigen && au_iigen(inode) == sigen)
		return 0;

	parent = dget_parent(dentry);
	di_read_lock_parent(parent, AuLock_IR);
	AuDebugOn(au_digen(parent) != sigen
		  || au_iigen(parent->d_inode) != sigen);
	au_dbg_verify_gen(parent, sigen);

	/* returns a number of positive dentries */
	err = au_refresh_hdentry(dentry, inode->i_mode & S_IFMT);
	if (err >= 0)
		err = au_refresh_hinode(inode, dentry);

	di_read_unlock(parent, AuLock_IR);
	dput(parent);
	return err;
}
Пример #2
0
/*
 * if valid returns 1, otherwise 0.
 */
static int aufs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
{
	int valid, err;
	unsigned int sigen;
	unsigned char do_udba;
	struct super_block *sb;
	struct inode *inode;

	err = -EINVAL;
	sb = dentry->d_sb;
	inode = dentry->d_inode;
	aufs_read_lock(dentry, AuLock_FLUSH | AuLock_DW);
	sigen = au_sigen(sb);
	if (au_digen(dentry) != sigen) {
		AuDebugOn(IS_ROOT(dentry));
		if (inode)
			err = au_reval_dpath(dentry, sigen);
		if (unlikely(err))
			goto out_dgrade;
		AuDebugOn(au_digen(dentry) != sigen);
	}
	if (inode && au_iigen(inode) != sigen) {
		AuDebugOn(IS_ROOT(dentry));
		err = au_refresh_hinode(inode, dentry);
		if (unlikely(err))
			goto out_dgrade;
		AuDebugOn(au_iigen(inode) != sigen);
	}
	di_downgrade_lock(dentry, AuLock_IR);

	AuDebugOn(au_digen(dentry) != sigen);
	AuDebugOn(inode && au_iigen(inode) != sigen);
	err = -EINVAL;
	do_udba = !au_opt_test(au_mntflags(sb), UDBA_NONE);
	if (do_udba && inode) {
		aufs_bindex_t bstart = au_ibstart(inode);

		if (bstart >= 0
		    && au_test_higen(inode, au_h_iptr(inode, bstart)))
			goto out;
	}

	err = h_d_revalidate(dentry, inode, nd, do_udba);
	if (unlikely(!err && do_udba && au_dbstart(dentry) < 0))
		/* both of real entry and whiteout found */
		err = -EIO;
	goto out;

 out_dgrade:
	di_downgrade_lock(dentry, AuLock_IR);
 out:
	aufs_read_unlock(dentry, AuLock_IR);
	AuTraceErr(err);
	valid = !err;
	if (!valid)
		AuDbg("%.*s invalid\n", AuDLNPair(dentry));
	return valid;
}
Пример #3
0
int au_reval_dpath(struct dentry *dentry, unsigned int sigen)
{
	int err;
	struct dentry *d, *parent;
	struct inode *inode;

	if (!au_ftest_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIRS))
		return simple_reval_dpath(dentry, sigen);

	/* slow loop, keep it simple and stupid */
	/* cf: au_cpup_dirs() */
	err = 0;
	parent = NULL;
	while (au_digen(dentry) != sigen
	       || au_iigen(dentry->d_inode) != sigen) {
		d = dentry;
		while (1) {
			dput(parent);
			parent = dget_parent(d);
			if (au_digen(parent) == sigen
			    && au_iigen(parent->d_inode) == sigen)
				break;
			d = parent;
		}

		inode = d->d_inode;
		if (d != dentry)
			di_write_lock_child(d);

		/* someone might update our dentry while we were sleeping */
		if (au_digen(d) != sigen || au_iigen(d->d_inode) != sigen) {
			di_read_lock_parent(parent, AuLock_IR);
			/* returns a number of positive dentries */
			err = au_refresh_hdentry(d, inode->i_mode & S_IFMT);
			if (err >= 0)
				err = au_refresh_hinode(inode, d);
			di_read_unlock(parent, AuLock_IR);
		}

		if (d != dentry)
			di_write_unlock(d);
		dput(parent);
		if (unlikely(err))
			break;
	}

	return err;
}
Пример #4
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;
}
Пример #5
0
/*
 * ->setattr() and ->getattr() are called in various cases.
 * chmod, stat: dentry is revalidated.
 * fchmod, fstat: file and dentry are not revalidated, additionally they may be
 *		  unhashed.
 * for ->setattr(), ia->ia_file is passed from ftruncate only.
 */
static int au_reval_for_attr(struct dentry *dentry, unsigned int sigen)
{
	int err;
	struct inode *inode;
	struct dentry *parent;

	err = 0;
	inode = dentry->d_inode;
	if (au_digen(dentry) != sigen || au_iigen(inode) != sigen) {
		parent = dget_parent(dentry);
		di_read_lock_parent(parent, AuLock_IR);
		/* returns a number of positive dentries */
		err = au_refresh_hdentry(dentry, inode->i_mode & S_IFMT);
		if (err >= 0)
			err = au_refresh_hinode(inode, dentry);
		di_read_unlock(parent, AuLock_IR);
		dput(parent);
	}

	AuTraceErr(err);
	return err;
}
Пример #6
0
/* successful returns with iinfo write_locked */
static int reval_inode(struct inode *inode, struct dentry *dentry, int *matched)
{
	int err;
	aufs_bindex_t bindex, bend;
	struct inode *h_inode, *h_dinode;

	*matched = 0;

	/*
	 * 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 = 0;
	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) {
			*matched = 1;
			err = 0;
			if (au_iigen(inode) != au_digen(dentry))
				err = au_refresh_hinode(inode, dentry);
			break;
		}
	}

	if (unlikely(err))
		ii_write_unlock(inode);
 out:
	return err;
}
Пример #7
0
/*
 * By adding a dirty branch, a cached dentry may be affected in various ways.
 *
 * a dirty branch is added
 * - on the top of layers
 * - in the middle of layers
 * - to the bottom of layers
 *
 * on the added branch there exists
 * - a whiteout
 * - a diropq
 * - a same named entry
 *   + exist
 *     * negative --> positive
 *     * positive --> positive
 *	 - type is unchanged
 *	 - type is changed
 *   + doesn't exist
 *     * negative --> negative
 *     * positive --> negative (rejected by au_br_del() for non-dir case)
 * - none
 */
static int au_refresh_by_dinfo(struct dentry *dentry, struct au_dinfo *dinfo,
			       struct au_dinfo *tmp)
{
	int err;
	aufs_bindex_t bindex, bend;
	struct {
		struct dentry *dentry;
		struct inode *inode;
		mode_t mode;
	} orig_h, tmp_h;
	struct au_hdentry *hd;
	struct inode *inode, *h_inode;
	struct dentry *h_dentry;

	err = 0;
	AuDebugOn(dinfo->di_bstart < 0);
	orig_h.dentry = dinfo->di_hdentry[dinfo->di_bstart].hd_dentry;
	orig_h.inode = orig_h.dentry->d_inode;
	orig_h.mode = 0;
	if (orig_h.inode)
		orig_h.mode = orig_h.inode->i_mode & S_IFMT;
	memset(&tmp_h, 0, sizeof(tmp_h));
	if (tmp->di_bstart >= 0) {
		tmp_h.dentry = tmp->di_hdentry[tmp->di_bstart].hd_dentry;
		tmp_h.inode = tmp_h.dentry->d_inode;
		if (tmp_h.inode)
			tmp_h.mode = tmp_h.inode->i_mode & S_IFMT;
	}

	inode = dentry->d_inode;
	if (!orig_h.inode) {
		AuDbg("nagative originally\n");
		if (inode) {
			au_hide(dentry);
			goto out;
		}
		AuDebugOn(inode);
		AuDebugOn(dinfo->di_bstart != dinfo->di_bend);
		AuDebugOn(dinfo->di_bdiropq != -1);

		if (!tmp_h.inode) {
			AuDbg("negative --> negative\n");
			/* should have only one negative lower */
			if (tmp->di_bstart >= 0
			    && tmp->di_bstart < dinfo->di_bstart) {
				AuDebugOn(tmp->di_bstart != tmp->di_bend);
				AuDebugOn(dinfo->di_bstart != dinfo->di_bend);
				au_set_h_dptr(dentry, dinfo->di_bstart, NULL);
				au_di_cp(dinfo, tmp);
				hd = tmp->di_hdentry + tmp->di_bstart;
				au_set_h_dptr(dentry, tmp->di_bstart,
					      dget(hd->hd_dentry));
			}
			au_dbg_verify_dinode(dentry);
		} else {
			AuDbg("negative --> positive\n");
			/*
			 * similar to the behaviour of creating with bypassing
			 * aufs.
			 * unhash it in order to force an error in the
			 * succeeding create operation.
			 * we should not set S_DEAD here.
			 */
			d_drop(dentry);
			/* au_di_swap(tmp, dinfo); */
			au_dbg_verify_dinode(dentry);
		}
	} else {
		AuDbg("positive originally\n");
		/* inode may be NULL */
		AuDebugOn(inode && (inode->i_mode & S_IFMT) != orig_h.mode);
		if (!tmp_h.inode) {
			AuDbg("positive --> negative\n");
			/* or bypassing aufs */
			au_hide(dentry);
			if (tmp->di_bwh >= 0 && tmp->di_bwh <= dinfo->di_bstart)
				dinfo->di_bwh = tmp->di_bwh;
			if (inode)
				err = au_refresh_hinode_self(inode);
			au_dbg_verify_dinode(dentry);
		} else if (orig_h.mode == tmp_h.mode) {
			AuDbg("positive --> positive, same type\n");
			if (!S_ISDIR(orig_h.mode)
			    && dinfo->di_bstart > tmp->di_bstart) {
				/*
				 * similar to the behaviour of removing and
				 * creating.
				 */
				au_hide(dentry);
				if (inode)
					err = au_refresh_hinode_self(inode);
				au_dbg_verify_dinode(dentry);
			} else {
				/* fill empty slots */
				if (dinfo->di_bstart > tmp->di_bstart)
					dinfo->di_bstart = tmp->di_bstart;
				if (dinfo->di_bend < tmp->di_bend)
					dinfo->di_bend = tmp->di_bend;
				dinfo->di_bwh = tmp->di_bwh;
				dinfo->di_bdiropq = tmp->di_bdiropq;
				hd = tmp->di_hdentry;
				bend = dinfo->di_bend;
				for (bindex = tmp->di_bstart; bindex <= bend;
				     bindex++) {
					if (au_h_dptr(dentry, bindex))
						continue;
					h_dentry = hd[bindex].hd_dentry;
					if (!h_dentry)
						continue;
					h_inode = h_dentry->d_inode;
					AuDebugOn(!h_inode);
					AuDebugOn(orig_h.mode
						  != (h_inode->i_mode
						      & S_IFMT));
					au_set_h_dptr(dentry, bindex,
						      dget(h_dentry));
				}
				err = au_refresh_hinode(inode, dentry);
				au_dbg_verify_dinode(dentry);
			}
		} else {
			AuDbg("positive --> positive, different type\n");
			/* similar to the behaviour of removing and creating */
			au_hide(dentry);
			if (inode)
				err = au_refresh_hinode_self(inode);
			au_dbg_verify_dinode(dentry);
		}
	}

out:
	return err;
}