Example #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);

	if (hd->hd_dentry)
		au_hdput(hd);
	hd->hd_dentry = h_dentry;
}
Example #2
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;
}
Example #3
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;
}
Example #4
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;
	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;
	}
}
Example #5
0
static int do_coo(struct dentry *dentry, aufs_bindex_t bstart)
{
	int err;
	struct dentry *parent, *h_parent, *h_dentry;
	aufs_bindex_t bcpup;
	struct inode *h_dir, *h_inode, *dir;

	LKTRTrace("%.*s\n", DLNPair(dentry));
	DEBUG_ON(IS_ROOT(dentry));
	DiMustWriteLock(dentry);

	parent = dentry->d_parent; // dget_parent()
	di_write_lock_parent(parent);
	bcpup = err = find_rw_parent_br(dentry, bstart);
	//bcpup = err = find_rw_br(sb, bstart);
	if (unlikely(err < 0)) {
		err = 0; // stop copyup, it is not an error
		goto out;
	}
	err = 0;

	h_parent = au_h_dptr_i(parent, bcpup);
	if (!h_parent) {
		err = cpup_dirs(dentry, bcpup, NULL);
		if (unlikely(err))
			goto out;
		h_parent = au_h_dptr_i(parent, bcpup);
	}

	h_dir = h_parent->d_inode;
	h_dentry = au_h_dptr_i(dentry, bstart);
	h_inode = h_dentry->d_inode;
	dir = parent->d_inode;
	hdir_lock(h_dir, dir, bcpup);
	hi_lock_child(h_inode);
	DEBUG_ON(au_h_dptr_i(dentry, bcpup));
	err = sio_cpup_simple(dentry, bcpup, -1,
			      au_flags_cpup(CPUP_DTIME, parent));
	TraceErr(err);
	i_unlock(h_inode);
	hdir_unlock(h_dir, dir, bcpup);

 out:
	di_write_unlock(parent);
	TraceErr(err);
	return err;
}
Example #6
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;
}
Example #7
0
void au_update_dbend(struct dentry *dentry)
{
	aufs_bindex_t bindex,
		bstart = au_dbstart(dentry),
		bend = au_dbend(dentry);
	struct dentry *h_dentry;

	DiMustWriteLock(dentry);
	for (bindex = bend; bindex <= bstart; bindex--) {
		h_dentry = au_h_dptr(dentry, bindex);
		if (!h_dentry)
			continue;
		if (h_dentry->d_inode) {
			au_set_dbend(dentry, bindex);
			return;
		}
		au_set_h_dptr(dentry, bindex, NULL);
	}
}
Example #8
0
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);
}
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;
}
Example #10
0
static int au_do_refresh_hdentry(struct dentry *dentry, struct dentry *parent)
{
	int err;
	aufs_bindex_t new_bindex, bindex, bend, bwh, bdiropq;
	struct au_hdentry tmp, *p, *q;
	struct au_dinfo *dinfo;
	struct super_block *sb;

	DiMustWriteLock(dentry);

	sb = dentry->d_sb;
	dinfo = au_di(dentry);
	bend = dinfo->di_bend;
	bwh = dinfo->di_bwh;
	bdiropq = dinfo->di_bdiropq;
	p = dinfo->di_hdentry + dinfo->di_bstart;
	for (bindex = dinfo->di_bstart; bindex <= bend; bindex++, p++) {
		if (!p->hd_dentry)
			continue;

		new_bindex = au_br_index(sb, p->hd_id);
		if (new_bindex == bindex)
			continue;

		if (dinfo->di_bwh == bindex)
			bwh = new_bindex;
		if (dinfo->di_bdiropq == bindex)
			bdiropq = new_bindex;
		if (new_bindex < 0) {
			au_hdput(p);
			p->hd_dentry = NULL;
			continue;
		}

		/* swap two lower dentries, and loop again */
		q = dinfo->di_hdentry + new_bindex;
		tmp = *q;
		*q = *p;
		*p = tmp;
		if (tmp.hd_dentry) {
			bindex--;
			p--;
		}
	}

	dinfo->di_bwh = -1;
	if (bwh >= 0 && bwh <= au_sbend(sb) && au_sbr_whable(sb, bwh))
		dinfo->di_bwh = bwh;

	dinfo->di_bdiropq = -1;
	if (bdiropq >= 0
	    && bdiropq <= au_sbend(sb)
	    && au_sbr_whable(sb, bdiropq))
		dinfo->di_bdiropq = bdiropq;

	err = -EIO;
	dinfo->di_bstart = -1;
	dinfo->di_bend = -1;
	bend = au_dbend(parent);
	p = dinfo->di_hdentry;
	for (bindex = 0; bindex <= bend; bindex++, p++)
		if (p->hd_dentry) {
			dinfo->di_bstart = bindex;
			break;
		}

	if (dinfo->di_bstart >= 0) {
		p = dinfo->di_hdentry + bend;
		for (bindex = bend; bindex >= 0; bindex--, p--)
			if (p->hd_dentry) {
				dinfo->di_bend = bindex;
				err = 0;
				break;
			}
	}

	return err;
}
Example #11
0
/*
 * copyup the deleted file for writing.
 */
static int cpup_wh_file(struct file *file, aufs_bindex_t bdst, loff_t len)
{
	int err;
	struct dentry *dentry, *parent, *hidden_parent, *tmp_dentry;
	struct dentry *hidden_dentry_bstart, *hidden_dentry_bdst;
	struct inode *hidden_dir;
	aufs_bindex_t bstart;
	struct aufs_dinfo *dinfo;
	struct dtime dt;
	struct lkup_args lkup;
	struct super_block *sb;

	dentry = file->f_dentry;
	LKTRTrace("%.*s, bdst %d, len %Lu\n", DLNPair(dentry), bdst, len);
	DEBUG_ON(S_ISDIR(dentry->d_inode->i_mode)
		 || !(file->f_mode & FMODE_WRITE));
	DiMustWriteLock(dentry);
	parent = dentry->d_parent;
	IiMustAnyLock(parent->d_inode);
	hidden_parent = au_h_dptr_i(parent, bdst);
	DEBUG_ON(!hidden_parent);
	hidden_dir = hidden_parent->d_inode;
	DEBUG_ON(!hidden_dir);
	IMustLock(hidden_dir);

	sb = parent->d_sb;
	lkup.nfsmnt = au_nfsmnt(sb, bdst);
	lkup.dlgt = need_dlgt(sb);
	tmp_dentry = lkup_whtmp(hidden_parent, &dentry->d_name, &lkup);
	//if (LktrCond) {dput(tmp_dentry); tmp_dentry = ERR_PTR(-1);}
	err = PTR_ERR(tmp_dentry);
	if (IS_ERR(tmp_dentry))
		goto out;

	dtime_store(&dt, parent, hidden_parent);
	dinfo = dtodi(dentry);
	bstart = dinfo->di_bstart;
	hidden_dentry_bdst = dinfo->di_hdentry[0 + bdst].hd_dentry;
	hidden_dentry_bstart = dinfo->di_hdentry[0 + bstart].hd_dentry;
	dinfo->di_bstart = bdst;
	dinfo->di_hdentry[0 + bdst].hd_dentry = tmp_dentry;
	dinfo->di_hdentry[0 + bstart].hd_dentry = au_h_fptr(file)->f_dentry;
	err = cpup_single(dentry, bdst, bstart, len,
			  au_flags_cpup(!CPUP_DTIME, parent));
	//if (LktrCond) err = -1;
	if (!err)
		err = au_reopen_nondir(file);
		//err = -1;
	if (unlikely(err)) {
		dinfo->di_hdentry[0 + bstart].hd_dentry = hidden_dentry_bstart;
		dinfo->di_hdentry[0 + bdst].hd_dentry = hidden_dentry_bdst;
		dinfo->di_bstart = bstart;
		goto out_tmp;
	}

	DEBUG_ON(!d_unhashed(dentry));
	err = vfsub_unlink(hidden_dir, tmp_dentry, lkup.dlgt);
	//if (LktrCond) err = -1;
	if (unlikely(err)) {
		IOErr("failed remove copied-up tmp file %.*s(%d)\n",
		      DLNPair(tmp_dentry), err);
		err = -EIO;
	}
	dtime_revert(&dt, !CPUP_LOCKED_GHDIR);

 out_tmp:
	dput(tmp_dentry);
 out:
	TraceErr(err);
	return err;
}
Example #12
0
static int au_cmoo(struct dentry *dentry)
{
	int err, cmoo;
	unsigned int udba;
	struct path h_path;
	struct au_pin pin;
	struct au_cp_generic cpg = {
		.dentry	= dentry,
		.bdst	= -1,
		.bsrc	= -1,
		.len	= -1,
		.pin	= &pin,
		.flags	= AuCpup_DTIME | AuCpup_HOPEN
	};
	struct inode *inode, *delegated;
	struct super_block *sb;
	struct au_sbinfo *sbinfo;
	struct au_fhsm *fhsm;
	pid_t pid;
	struct au_branch *br;
	struct dentry *parent;
	struct au_hinode *hdir;

	DiMustWriteLock(dentry);
	inode = dentry->d_inode;
	IiMustWriteLock(inode);

	err = 0;
	if (IS_ROOT(dentry))
		goto out;
	cpg.bsrc = au_dbstart(dentry);
	if (!cpg.bsrc)
		goto out;

	sb = dentry->d_sb;
	sbinfo = au_sbi(sb);
	fhsm = &sbinfo->si_fhsm;
	pid = au_fhsm_pid(fhsm);
	if (pid
	    && (current->pid == pid
		|| current->real_parent->pid == pid))
		goto out;

	br = au_sbr(sb, cpg.bsrc);
	cmoo = au_br_cmoo(br->br_perm);
	if (!cmoo)
		goto out;
	if (!S_ISREG(inode->i_mode))
		cmoo &= AuBrAttr_COO_ALL;
	if (!cmoo)
		goto out;

	parent = dget_parent(dentry);
	di_write_lock_parent(parent);
	err = au_wbr_do_copyup_bu(dentry, cpg.bsrc - 1);
	cpg.bdst = err;
	if (unlikely(err < 0)) {
		err = 0;	/* there is no upper writable branch */
		goto out_dgrade;
	}
	AuDbg("bsrc %d, bdst %d\n", cpg.bsrc, cpg.bdst);

	/* do not respect the coo attrib for the target branch */
	err = au_cpup_dirs(dentry, cpg.bdst);
	if (unlikely(err))
		goto out_dgrade;

	di_downgrade_lock(parent, AuLock_IR);
	udba = au_opt_udba(sb);
	err = au_pin(&pin, dentry, cpg.bdst, udba,
		     AuPin_DI_LOCKED | AuPin_MNT_WRITE);
	if (unlikely(err))
		goto out_parent;

	err = au_sio_cpup_simple(&cpg);
	au_unpin(&pin);
	if (unlikely(err))
		goto out_parent;
	if (!(cmoo & AuBrWAttr_MOO))
		goto out_parent; /* success */

	err = au_pin(&pin, dentry, cpg.bsrc, udba,
		     AuPin_DI_LOCKED | AuPin_MNT_WRITE);
	if (unlikely(err))
		goto out_parent;

	h_path.mnt = au_br_mnt(br);
	h_path.dentry = au_h_dptr(dentry, cpg.bsrc);
	hdir = au_hi(parent->d_inode, cpg.bsrc);
	delegated = NULL;
	err = vfsub_unlink(hdir->hi_inode, &h_path, &delegated, /*force*/1);
	au_unpin(&pin);
	/* todo: keep h_dentry or not? */
	if (unlikely(err == -EWOULDBLOCK)) {
		pr_warn("cannot retry for NFSv4 delegation"
			" for an internal unlink\n");
		iput(delegated);
	}
	if (unlikely(err)) {
		pr_err("unlink %pd after coo failed (%d), ignored\n",
		       dentry, err);
		err = 0;
	}
	goto out_parent; /* success */

out_dgrade:
	di_downgrade_lock(parent, AuLock_IR);
out_parent:
	di_read_unlock(parent, AuLock_IR);
	dput(parent);
out:
	AuTraceErr(err);
	return err;
}

int au_do_open(struct file *file, int (*open)(struct file *file, int flags),
	       struct au_fidir *fidir)
{
	int err;
	struct dentry *dentry;
	struct au_finfo *finfo;

	err = au_finfo_init(file, fidir);
	if (unlikely(err))
		goto out;

	dentry = file->f_path.dentry;
	di_write_lock_child(dentry);
	err = au_cmoo(dentry);
	di_downgrade_lock(dentry, AuLock_IR);
	if (!err)
		err = open(file, vfsub_file_flags(file));
	di_read_unlock(dentry, AuLock_IR);

	finfo = au_fi(file);
	if (!err) {
		finfo->fi_file = file;
		au_sphl_add(&finfo->fi_hlist,
			    &au_sbi(file->f_path.dentry->d_sb)->si_files);
	}
	fi_write_unlock(file);
	if (unlikely(err)) {
		finfo->fi_hdir = NULL;
		au_finfo_fin(file);
	}

out:
	return err;
}