Beispiel #1
0
/* common functions to regular file and dir */
struct file *hidden_open(struct dentry *dentry, aufs_bindex_t bindex, int flags)
{
	struct dentry *hidden_dentry;
	struct inode *hidden_inode;
	struct super_block *sb;
	struct vfsmount *hidden_mnt;
	struct file *hidden_file;
	struct aufs_branch *br;
	loff_t old_size;
	int udba;

	LKTRTrace("%.*s, b%d, flags 0%o\n", DLNPair(dentry), bindex, flags);
	DEBUG_ON(!dentry);
	hidden_dentry = au_h_dptr_i(dentry, bindex);
	DEBUG_ON(!hidden_dentry);
	hidden_inode = hidden_dentry->d_inode;
	DEBUG_ON(!hidden_inode);

	sb = dentry->d_sb;
	udba = au_flag_test(sb, AuFlag_UDBA_INOTIFY);
	if (unlikely(udba)) {
		// test here?
	}

	br = stobr(sb, bindex);
	br_get(br);
	/* drop flags for writing */
	if (test_ro(sb, bindex, dentry->d_inode))
		flags = au_file_roflags(flags);
	flags &= ~O_CREAT;
	spin_lock(&hidden_inode->i_lock);
	old_size = i_size_read(hidden_inode);
	spin_unlock(&hidden_inode->i_lock);

	//DbgSleep(3);

	dget(hidden_dentry);
	hidden_mnt = mntget(br->br_mnt);
	hidden_file = dentry_open(hidden_dentry, hidden_mnt, flags);
	//if (LktrCond) {fput(hidden_file); hidden_file = ERR_PTR(-1);}

	if (!IS_ERR(hidden_file)) {
#if 0 // remove this
		if (/* old_size && */ (flags & O_TRUNC)) {
			au_direval_dec(dentry);
			if (!IS_ROOT(dentry))
				au_direval_dec(dentry->d_parent);
		}
#endif
		return hidden_file;
	}

	br_put(br);
	TraceErrPtr(hidden_file);
	return hidden_file;
}
Beispiel #2
0
int au_is_subdir(struct dentry *d1, struct dentry *d2)
{
	int err;
#ifndef AuUse_ISSUBDIR
	int i, j;
	struct au_dcsub_pages dpages;
	struct au_dpage *dpage;
	struct dentry **dentries;
#endif

	LKTRTrace("%.*s, %.*s\n", DLNPair(d1), DLNPair(d2));

#ifdef AuUse_ISSUBDIR
	spin_lock(&dcache_lock);
	err = is_subdir(d1, d2);
	spin_unlock(&dcache_lock);
#else
	err = au_dpages_init(&dpages, GFP_KERNEL);
	if (unlikely(err))
		goto out;
	err = au_dcsub_pages_rev(&dpages, d1, /*do_include*/1, NULL, NULL);
	if (unlikely(err))
		goto out_dpages;

	for (i = dpages.ndpage - 1; !err && i >= 0; i--) {
		dpage = dpages.dpages + i;
		dentries = dpage->dentries;
		for (j = dpage->ndentry - 1; !err && j >= 0; j--) {
			struct dentry *d;
			d = dentries[j];
			//Dbg("d %.*s\n", DLNPair(d));
			err = (d == d2);
		}
	}

 out_dpages:
	au_dpages_free(&dpages);
 out:
#endif
	TraceErr(err);
	return err;
}
Beispiel #3
0
int au_reopen_nondir(struct file *file)
{
	int err;
	struct dentry *dentry;
	aufs_bindex_t bstart, bindex, bend;
	struct file *hidden_file, *h_file_tmp;

	dentry = file->f_dentry;
	LKTRTrace("%.*s\n", DLNPair(dentry));
	DEBUG_ON(S_ISDIR(dentry->d_inode->i_mode)
		 || !au_h_dptr(dentry)->d_inode);
	bstart = dbstart(dentry);

	h_file_tmp = NULL;
	if (fbstart(file) == bstart) {
		hidden_file = au_h_fptr(file);
		if (file->f_mode == hidden_file->f_mode)
			return 0; /* success */
		h_file_tmp = hidden_file;
		get_file(h_file_tmp);
		set_h_fptr(file, bstart, NULL);
	}
	DEBUG_ON(fbstart(file) < bstart
		 || ftofi(file)->fi_hfile[0 + bstart].hf_file);

	hidden_file = hidden_open(dentry, bstart, file->f_flags & ~O_TRUNC);
	//if (LktrCond) {fput(hidden_file); br_put(stobr(dentry->d_sb, bstart));
	//hidden_file = ERR_PTR(-1);}
	err = PTR_ERR(hidden_file);
	if (IS_ERR(hidden_file))
		goto out; // close all?
	err = 0;
	//cpup_file_flags(hidden_file, file);
	set_fbstart(file, bstart);
	set_h_fptr(file, bstart, hidden_file);
	memcpy(&hidden_file->f_ra, &file->f_ra, sizeof(file->f_ra)); //??

	/* close lower files */
	bend = fbend(file);
	for (bindex = bstart + 1; bindex <= bend; bindex++)
		set_h_fptr(file, bindex, NULL);
	set_fbend(file, bstart);

 out:
	if (h_file_tmp)
		fput(h_file_tmp);
	TraceErr(err);
	return err;
}
Beispiel #4
0
static int renwh_and_rmdir(struct dentry *dentry, aufs_bindex_t bindex,
			   struct aufs_nhash *whlist, struct inode *dir)
{
	int rmdir_later, err;
	struct dentry *hidden_dentry;

	LKTRTrace("%.*s, b%d\n", DLNPair(dentry), bindex);

	err = rename_whtmp(dentry, bindex);
	//err = -1;
	//todo: bug
	if (unlikely(err)) {
		au_direval_inc(dentry->d_parent);
		return err;
	}

	hidden_dentry = au_h_dptr_i(dentry, bindex);
	if (!au_is_nfs(hidden_dentry->d_sb)) {
		const int dirwh = stosi(dentry->d_sb)->si_dirwh;
		rmdir_later = (dirwh <= 1);
		if (!rmdir_later)
			rmdir_later = is_longer_wh(whlist, bindex, dirwh);
		if (rmdir_later)
			return rmdir_later;
	}

	err = rmdir_whtmp(hidden_dentry, whlist, bindex, dir, dentry->d_inode);
	//err = -1;
	if (unlikely(err)) {
		IOErr("rmdir %.*s, b%d failed, %d. ignored\n",
		      DLNPair(hidden_dentry), bindex, err);
		err = 0;
	}
	TraceErr(err);
	return err;
}
Beispiel #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;
}
Beispiel #6
0
static int do_revert(int err, struct dentry *wh_dentry, struct dentry *dentry,
		     aufs_bindex_t bwh, struct dtime *dt, int dlgt)
{
	int rerr;

	rerr = au_unlink_wh_dentry(wh_dentry->d_parent->d_inode, wh_dentry,
				   dentry, dlgt);
	//rerr = -1;
	if (!rerr) {
		set_dbwh(dentry, bwh);
		dtime_revert(dt, !CPUP_LOCKED_GHDIR);
		return 0;
	}

	IOErr("%.*s reverting whiteout failed(%d, %d)\n",
	      DLNPair(dentry), err, rerr);
	return -EIO;
}
Beispiel #7
0
static struct dentry *
lock_hdir_create_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup,
		    struct dtime *dt)
{
	struct dentry *wh_dentry;
	int err, need_wh;
	struct dentry *hidden_parent, *parent;
	struct inode *dir, *h_dir;
	struct lkup_args lkup;

	LKTRTrace("%.*s, isdir %d\n", DLNPair(dentry), isdir);

	err = need_wh = wr_dir_need_wh(dentry, isdir, bcpup, NULL);
	//err = -1;
	wh_dentry = ERR_PTR(err);
	if (unlikely(err < 0))
		goto out;

	parent = dentry->d_parent;
	dir = parent->d_inode;
	hidden_parent = au_h_dptr_i(parent, *bcpup);
	h_dir = hidden_parent->d_inode;
	hdir_lock(h_dir, dir, *bcpup);
	dtime_store(dt, parent, hidden_parent);
	if (!need_wh)
		return NULL; /* success, no need to create whiteout */

	lkup.nfsmnt = au_nfsmnt(dentry->d_sb, *bcpup);
	lkup.dlgt = need_dlgt(dentry->d_sb);
	wh_dentry = simple_create_wh(dentry, *bcpup, hidden_parent, &lkup);
	//wh_dentry = ERR_PTR(-1);
	if (!IS_ERR(wh_dentry))
		goto out; /* success */
	/* returns with the parent is locked and wh_dentry is DGETed */

	hdir_unlock(h_dir, dir, *bcpup);

 out:
	TraceErrPtr(wh_dentry);
	return wh_dentry;
}
Beispiel #8
0
static ssize_t xino_fread(readf_t func, struct file *file, void *buf,
			  size_t size, loff_t *pos)
{
	ssize_t err;
	mm_segment_t oldfs;

	LKTRTrace("%.*s, sz %lu, *pos %Ld\n",
		  DLNPair(file->f_dentry), (unsigned long)size, *pos);

	oldfs = get_fs();
	set_fs(KERNEL_DS);
	do {
		err = func(file, (char __user*)buf, size, pos);
	} while (err == -EAGAIN || err == -EINTR);
	set_fs(oldfs);

#if 0
	if (err > 0)
		fsnotify_access(file->f_dentry);
#endif

	TraceErr(err);
	return err;
}
Beispiel #9
0
static ssize_t xino_fwrite(writef_t func, struct file *file, void *buf,
			   size_t size, loff_t *pos)
{
	ssize_t err;

	LKTRTrace("%.*s, sz %lu, *pos %Ld\n",
		  DLNPair(file->f_dentry), (unsigned long)size, *pos);

	// signal block and no wkq?
	/*
	 * it breaks RLIMIT_FSIZE and normal user's limit,
	 * users should care about quota and real 'filesystem full.'
	 */
	if (!is_aufsd(current)) {
		struct do_xino_fwrite_args args = {
			.errp	= &err,
			.func	= func,
			.file	= file,
			.buf	= buf,
			.size	= size,
			.pos	= pos
		};
		au_wkq_wait(call_do_xino_fwrite, &args, /*dlgt*/0);
	} else
Beispiel #10
0
static struct dentry *lkup_hash(const char *name, struct dentry *parent,
				int len, struct lkup_args *lkup)
{
	struct dentry *dentry;
	char *p;
	unsigned long hash;
	struct qstr this;
	unsigned int c;
	struct nameidata tmp_nd;

	dentry = ERR_PTR(-EACCES);
	this.name = name;
	this.len = len;
	if (unlikely(!len))
		goto out;

	p = (void*)name;
	hash = init_name_hash();
	while (len--) {
		c = *p++;
		if (unlikely(c == '/' || c == '\0'))
			goto out;
		hash = partial_name_hash(c, hash);
	}
	this.hash = end_name_hash(hash);

	memset(&tmp_nd, 0, sizeof(tmp_nd));
	tmp_nd.dentry = dget(parent);
	tmp_nd.mnt = mntget(lkup->nfsmnt);
#ifndef CONFIG_AUFS_DLGT
	dentry = __lookup_hash(&this, parent, &tmp_nd);
#else
	if (!lkup->dlgt)
		dentry = __lookup_hash(&this, parent, &tmp_nd);
	else {
		int wkq_err;
		struct lookup_hash_args args = {
			.errp	= &dentry,
			.name	= &this,
			.base	= parent,
			.nd	= &tmp_nd
		};
		wkq_err = au_wkq_wait(call_lookup_hash, &args, /*dlgt*/1);
		if (unlikely(wkq_err))
			dentry = ERR_PTR(wkq_err);
	}
#endif
	path_release(&tmp_nd);

 out:
	TraceErrPtr(dentry);
	return dentry;
}
#elif defined(CONFIG_AUFS_DLGT)
static struct dentry *lkup_hash(const char *name, struct dentry *parent,
				int len, struct lkup_args *lkup)
{
	return ERR_PTR(-ENOSYS);
}
#endif

#ifdef CONFIG_AUFS_DLGT
struct lookup_one_len_args {
	struct dentry **errp;
	const char *name;
	struct dentry *parent;
	int len;
};

static void call_lookup_one_len(void *args)
{
	struct lookup_one_len_args *a = args;
	*a->errp = lookup_one_len(a->name, a->parent, a->len);
}
#endif /* CONFIG_AUFS_DLGT */

#if defined(CONFIG_AUFS_LHASH_PATCH) || defined(CONFIG_AUFS_DLGT)
/* cf. lookup_one_len() in linux/fs/namei.c */
struct dentry *lkup_one(const char *name, struct dentry *parent, int len,
			struct lkup_args *lkup)
{
	struct dentry *dentry;

	LKTRTrace("%.*s/%.*s, lkup{%p, %d}\n",
		  DLNPair(parent), len, name, lkup->nfsmnt, lkup->dlgt);

	if (!lkup->nfsmnt) {
#ifndef CONFIG_AUFS_DLGT
		dentry = lookup_one_len(name, parent, len);
#else
		if (!lkup->dlgt)
			dentry = lookup_one_len(name, parent, len);
		else {
			int wkq_err;
			struct lookup_one_len_args args = {
				.errp	= &dentry,
				.name	= name,
				.parent	= parent,
				.len	= len
			};
			wkq_err = au_wkq_wait(call_lookup_one_len, &args,
					      /*dlgt*/1);
			if (unlikely(wkq_err))
				dentry = ERR_PTR(wkq_err);
		}
#endif
	} else
Beispiel #11
0
int aufs_rmdir(struct inode *dir, struct dentry *dentry)
{
	int err, rmdir_later;
	struct inode *inode, *hidden_dir;
	struct dentry *parent, *wh_dentry, *hidden_dentry, *hidden_parent;
	struct dtime dt;
	aufs_bindex_t bwh, bindex, bstart;
	struct rmdir_whtmp_arg *arg;
	struct aufs_nhash *whlist;

	LKTRTrace("i%lu, %.*s\n", dir->i_ino, DLNPair(dentry));
	IMustLock(dir);
	inode = dentry->d_inode;
	if (unlikely(!inode))
		return -ENOENT; // possible?
	IMustLock(inode);

	whlist = nhash_new(GFP_KERNEL);
	err = PTR_ERR(whlist);
	if (IS_ERR(whlist))
		goto out;

	err = -ENOMEM;
	arg = kmalloc(sizeof(*arg), GFP_KERNEL);
	//arg = NULL;
	if (unlikely(!arg))
		goto out_whlist;

	aufs_read_lock(dentry, AUFS_D_WLOCK);
	parent = dentry->d_parent;
	di_write_lock_parent(parent);
	err = test_empty(dentry, whlist);
	//err = -1;
	if (unlikely(err))
		goto out_arg;

	bstart = dbstart(dentry);
	bwh = dbwh(dentry);
	bindex = -1;
	wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/ 1, &bindex, &dt);
	//wh_dentry = ERR_PTR(-1);
	err = PTR_ERR(wh_dentry);
	if (IS_ERR(wh_dentry))
		goto out_arg;

	hidden_dentry = au_h_dptr(dentry);
	dget(hidden_dentry);
	hidden_parent = hidden_dentry->d_parent;
	hidden_dir = hidden_parent->d_inode;

	rmdir_later = 0;
	if (bindex == bstart) {
		IMustLock(hidden_dir);
		err = renwh_and_rmdir(dentry, bstart, whlist, dir);
		//err = -1;
		if (err > 0) {
			rmdir_later = err;
			err = 0;
		}
	} else {
		DEBUG_ON(!wh_dentry);
		hidden_parent = wh_dentry->d_parent;
		DEBUG_ON(hidden_parent != au_h_dptr_i(parent, bindex));
		hidden_dir = hidden_parent->d_inode;
		IMustLock(hidden_dir);
		err = 0;
	}

	if (!err) {
		au_reset_hinotify(inode, /*flags*/0);
		inode->i_nlink = 0;
		set_dbdiropq(dentry, -1);
		epilog(dir, dentry, bindex);

		if (rmdir_later) {
			kick_rmdir_whtmp(hidden_dentry, whlist, bstart, dir,
					 inode, arg);
			arg = NULL;
		}

		goto out_unlock; /* success */
	}

	/* revert */
	LKTRLabel(revert);
	if (wh_dentry) {
		int rerr;
		rerr = do_revert(err, wh_dentry, dentry, bwh, &dt,
				 need_dlgt(dir->i_sb));
		if (rerr)
			err = rerr;
	}

 out_unlock:
	hdir_unlock(hidden_dir, dir, bindex);
	dput(wh_dentry);
	dput(hidden_dentry);
 out_arg:
	di_write_unlock(parent);
	aufs_read_unlock(dentry, AUFS_D_WLOCK);
	kfree(arg);
 out_whlist:
	nhash_del(whlist);
 out:
	TraceErr(err);
	return err;
}
Beispiel #12
0
/* returns,
 * 0: wh is unnecessary
 * plus: wh is necessary
 * minus: error
 */
int wr_dir_need_wh(struct dentry *dentry, int isdir, aufs_bindex_t *bcpup,
		   struct dentry *locked)
{
	int need_wh, err;
	aufs_bindex_t bstart;
	struct dentry *hidden_dentry;
	struct super_block *sb;

	LKTRTrace("%.*s, isdir %d, *bcpup %d, locked %p\n",
		  DLNPair(dentry), isdir, *bcpup, locked);
	sb = dentry->d_sb;

	bstart = dbstart(dentry);
	LKTRTrace("bcpup %d, bstart %d\n", *bcpup, bstart);
	hidden_dentry = au_h_dptr(dentry);
	if (*bcpup < 0) {
		*bcpup = bstart;
		if (test_ro(sb, bstart, dentry->d_inode)) {
			*bcpup = err = find_rw_parent_br(dentry, bstart);
			//*bcpup = err = find_rw_br(sb, bstart);
			//err = -1;
			if (unlikely(err < 0))
				goto out;
		}
	} else
		DEBUG_ON(bstart < *bcpup
			 || test_ro(sb, *bcpup, dentry->d_inode));
	LKTRTrace("bcpup %d, bstart %d\n", *bcpup, bstart);

	if (*bcpup != bstart) {
		err = cpup_dirs(dentry, *bcpup, locked);
		//err = -1;
		if (unlikely(err))
			goto out;
		need_wh = 1;
	} else {
		//struct nameidata nd;
		aufs_bindex_t old_bend, new_bend, bdiropq = -1;
		old_bend = dbend(dentry);
		if (isdir) {
			bdiropq = dbdiropq(dentry);
			set_dbdiropq(dentry, -1);
		}
		err = need_wh = lkup_dentry(dentry, bstart + 1, /*type*/0);
		//err = -1;
		if (isdir)
			set_dbdiropq(dentry, bdiropq);
		if (unlikely(err < 0))
			goto out;
		new_bend = dbend(dentry);
		if (!need_wh && old_bend != new_bend) {
			set_h_dptr(dentry, new_bend, NULL);
			set_dbend(dentry, old_bend);
#if 0
		} else if (!au_h_dptr_i(dentry, new_bend)->d_inode) {
			LKTRTrace("negative\n");
			set_h_dptr(dentry, new_bend, NULL);
			set_dbend(dentry, old_bend);
			need_wh = 0;
#endif
		}
	}
	LKTRTrace("need_wh %d\n", need_wh);
	err = need_wh;

 out:
	TraceErr(err);
	return err;
}
Beispiel #13
0
int aufs_unlink(struct inode *dir, struct dentry *dentry)
{
	int err, dlgt;
	struct inode *inode, *hidden_dir;
	struct dentry *parent, *wh_dentry, *hidden_dentry, *hidden_parent;
	struct dtime dt;
	aufs_bindex_t bwh, bindex, bstart;

	LKTRTrace("i%lu, %.*s\n", dir->i_ino, DLNPair(dentry));
	IMustLock(dir);
	inode = dentry->d_inode;
	if (unlikely(!inode))
		return -ENOENT; // possible?
	IMustLock(inode);

	aufs_read_lock(dentry, AUFS_D_WLOCK);
	parent = dentry->d_parent;
	di_write_lock_parent(parent);

	bstart = dbstart(dentry);
	bwh = dbwh(dentry);
	bindex = -1;
	wh_dentry = lock_hdir_create_wh(dentry, /*isdir*/0, &bindex, &dt);
	//wh_dentry = ERR_PTR(-1);
	err = PTR_ERR(wh_dentry);
	if (IS_ERR(wh_dentry))
		goto out;

	dlgt = need_dlgt(dir->i_sb);
	hidden_dentry = au_h_dptr(dentry);
	dget(hidden_dentry);
	hidden_parent = hidden_dentry->d_parent;
	hidden_dir = hidden_parent->d_inode;

	if (bindex == bstart) {
		err = vfsub_unlink(hidden_dir, hidden_dentry, dlgt);
		//err = -1;
	} else {
		DEBUG_ON(!wh_dentry);
		hidden_parent = wh_dentry->d_parent;
		DEBUG_ON(hidden_parent != au_h_dptr_i(parent, bindex));
		hidden_dir = hidden_parent->d_inode;
		IMustLock(hidden_dir);
		err = 0;
	}

	if (!err) {
		inode->i_nlink--;
		epilog(dir, dentry, bindex);
		goto out_unlock; /* success */
	}

	/* revert */
	if (wh_dentry) {
		int rerr;
		rerr = do_revert(err, wh_dentry, dentry, bwh, &dt, dlgt);
		if (rerr)
			err = rerr;
	}

 out_unlock:
	hdir_unlock(hidden_dir, dir, bindex);
	dput(wh_dentry);
	dput(hidden_dentry);
 out:
	di_write_unlock(parent);
	aufs_read_unlock(dentry, AUFS_D_WLOCK);
	TraceErr(err);
	return err;
}
Beispiel #14
0
/*
 * prepare the @file for writing.
 */
int au_ready_to_write(struct file *file, loff_t len)
{
	int err;
	struct dentry *dentry, *parent, *hidden_dentry, *hidden_parent;
	struct inode *hidden_inode, *hidden_dir, *inode, *dir;
	struct super_block *sb;
	aufs_bindex_t bstart, bcpup;

	dentry = file->f_dentry;
	LKTRTrace("%.*s, len %Ld\n", DLNPair(dentry), len);
	FiMustWriteLock(file);

	sb = dentry->d_sb;
	bstart = fbstart(file);
	DEBUG_ON(ftobr(file, bstart) != stobr(sb, bstart));

	inode = dentry->d_inode;
	ii_read_lock_child(inode);
	LKTRTrace("rdonly %d, bstart %d\n", test_ro(sb, bstart, inode), bstart);
	err = test_ro(sb, bstart, inode);
	ii_read_unlock(inode);
	if (!err && (au_h_fptr(file)->f_mode & FMODE_WRITE))
		return 0;

	/* need to cpup */
	parent = dentry->d_parent; // dget_parent()
	di_write_lock_child(dentry);
	di_write_lock_parent(parent);
	bcpup = err = find_rw_parent_br(dentry, bstart);
	//bcpup = err = find_rw_br(sb, bstart);
	if (unlikely(err < 0))
		goto out_unlock;
	err = 0;

	hidden_parent = au_h_dptr_i(parent, bcpup);
	if (!hidden_parent) {
		err = cpup_dirs(dentry, bcpup, NULL);
		//if (LktrCond) err = -1;
		if (unlikely(err))
			goto out_unlock;
		hidden_parent = au_h_dptr_i(parent, bcpup);
	}

	hidden_dir = hidden_parent->d_inode;
	hidden_dentry = au_h_fptr(file)->f_dentry;
	hidden_inode = hidden_dentry->d_inode;
	dir = parent->d_inode;
	hdir_lock(hidden_dir, dir, bcpup);
	hi_lock_child(hidden_inode);
	if (d_unhashed(dentry) || d_unhashed(hidden_dentry)
	    /* || !hidden_inode->i_nlink */) {
		if (!au_test_perm(hidden_dir, MAY_EXEC | MAY_WRITE,
				  need_dlgt(sb)))
			err = cpup_wh_file(file, bcpup, len);
		else {
			struct cpup_wh_file_args args = {
				.errp	= &err,
				.file	= file,
				.bdst	= bcpup,
				.len	= len
			};
			au_wkq_wait(call_cpup_wh_file, &args, /*dlgt*/0);
		}
		//if (LktrCond) err = -1;
		TraceErr(err);
	} else {
		if (!au_h_dptr_i(dentry, bcpup))
Beispiel #15
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;
}
Beispiel #16
0
int au_do_open(struct inode *inode, struct file *file,
	       int (*open)(struct file *file, int flags))
{
	int err, coo;
	struct dentry *dentry;
	struct super_block *sb;
	aufs_bindex_t bstart;
	struct inode *h_dir, *dir;

	dentry = file->f_dentry;
	LKTRTrace("i%lu, %.*s\n", inode->i_ino, DLNPair(dentry));

	sb = dentry->d_sb;
	si_read_lock(sb);
	coo = 0;
#if 0
	switch (au_flag_test_coo(sb)) {
	case AuFlag_COO_LEAF:
		coo = !S_ISDIR(inode->i_mode);
		break;
	case AuFlag_COO_ALL:
		coo = 1;
		break;
	}
#endif
	err = au_init_finfo(file);
	//if (LktrCond) {fi_write_unlock(file); fin_finfo(file); err = -1;}
	if (unlikely(err))
		goto out;

	if (!coo) {
		di_read_lock_child(dentry, AUFS_I_RLOCK);
		bstart = dbstart(dentry);
	} else {
		di_write_lock_child(dentry);
		bstart = dbstart(dentry);
		if (test_ro(sb, bstart, dentry->d_inode)) {
			err = do_coo(dentry, bstart);
			if (err) {
				di_write_unlock(dentry);
				goto out_finfo;
			}
			bstart = dbstart(dentry);
		}
		di_downgrade_lock(dentry, AUFS_I_RLOCK);
	}

	// todo: remove this extra locks
	dir = dentry->d_parent->d_inode;
	if (!IS_ROOT(dentry))
		ii_read_lock_parent(dir);
	h_dir = au_h_iptr_i(dir, bstart);
	hdir_lock(h_dir, dir, bstart);
	err = open(file, file->f_flags);
	//if (LktrCond) err = -1;
	hdir_unlock(h_dir, dir, bstart);
	if (!IS_ROOT(dentry))
		ii_read_unlock(dir);
	di_read_unlock(dentry, AUFS_I_RLOCK);

 out_finfo:
	fi_write_unlock(file);
	if (unlikely(err))
		au_fin_finfo(file);
	//DbgFile(file);
 out:
	si_read_unlock(sb);
	TraceErr(err);
	return err;
}