Exemple #1
0
void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex,
		   struct dentry *h_dentry)
{
	struct au_hdentry *hd = au_di(dentry)->di_hdentry + bindex;
	DiMustWriteLock(dentry);
	AuDebugOn(bindex < au_di(dentry)->di_bstart
		  || bindex > au_di(dentry)->di_bend
		  || (h_dentry && atomic_read(&h_dentry->d_count) <= 0)
		  || (h_dentry && hd->hd_dentry)
		);
	if (hd->hd_dentry)
		au_hdput(hd, /*do_free*/0);
	hd->hd_dentry = h_dentry;
}
Exemple #2
0
int au_dcsub_pages(struct au_dcsub_pages *dpages, struct dentry *root,
		   au_dpages_test test, void *arg)
{
	int err;
	struct dentry *this_parent = root;
	struct list_head *next;
	struct super_block *sb = root->d_sb;

	err = 0;
	spin_lock(&dcache_lock);
repeat:
	next = this_parent->d_subdirs.next;
resume:
	if (this_parent->d_sb == sb
	    && !IS_ROOT(this_parent)
	    && au_di(this_parent)
	    && (!test || test(this_parent, arg))) {
		err = au_dpages_append(dpages, this_parent, GFP_ATOMIC);
		if (unlikely(err))
			goto out;
	}

	while (next != &this_parent->d_subdirs) {
		struct list_head *tmp = next;
		struct dentry *dentry = list_entry(tmp, struct dentry,
						   d_u.d_child);
		next = tmp->next;
		if (!list_empty(&dentry->d_subdirs)) {
			this_parent = dentry;
			goto repeat;
		}
		if (dentry->d_sb == sb
		    && au_di(dentry)
		    && (!test || test(dentry, arg))) {
			err = au_dpages_append(dpages, dentry, GFP_ATOMIC);
			if (unlikely(err))
				goto out;
		}
	}

	if (this_parent != root) {
		next = this_parent->d_u.d_child.next;
		this_parent = this_parent->d_parent; /* dcache_lock is locked */
		goto resume;
	}
out:
	spin_unlock(&dcache_lock);
	return err;
}
void di_write_unlock(struct dentry *d)
{
	au_dbg_verify_dinode(d);
	if (d->d_inode)
		ii_write_unlock(d->d_inode);
	au_rw_write_unlock(&au_di(d)->di_rwsem);
}
static void aufs_d_release(struct dentry *dentry)
{
	if (au_di(dentry)) {
		au_di_fin(dentry);
		au_hn_di_reinit(dentry);
	}
}
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);
}
void di_write_unlock2(struct dentry *d1, struct dentry *d2)
{
	di_write_unlock(d1);
	if (d1->d_inode == d2->d_inode)
		au_rw_write_unlock(&au_di(d2)->di_rwsem);
	else
		di_write_unlock(d2);
}
Exemple #7
0
void di_downgrade_lock(struct dentry *d, int flags)
{
	SiMustAnyLock(d->d_sb);

	au_rw_dgrade_lock(&au_di(d)->di_rwsem);
	if (d->d_inode && au_ftest_lock(flags, IR))
		ii_downgrade_lock(d->d_inode);
}
void au_di_fin(struct dentry *dentry)
{
	struct au_dinfo *dinfo;

	dinfo = au_di(dentry);
	AuRwDestroy(&dinfo->di_rwsem);
	au_di_free(dinfo);
}
Exemple #9
0
void di_write_unlock2(struct dentry *d1, struct dentry *d2)
{
	di_write_unlock(d1);
	if (d1->d_inode == d2->d_inode) {
		au_rw_write_unlock(&au_di(d2)->di_rwsem);
		au_dbg_locked_di_unreg(d2, AuLock_IW);
	} else
		di_write_unlock(d2);
}
Exemple #10
0
void di_write_unlock(struct dentry *d)
{
	LKTRTrace("%.*s\n", AuDLNPair(d));
	SiMustAnyLock(d->d_sb);

	if (d->d_inode)
		ii_write_unlock(d->d_inode);
	au_rw_write_unlock(&au_di(d)->di_rwsem);
	au_dbg_locked_di_unreg(d, AuLock_IW);
}
Exemple #11
0
void di_read_unlock(struct dentry *d, int flags)
{
	if (d->d_inode) {
		if (au_ftest_lock(flags, IW))
			ii_write_unlock(d->d_inode);
		else if (au_ftest_lock(flags, IR))
			ii_read_unlock(d->d_inode);
	}
	au_rw_read_unlock(&au_di(d)->di_rwsem);
}
void di_read_lock(struct dentry *d, int flags, unsigned int lsc)
{
	au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc);
	if (d->d_inode) {
		if (au_ftest_lock(flags, IW))
			do_ii_write_lock(d->d_inode, lsc);
		else if (au_ftest_lock(flags, IR))
			do_ii_read_lock(d->d_inode, lsc);
	}
}
Exemple #13
0
void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex,
		   struct dentry *h_dentry)
{
	struct au_hdentry *hd = au_di(dentry)->di_hdentry + bindex;

	DiMustWriteLock(dentry);

	if (hd->hd_dentry)
		au_hdput(hd);
	hd->hd_dentry = h_dentry;
}
Exemple #14
0
void au_set_dbdiropq(struct dentry *dentry, aufs_bindex_t bindex)
{
	DiMustWriteLock(dentry);
	AuDebugOn(au_sbend(dentry->d_sb) < bindex);
	AuDebugOn((bindex >= 0
		   && (bindex < au_dbstart(dentry)
		       || au_dbend(dentry) < bindex))
		  || (dentry->d_inode
		      && dentry->d_inode->i_mode
		      && !S_ISDIR(dentry->d_inode->i_mode)));
	au_di(dentry)->di_bdiropq = bindex;
}
Exemple #15
0
struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex)
{
	struct dentry *d;

	DiMustAnyLock(dentry);
	if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry))
		return NULL;
	AuDebugOn(bindex < 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;
}
struct dentry *au_h_dptr(struct dentry *dentry, aufs_bindex_t bindex)
{
	struct dentry *d;

	DiMustAnyLock(dentry);

	if (au_dbstart(dentry) < 0 || bindex < au_dbstart(dentry))
		return NULL;
	AuDebugOn(bindex < 0);
	d = au_di(dentry)->di_hdentry[0 + bindex].hd_dentry;
	AuDebugOn(d && au_dcount(d) <= 0);
	return d;
}
void di_read_unlock(struct dentry *d, int flags)
{
	if (d->d_inode) {
		if (au_ftest_lock(flags, IW)) {
			au_dbg_verify_dinode(d);
			ii_write_unlock(d->d_inode);
		} else if (au_ftest_lock(flags, IR)) {
			au_dbg_verify_dinode(d);
			ii_read_unlock(d->d_inode);
		}
	}
	au_rw_read_unlock(&au_di(d)->di_rwsem);
}
Exemple #18
0
void di_write_lock(struct dentry *d, unsigned int lsc)
{
	LKTRTrace("%.*s, %u\n", AuDLNPair(d), lsc);
	SiMustAnyLock(d->d_sb);

	/* todo: always nested? */
	au_dbg_locking_di_reg(d, AuLock_IW, lsc);
	au_rw_write_lock_nested(&au_di(d)->di_rwsem, lsc);
	au_dbg_locking_di_unreg(d, AuLock_IW);
	au_dbg_locked_di_reg(d, AuLock_IW, lsc);
	if (d->d_inode)
		do_ii_write_lock(d->d_inode, lsc);
}
Exemple #19
0
void di_read_unlock(struct dentry *d, int flags)
{
	LKTRTrace("%.*s\n", AuDLNPair(d));
	SiMustAnyLock(d->d_sb);

	if (d->d_inode) {
		if (au_ftest_lock(flags, IW))
			ii_write_unlock(d->d_inode);
		else if (au_ftest_lock(flags, IR))
			ii_read_unlock(d->d_inode);
	}
	au_rw_read_unlock(&au_di(d)->di_rwsem);
	au_dbg_locked_di_unreg(d, flags);
}
Exemple #20
0
/*
 * decide if a new whiteout for @dentry is necessary or not.
 * when it is necessary, prepare the parent dir for the upper branch whose
 * branch index is @bcpup for creation. the actual creation of the whiteout will
 * be done by caller.
 * return value:
 * 0: wh is unnecessary
 * plus: wh is necessary
 * minus: error
 */
int au_wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup)
{
	int need_wh, err;
	aufs_bindex_t bstart;
	struct super_block *sb;

	sb = dentry->d_sb;
	bstart = au_dbstart(dentry);
	if (*bcpup < 0) {
		*bcpup = bstart;
		if (au_test_ro(sb, bstart, dentry->d_inode)) {
			err = AuWbrCopyup(au_sbi(sb), dentry);
			*bcpup = err;
			if (unlikely(err < 0))
				goto out;
		}
	} else
		AuDebugOn(bstart < *bcpup
			  || au_test_ro(sb, *bcpup, dentry->d_inode));
	AuDbg("bcpup %d, bstart %d\n", *bcpup, bstart);

	if (*bcpup != bstart) {
		err = au_cpup_dirs(dentry, *bcpup);
		if (unlikely(err))
			goto out;
		need_wh = 1;
	} else {
		struct au_dinfo *dinfo, *tmp;

		need_wh = -ENOMEM;
		dinfo = au_di(dentry);
		tmp = au_di_alloc(sb, AuLsc_DI_TMP);
		if (tmp) {
			au_di_cp(tmp, dinfo);
			au_di_swap(tmp, dinfo);
			/* returns the number of positive dentries */
			need_wh = au_lkup_dentry(dentry, bstart + 1, /*type*/0,
						 /*nd*/NULL);
			au_di_swap(tmp, dinfo);
			au_rw_write_unlock(&tmp->di_rwsem);
			au_di_free(tmp);
		}
	}
	AuDbg("need_wh %d\n", need_wh);
	err = need_wh;

out:
	return err;
}
void au_set_h_dptr(struct dentry *dentry, aufs_bindex_t bindex,
		   struct dentry *h_dentry)
{
	struct au_hdentry *hd = au_di(dentry)->di_hdentry + bindex;
	struct au_branch *br;

	DiMustWriteLock(dentry);

	au_hdput(hd);
	hd->hd_dentry = h_dentry;
	if (h_dentry) {
		br = au_sbr(dentry->d_sb, bindex);
		hd->hd_id = br->br_id;
	}
}
Exemple #22
0
void di_read_lock(struct dentry *d, int flags, unsigned int lsc)
{
	LKTRTrace("%.*s, %u\n", AuDLNPair(d), lsc);
	SiMustAnyLock(d->d_sb);

	/* todo: always nested? */
	au_dbg_locking_di_reg(d, flags, lsc);
	au_rw_read_lock_nested(&au_di(d)->di_rwsem, lsc);
	au_dbg_locking_di_unreg(d, flags);
	au_dbg_locked_di_reg(d, flags, lsc);
	if (d->d_inode) {
		if (au_ftest_lock(flags, IW))
			do_ii_write_lock(d->d_inode, lsc);
		else if (au_ftest_lock(flags, IR))
			do_ii_read_lock(d->d_inode, lsc);
	}
}
Exemple #23
0
static void au_br_do_add(struct super_block *sb, struct dentry *h_dentry,
                         struct au_branch *br, aufs_bindex_t bindex)
{
    struct dentry *root;
    struct inode *root_inode;
    aufs_bindex_t bend, amount;

    root = sb->s_root;
    root_inode = root->d_inode;
    bend = au_sbend(sb);
    amount = bend + 1 - bindex;
    au_br_do_add_brp(au_sbi(sb), bindex, br, bend, amount);
    au_br_do_add_hdp(au_di(root), bindex, bend, amount);
    au_br_do_add_hip(au_ii(root_inode), bindex, bend, amount);
    au_set_h_dptr(root, bindex, dget(h_dentry));
    au_set_h_iptr(root_inode, bindex, au_igrab(h_dentry->d_inode),
                  /*flags*/0);
}
Exemple #24
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;
}
/*
 * returns a newly allocated branch. @new_nbranch is a number of branches
 * after adding a branch.
 */
static struct au_branch *au_br_alloc(struct super_block *sb, int new_nbranch,
				     int perm)
{
	struct au_branch *add_branch;
	struct dentry *root;
	int err;

	err = -ENOMEM;
	root = sb->s_root;
	add_branch = kmalloc(sizeof(*add_branch), GFP_NOFS);
	if (unlikely(!add_branch))
		goto out;

	err = au_hnotify_init_br(add_branch, perm);
	if (unlikely(err))
		goto out_br;

	add_branch->br_wbr = NULL;
	if (au_br_writable(perm)) {
		/* may be freed separately at changing the branch permission */
		add_branch->br_wbr = kmalloc(sizeof(*add_branch->br_wbr),
					     GFP_NOFS);
		if (unlikely(!add_branch->br_wbr))
			goto out_hnotify;
	}

	err = au_sbr_realloc(au_sbi(sb), new_nbranch);
	if (!err)
		err = au_di_realloc(au_di(root), new_nbranch);
	if (!err)
		err = au_ii_realloc(au_ii(root->d_inode), new_nbranch);
	if (!err)
		return add_branch; /* success */

	kfree(add_branch->br_wbr);

out_hnotify:
	au_hnotify_fin_br(add_branch);
out_br:
	kfree(add_branch);
out:
	return ERR_PTR(err);
}
Exemple #26
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);
}
Exemple #27
0
static int au_reopen_wh(struct file *file, aufs_bindex_t btgt,
			struct dentry *hi_wh)
{
	int err;
	aufs_bindex_t bstart;
	struct au_dinfo *dinfo;
	struct dentry *h_dentry;

	dinfo = au_di(file->f_dentry);
	AuRwMustWriteLock(&dinfo->di_rwsem);

	bstart = dinfo->di_bstart;
	dinfo->di_bstart = btgt;
	h_dentry = dinfo->di_hdentry[0 + btgt].hd_dentry;
	dinfo->di_hdentry[0 + btgt].hd_dentry = hi_wh;
	err = au_reopen_nondir(file);
	dinfo->di_hdentry[0 + btgt].hd_dentry = h_dentry;
	dinfo->di_bstart = bstart;

	return err;
}
void au_update_dbrange(struct dentry *dentry, int do_put_zero)
{
	struct au_dinfo *dinfo;
	struct dentry *h_d;
	struct au_hdentry *hdp;

	DiMustWriteLock(dentry);

	dinfo = au_di(dentry);
	if (!dinfo || dinfo->di_bstart < 0)
		return;

	hdp = dinfo->di_hdentry;
	if (do_put_zero) {
		aufs_bindex_t bindex, bend;

		bend = dinfo->di_bend;
		for (bindex = dinfo->di_bstart; bindex <= bend; bindex++) {
			h_d = hdp[0 + bindex].hd_dentry;
			if (h_d && !h_d->d_inode)
				au_set_h_dptr(dentry, bindex, NULL);
		}
	}

	dinfo->di_bstart = -1;
	while (++dinfo->di_bstart <= dinfo->di_bend)
		if (hdp[0 + dinfo->di_bstart].hd_dentry)
			break;
	if (dinfo->di_bstart > dinfo->di_bend) {
		dinfo->di_bstart = -1;
		dinfo->di_bend = -1;
		return;
	}

	dinfo->di_bend++;
	while (0 <= --dinfo->di_bend)
		if (hdp[0 + dinfo->di_bend].hd_dentry)
			break;
	AuDebugOn(dinfo->di_bstart > dinfo->di_bend || dinfo->di_bend < 0);
}
Exemple #29
0
static inline int au_dcsub_dpages_aufs(struct dentry *dentry, void *arg)
{
	return au_di(dentry) && dentry->d_sb == arg;
}
void au_update_digen(struct dentry *dentry)
{
	atomic_set(&au_di(dentry)->di_generation, au_sigen(dentry->d_sb));
	/* smp_mb(); */ /* atomic_set */
}