コード例 #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;
}
コード例 #2
0
ファイル: mvdown.c プロジェクト: ammubhave/bargud
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;
}
コード例 #3
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;
}