Example #1
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;
}
Example #2
0
int au_di_init(struct dentry *dentry)
{
	int err;
	struct super_block *sb;
	struct au_dinfo *dinfo;

	err = 0;
	sb = dentry->d_sb;
	dinfo = au_di_alloc(sb, AuLsc_DI_CHILD);
	if (dinfo) {
		atomic_set(&dinfo->di_generation, au_sigen(sb));
		/* smp_mb(); */ /* atomic_set */
		dentry->d_fsdata = dinfo;
	} else
		err = -ENOMEM;

	return err;
}
Example #3
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;
}
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;
}