Ejemplo n.º 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;
}
Ejemplo n.º 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;
}
Ejemplo n.º 3
0
/* common function to regular file and dir */
int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file),
			  int wlock)
{
	int err;
	unsigned int sigen, figen;
	aufs_bindex_t bstart;
	unsigned char pseudo_link;
	struct dentry *dentry;
	struct inode *inode;

	err = 0;
	dentry = file->f_dentry;
	inode = dentry->d_inode;
	AuDebugOn(au_special_file(inode->i_mode));
	sigen = au_sigen(dentry->d_sb);
	fi_write_lock(file);
	figen = au_figen(file);
	di_write_lock_child(dentry);
	bstart = au_dbstart(dentry);
	pseudo_link = (bstart != au_ibstart(inode));
	if (sigen == figen && !pseudo_link && au_fbstart(file) == bstart) {
		if (!wlock) {
			di_downgrade_lock(dentry, AuLock_IR);
			fi_downgrade_lock(file);
		}
		goto out; /* success */
	}

	AuDbg("sigen %d, figen %d\n", sigen, figen);
	if (sigen != au_digen(dentry)
	    || sigen != au_iigen(inode)) {
		err = au_reval_dpath(dentry, sigen);
		if (unlikely(err < 0))
			goto out;
		AuDebugOn(au_digen(dentry) != sigen
			  || au_iigen(inode) != sigen);
	}

	err = refresh_file(file, reopen);
	if (!err) {
		if (!wlock) {
			di_downgrade_lock(dentry, AuLock_IR);
			fi_downgrade_lock(file);
		}
	} else {
		di_write_unlock(dentry);
		fi_write_unlock(file);
	}

out:
	return err;
}
Ejemplo n.º 4
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;
}
Ejemplo n.º 5
0
int au_finfo_init(struct file *file, struct au_fidir *fidir)
{
	int err;
	unsigned long ul;
	struct au_finfo *finfo;
	struct dentry *dentry;

	err = -ENOMEM;
	dentry = file->f_dentry;
	finfo = au_cache_alloc_finfo();
	if (unlikely(!finfo))
		goto out;

	err = 0;
	au_rw_write_lock(&finfo->fi_rwsem);
	finfo->fi_btop = -1;
	finfo->fi_hdir = fidir;
	atomic_set(&finfo->fi_generation, au_digen(dentry));
	/* smp_mb(); */ /* atomic_set */

	/* cf. au_store_oflag() */
	ul = (unsigned long)file->private_data;
	file->f_mode |= (ul & FMODE_EXEC);
	file->private_data = finfo;

out:
	return err;
}
Ejemplo n.º 6
0
int au_finfo_init(struct file *file, struct au_fidir *fidir)
{
	int err, lc_idx;
	struct au_finfo *finfo;
	struct dentry *dentry;

	err = -ENOMEM;
	dentry = file->f_dentry;
	finfo = au_cache_alloc_finfo();
	if (unlikely(!finfo))
		goto out;

	err = 0;
	au_nfiles_inc(dentry->d_sb);
	lc_idx = AuLcNonDir_FIINFO;
	if (fidir)
		lc_idx = AuLcDir_FIINFO;
	au_rw_class(&finfo->fi_rwsem, au_lc_key + lc_idx);
	au_rw_write_lock(&finfo->fi_rwsem);
	finfo->fi_btop = -1;
	finfo->fi_hdir = fidir;
	atomic_set(&finfo->fi_generation, au_digen(dentry));
	/* smp_mb(); */ /* atomic_set */

	file->private_data = finfo;

out:
	return err;
}
Ejemplo n.º 7
0
int au_finfo_init(struct file *file)
{
	struct au_finfo *finfo;
	struct dentry *dentry;
	unsigned long ul;

	dentry = file->f_dentry;
	finfo = au_cache_alloc_finfo();
	if (unlikely(!finfo))
		goto out;

	finfo->fi_hfile = kcalloc(au_sbend(dentry->d_sb) + 1,
				  sizeof(*finfo->fi_hfile), GFP_NOFS);
	if (unlikely(!finfo->fi_hfile))
		goto out_finfo;

	au_rw_init_wlock(&finfo->fi_rwsem);
	finfo->fi_bstart = -1;
	finfo->fi_bend = -1;
	atomic_set(&finfo->fi_generation, au_digen(dentry));
	/* smp_mb(); */ /* atomic_set */

	/* cf. au_store_oflag() */
	/* suppress a warning in lp64 */
	ul = (unsigned long)file->private_data;
	file->f_mode |= (vfsub_uint_to_fmode(ul) & FMODE_EXEC);
	file->private_data = finfo;
	return 0; /* success */

 out_finfo:
	au_cache_free_finfo(finfo);
 out:
	return -ENOMEM;
}
Ejemplo n.º 8
0
void au_dbg_verify_nondir_parent(struct dentry *dentry, unsigned int sigen)
{
	struct dentry *parent;

	parent = dget_parent(dentry);
	AuDebugOn(S_ISDIR(dentry->d_inode->i_mode)
		  || au_digen(parent) != sigen);
	dput(parent);
}
Ejemplo n.º 9
0
int au_digen_test(struct dentry *dentry, unsigned int sigen)
{
	int err;

	err = 0;
	if (unlikely(au_digen(dentry) != sigen
		     || au_iigen_test(dentry->d_inode, sigen)))
		err = -EIO;

	return err;
}
Ejemplo n.º 10
0
static struct dentry *decode_by_ino(struct super_block *sb, ino_t ino,
				    ino_t dir_ino)
{
	struct dentry *dentry, *d;
	struct inode *inode;
	au_gen_t sigen;

	LKTRTrace("i%lu, diri%lu\n",
		  (unsigned long)ino, (unsigned long)dir_ino);

	dentry = NULL;
	inode = ilookup(sb, ino);
	if (!inode)
		goto out;

	dentry = ERR_PTR(-ESTALE);
	sigen = au_sigen(sb);
	if (unlikely(is_bad_inode(inode)
		     || IS_DEADDIR(inode)
		     || sigen != au_iigen(inode)))
		goto out_iput;

	dentry = NULL;
	if (!dir_ino || S_ISDIR(inode->i_mode))
		dentry = d_find_alias(inode);
	else {
		spin_lock(&dcache_lock);
		list_for_each_entry(d, &inode->i_dentry, d_alias)
			if (!au_test_anon(d)
			    && d->d_parent->d_inode->i_ino == dir_ino) {
				dentry = dget_locked(d);
				break;
			}
		spin_unlock(&dcache_lock);
	}
	if (unlikely(dentry && sigen != au_digen(dentry))) {
		dput(dentry);
		dentry = ERR_PTR(-ESTALE);
	}

 out_iput:
	iput(inode);
 out:
	AuTraceErrPtr(dentry);
	return dentry;
}
Ejemplo n.º 11
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.º 12
0
/*
 * returns the number of found lower positive dentries,
 * otherwise an error.
 */
int au_refresh_hdentry(struct dentry *dentry, mode_t type)
{
	int npositive, err;
	unsigned int sigen;
	aufs_bindex_t bstart;
	struct au_dinfo *dinfo;
	struct super_block *sb;
	struct dentry *parent;

	DiMustWriteLock(dentry);

	sb = dentry->d_sb;
	AuDebugOn(IS_ROOT(dentry));
	sigen = au_sigen(sb);
	parent = dget_parent(dentry);
	AuDebugOn(au_digen(parent) != sigen
		  || au_iigen(parent->d_inode) != sigen);

	dinfo = au_di(dentry);
	err = au_di_realloc(dinfo, au_sbend(sb) + 1);
	npositive = err;
	if (unlikely(err))
		goto out;
	au_do_refresh_hdentry(dinfo->di_hdentry + dinfo->di_bstart, dinfo,
			      parent);

	npositive = 0;
	bstart = au_dbstart(parent);
	if (type != S_IFDIR && dinfo->di_bstart == bstart)
		goto out_dgen; /* success */

	npositive = au_lkup_dentry(dentry, bstart, type, /*nd*/NULL);
	if (npositive < 0)
		goto out;
	if (dinfo->di_bwh >= 0 && dinfo->di_bwh <= dinfo->di_bstart)
		d_drop(dentry);

 out_dgen:
	au_update_digen(dentry);
 out:
	dput(parent);
	AuTraceErr(npositive);
	return npositive;
}
Ejemplo n.º 13
0
void au_dbg_verify_gen(struct dentry *parent, unsigned int sigen)
{
	int err, i, j;
	struct au_dcsub_pages dpages;
	struct au_dpage *dpage;
	struct dentry **dentries;

	err = au_dpages_init(&dpages, GFP_NOFS);
	AuDebugOn(err);
	err = au_dcsub_pages_rev(&dpages, parent, /*do_include*/1, NULL, NULL);
	AuDebugOn(err);
	for (i = dpages.ndpage - 1; !err && i >= 0; i--) {
		dpage = dpages.dpages + i;
		dentries = dpage->dentries;
		for (j = dpage->ndentry - 1; !err && j >= 0; j--)
			AuDebugOn(au_digen(dentries[j]) != sigen);
	}
	au_dpages_free(&dpages);
}
Ejemplo n.º 14
0
void au_dpri_dentry(struct dentry *dentry)
{
	struct au_dinfo *dinfo;
	aufs_bindex_t bindex;
	int err;

	err = do_pri_dentry(-1, dentry);
	if (err || !au_test_aufs(dentry->d_sb))
		return;

	dinfo = au_di(dentry);
	if (!dinfo)
		return;
	dpri("d-1: bstart %d, bend %d, bwh %d, bdiropq %d, gen %d\n",
	     dinfo->di_bstart, dinfo->di_bend,
	     dinfo->di_bwh, dinfo->di_bdiropq, au_digen(dentry));
	if (dinfo->di_bstart < 0)
		return;
	for (bindex = dinfo->di_bstart; bindex <= dinfo->di_bend; bindex++)
		do_pri_dentry(bindex, dinfo->di_hdentry[0 + bindex].hd_dentry);
}
Ejemplo n.º 15
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;
}
Ejemplo n.º 16
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;
}
Ejemplo n.º 17
0
void au_update_figen(struct file *file)
{
	atomic_set(&au_fi(file)->fi_generation, au_digen(file->f_dentry));
	/* smp_mb(); */ /* atomic_set */
}