Пример #1
0
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);
}
Пример #2
0
/*
 * they are necessary regardless sysfs is disabled.
 */
void au_si_free(struct kobject *kobj)
{
	struct au_sbinfo *sbinfo;
	char *locked __maybe_unused; /* debug only */

	sbinfo = container_of(kobj, struct au_sbinfo, si_kobj);
	AuDebugOn(!list_empty(&sbinfo->si_plink.head));
	AuDebugOn(atomic_read(&sbinfo->si_nowait.nw_len));

	au_rw_write_lock(&sbinfo->si_rwsem);
	au_br_free(sbinfo);
	au_rw_write_unlock(&sbinfo->si_rwsem);

	AuDebugOn(radix_tree_gang_lookup
		  (&sbinfo->au_si_pid.tree, (void **)&locked,
		   /*first_index*/PID_MAX_DEFAULT - 1,
		   /*max_items*/sizeof(locked)/sizeof(*locked)));

	kfree(sbinfo->si_branch);
	kfree(sbinfo->au_si_pid.bitmap);
	mutex_destroy(&sbinfo->si_xib_mtx);
	AuRwDestroy(&sbinfo->si_rwsem);

	kfree(sbinfo);
}
Пример #3
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);
	else
		di_write_unlock(d2);
}
Пример #4
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);
}
Пример #5
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);
}
Пример #6
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;
}
Пример #7
0
static int au_mvd_args_intermediate(const unsigned char dmsg,
                                    struct au_mvd_args *a)
{
    int err;
    struct au_dinfo *dinfo, *tmp;

    /* lookup the next lower positive entry */
    err = -ENOMEM;
    tmp = au_di_alloc(a->sb, AuLsc_DI_TMP);
    if (unlikely(!tmp))
        goto out;

    a->bfound = -1;
    a->bwh = -1;
    dinfo = au_di(a->dentry);
    au_di_cp(tmp, dinfo);
    au_di_swap(tmp, dinfo);

    /* returns the number of positive dentries */
    err = au_lkup_dentry(a->dentry, a->mvd_bsrc + 1, /*type*/0);
    if (!err)
        a->bwh = au_dbwh(a->dentry);
    else if (err > 0)
        a->bfound = au_dbstart(a->dentry);

    au_di_swap(tmp, dinfo);
    au_rw_write_unlock(&tmp->di_rwsem);
    au_di_free(tmp);
    if (unlikely(err < 0))
        AU_MVD_PR(dmsg, "failed look-up lower\n");

    /*
     * here, we have these cases.
     * bfound == -1
     *	no positive dentry under bsrc. there are more sub-cases.
     *	bwh < 0
     *		there no whiteout, we can safely move-down.
     *	bwh <= bsrc
     *		impossible
     *	bsrc < bwh && bwh < bdst
     *		there is a whiteout on RO branch. cannot proceed.
     *	bwh == bdst
     *		there is a whiteout on the RW target branch. it should
     *		be removed.
     *	bdst < bwh
     *		there is a whiteout somewhere unrelated branch.
     * -1 < bfound && bfound <= bsrc
     *	impossible.
     * bfound < bdst
     *	found, but it is on RO branch between bsrc and bdst. cannot
     *	proceed.
     * bfound == bdst
     *	found, replace it if AUFS_MVDOWN_FORCE is set. otherwise return
     *	error.
     * bdst < bfound
     *	found, after we create the file on bdst, it will be hidden.
     */

    AuDebugOn(a->bfound == -1
              && a->bwh != -1
              && a->bwh <= a->mvd_bsrc);
    AuDebugOn(-1 < a->bfound
              && a->bfound <= a->mvd_bsrc);

    err = -EINVAL;
    if (a->bfound == -1
            && a->mvd_bsrc < a->bwh
            && a->bwh != -1
            && a->bwh < a->mvd_bdst) {
        a->mvd_errno = EAU_MVDOWN_WHITEOUT;
        AU_MVD_PR(dmsg, "bsrc %d, bdst %d, bfound %d, bwh %d\n",
                  a->mvd_bsrc, a->mvd_bdst, a->bfound, a->bwh);
        goto out;
    } else if (a->bfound != -1 && a->bfound < a->mvd_bdst) {
        a->mvd_errno = EAU_MVDOWN_UPPER;
        AU_MVD_PR(dmsg, "bdst %d, bfound %d\n",
                  a->mvd_bdst, a->bfound);
        goto out;
    }

    err = 0; /* success */

out:
    AuTraceErr(err);
    return err;
}
Пример #8
0
int au_refresh_dentry(struct dentry *dentry, struct dentry *parent)
{
	int err, ebrange;
	unsigned int sigen;
	struct au_dinfo *dinfo, *tmp;
	struct super_block *sb;
	struct inode *inode;

	DiMustWriteLock(dentry);
	AuDebugOn(IS_ROOT(dentry));
	AuDebugOn(!parent->d_inode);

	sb = dentry->d_sb;
	inode = dentry->d_inode;
	sigen = au_sigen(sb);
	err = au_digen_test(parent, sigen);
	if (unlikely(err))
		goto out;

	dinfo = au_di(dentry);
	err = au_di_realloc(dinfo, au_sbend(sb) + 1);
	if (unlikely(err))
		goto out;
	ebrange = au_dbrange_test(dentry);
	if (!ebrange)
		ebrange = au_do_refresh_hdentry(dentry, parent);

	if (d_unhashed(dentry) || ebrange) {
		AuDebugOn(au_dbstart(dentry) < 0 && au_dbend(dentry) >= 0);
		if (inode)
			err = au_refresh_hinode_self(inode);
		au_dbg_verify_dinode(dentry);
		if (!err)
			goto out_dgen; /* success */
		goto out;
	}

	/* temporary dinfo */
	AuDbgDentry(dentry);
	err = -ENOMEM;
	tmp = au_di_alloc(sb, AuLsc_DI_TMP);
	if (unlikely(!tmp))
		goto out;
	au_di_swap(tmp, dinfo);
	/* returns the number of positive dentries */
	/*
	 * if current working dir is removed, it returns an error.
	 * but the dentry is legal.
	 */
	err = au_lkup_dentry(dentry, /*bstart*/0, /*type*/0, /*nd*/NULL);
	AuDbgDentry(dentry);
	au_di_swap(tmp, dinfo);
	if (err == -ENOENT)
		err = 0;
	if (err >= 0) {
		/* compare/refresh by dinfo */
		AuDbgDentry(dentry);
		err = au_refresh_by_dinfo(dentry, dinfo, tmp);
		au_dbg_verify_dinode(dentry);
		AuTraceErr(err);
	}
	au_rw_write_unlock(&tmp->di_rwsem);
	au_di_free(tmp);
	if (unlikely(err))
		goto out;

out_dgen:
	au_update_digen(dentry);
out:
	if (unlikely(err && !(dentry->d_flags & DCACHE_NFSFS_RENAMED))) {
		AuIOErr("failed refreshing %.*s, %d\n",
			AuDLNPair(dentry), err);
		AuDbgDentry(dentry);
	}
	AuTraceErr(err);
	return err;
}
Пример #9
0
void di_write_unlock(struct dentry *d)
{
	if (d->d_inode)
		ii_write_unlock(d->d_inode);
	au_rw_write_unlock(&au_di(d)->di_rwsem);
}