static ssize_t aufs_aio_write_sp(struct kiocb *kio, const struct iovec *iov,
				 unsigned long nv, loff_t pos)
{
	ssize_t err;
	aufs_bindex_t bstart;
	unsigned char wbr;
	struct super_block *sb;
	struct file *file, *h_file;

	file = kio->ki_filp;
	sb = file->f_dentry->d_sb;
	si_read_lock(sb, AuLock_FLUSH);
	fi_read_lock(file);
	bstart = au_fbstart(file);
	h_file = au_hf_top(file);
	fi_read_unlock(file);
	wbr = !!au_br_writable(au_sbr(sb, bstart)->br_perm);
	si_read_unlock(sb);

	/* do not change the file in kio */
	AuDebugOn(!h_file->f_op || !h_file->f_op->aio_write);
	err = h_file->f_op->aio_write(kio, iov, nv, pos);
	if (err > 0 && wbr)
		file_update_time(h_file);

	return err;
}
Esempio n. 2
0
File: file.c Progetto: bojosos/linux
/*
 * after branch manipulating, refresh the file.
 */
static int refresh_file(struct file *file, int (*reopen)(struct file *file))
{
	int err, need_reopen;
	struct dentry *dentry;
	aufs_bindex_t bend, bindex;

	dentry = file->f_dentry;
	err = au_fi_realloc(au_fi(file), au_sbend(dentry->d_sb) + 1);
	if (unlikely(err))
		goto out;
	au_do_refresh_file(file);

	err = 0;
	need_reopen = 1;
	if (!au_test_mmapped(file))
		err = au_file_refresh_by_inode(file, &need_reopen);
	if (!err && need_reopen && !d_unhashed(dentry))
		err = reopen(file);
	if (!err) {
		au_update_figen(file);
		return 0; /* success */
	}

	/* error, close all lower files */
	bend = au_fbend(file);
	for (bindex = au_fbstart(file); bindex <= bend; bindex++)
		au_set_h_fptr(file, bindex, NULL);

 out:
	return err;
}
Esempio n. 3
0
File: file.c Progetto: bojosos/linux
int au_reopen_nondir(struct file *file)
{
	int err;
	aufs_bindex_t bstart, bindex, bend;
	struct dentry *dentry;
	struct file *h_file, *h_file_tmp;

	dentry = file->f_dentry;
	AuDebugOn(au_special_file(dentry->d_inode->i_mode));
	bstart = au_dbstart(dentry);
	h_file_tmp = NULL;
	if (au_fbstart(file) == bstart) {
		h_file = au_h_fptr(file, bstart);
		if (file->f_mode == h_file->f_mode)
			return 0; /* success */
		h_file_tmp = h_file;
		get_file(h_file_tmp);
		au_set_h_fptr(file, bstart, NULL);
	}
	AuDebugOn(au_fbstart(file) < bstart
		  || au_fi(file)->fi_hfile[0 + bstart].hf_file);

	h_file = au_h_open(dentry, bstart, vfsub_file_flags(file) & ~O_TRUNC,
			   file);
	err = PTR_ERR(h_file);
	if (IS_ERR(h_file))
		goto out; /* todo: close all? */

	err = 0;
	au_set_fbstart(file, bstart);
	au_set_h_fptr(file, bstart, h_file);
	au_update_figen(file);
	/* todo: necessary? */
	/* file->f_ra = h_file->f_ra; */

	/* close lower files */
	bend = au_fbend(file);
	for (bindex = bstart + 1; bindex <= bend; bindex++)
		au_set_h_fptr(file, bindex, NULL);
	au_set_fbend(file, bstart);

 out:
	if (h_file_tmp)
		fput(h_file_tmp);
	return err;
}
Esempio n. 4
0
int au_reopen_nondir(struct file *file)
{
	int err;
	aufs_bindex_t bstart;
	struct dentry *dentry;
	struct file *h_file, *h_file_tmp;

	dentry = file->f_dentry;
	AuDebugOn(au_special_file(dentry->d_inode->i_mode));
	bstart = au_dbstart(dentry);
	h_file_tmp = NULL;
	if (au_fbstart(file) == bstart) {
		h_file = au_hf_top(file);
		if (file->f_mode == h_file->f_mode)
			return 0; /* success */
		h_file_tmp = h_file;
		get_file(h_file_tmp);
		au_set_h_fptr(file, bstart, NULL);
	}
	AuDebugOn(au_fi(file)->fi_hdir);
	/*
	 * it can happen
	 * file exists on both of rw and ro
	 * open --> dbstart and fbstart are both 0
	 * prepend a branch as rw, "rw" become ro
	 * remove rw/file
	 * delete the top branch, "rw" becomes rw again
	 *	--> dbstart is 1, fbstart is still 0
	 * write --> fbstart is 0 but dbstart is 1
	 */
	/* AuDebugOn(au_fbstart(file) < bstart); */

	h_file = au_h_open(dentry, bstart, vfsub_file_flags(file) & ~O_TRUNC,
			   file, /*force_wr*/0);
	err = PTR_ERR(h_file);
	if (IS_ERR(h_file)) {
		if (h_file_tmp) {
			atomic_inc(&au_sbr(dentry->d_sb, bstart)->br_count);
			au_set_h_fptr(file, bstart, h_file_tmp);
			h_file_tmp = NULL;
		}
		goto out; /* todo: close all? */
	}

	err = 0;
	au_set_fbstart(file, bstart);
	au_set_h_fptr(file, bstart, h_file);
	au_update_figen(file);
	/* todo: necessary? */
	/* file->f_ra = h_file->f_ra; */

out:
	if (h_file_tmp)
		fput(h_file_tmp);
	return err;
}
Esempio n. 5
0
/* common function to regular file and dir */
int au_reval_and_lock_fdi(struct file *file, int (*reopen)(struct file *file),
			  int wlock)
{
	int err;
	unsigned int sigen, figen;
	aufs_bindex_t bstart;
	unsigned char pseudo_link;
	struct dentry *dentry;
	struct inode *inode;

	err = 0;
	dentry = file->f_dentry;
	inode = dentry->d_inode;
	AuDebugOn(au_special_file(inode->i_mode));
	sigen = au_sigen(dentry->d_sb);
	fi_write_lock(file);
	figen = au_figen(file);
	di_write_lock_child(dentry);
	bstart = au_dbstart(dentry);
	pseudo_link = (bstart != au_ibstart(inode));
	if (sigen == figen && !pseudo_link && au_fbstart(file) == bstart) {
		if (!wlock) {
			di_downgrade_lock(dentry, AuLock_IR);
			fi_downgrade_lock(file);
		}
		goto out; /* success */
	}

	AuDbg("sigen %d, figen %d\n", sigen, figen);
	if (sigen != au_digen(dentry)
	    || sigen != au_iigen(inode)) {
		err = au_reval_dpath(dentry, sigen);
		if (unlikely(err < 0))
			goto out;
		AuDebugOn(au_digen(dentry) != sigen
			  || au_iigen(inode) != sigen);
	}

	err = refresh_file(file, reopen);
	if (!err) {
		if (!wlock) {
			di_downgrade_lock(dentry, AuLock_IR);
			fi_downgrade_lock(file);
		}
	} else {
		di_write_unlock(dentry);
		fi_write_unlock(file);
	}

out:
	return err;
}
int au_reopen_nondir(struct file *file)
{
	int err;
	aufs_bindex_t bstart;
	struct dentry *dentry;
	struct file *h_file, *h_file_tmp;

	dentry = file->f_dentry;
	AuDebugOn(au_special_file(dentry->d_inode->i_mode));
	bstart = au_dbstart(dentry);
	h_file_tmp = NULL;
	if (au_fbstart(file) == bstart) {
		h_file = au_hf_top(file);
		if (file->f_mode == h_file->f_mode)
			return 0; /* success */
		h_file_tmp = h_file;
		get_file(h_file_tmp);
		au_set_h_fptr(file, bstart, NULL);
	}
	AuDebugOn(au_fi(file)->fi_hdir);
	AuDebugOn(au_fbstart(file) < bstart);

	h_file = au_h_open(dentry, bstart, file->f_flags & ~O_TRUNC, file);
	err = PTR_ERR(h_file);
	if (IS_ERR(h_file))
		goto out; /* todo: close all? */

	err = 0;
	au_set_fbstart(file, bstart);
	au_set_h_fptr(file, bstart, h_file);
	au_update_figen(file);
	/* todo: necessary? */
	/* file->f_ra = h_file->f_ra; */

out:
	if (h_file_tmp)
		fput(h_file_tmp);
	return err;
}
Esempio n. 7
0
static int aufs_release_sp(struct inode *inode, struct file *file)
{
	int err;
	struct file *h_file;

	fi_read_lock(file);
	h_file = au_h_fptr(file, au_fbstart(file));
	fi_read_unlock(file);
	/* close this fifo in aufs */
	err = h_file->f_op->release(inode, file); /* ignore */
	aufs_release_nondir(inode, file); /* ignore */
	return err;
}
Esempio n. 8
0
loff_t au_dir_size(struct file *file, struct dentry *dentry)
{
	loff_t sz;
	aufs_bindex_t bindex, bend;
	struct file *h_file;
	struct dentry *h_dentry;

	sz = 0;
	if (file) {
		AuDebugOn(!file->f_dentry);
		AuDebugOn(!file->f_dentry->d_inode);
		AuDebugOn(!S_ISDIR(file->f_dentry->d_inode->i_mode));

		bend = au_fbend_dir(file);
		for (bindex = au_fbstart(file);
		     bindex <= bend && sz < KMALLOC_MAX_SIZE;
		     bindex++) {
			h_file = au_hf_dir(file, bindex);
			if (h_file
			    && h_file->f_dentry
			    && h_file->f_dentry->d_inode)
				sz += i_size_read(h_file->f_dentry->d_inode);
		}
	} else {
		AuDebugOn(!dentry);
		AuDebugOn(!dentry->d_inode);
		AuDebugOn(!S_ISDIR(dentry->d_inode->i_mode));

		bend = au_dbtaildir(dentry);
		for (bindex = au_dbstart(dentry);
		     bindex <= bend && sz < KMALLOC_MAX_SIZE;
		     bindex++) {
			h_dentry = au_h_dptr(dentry, bindex);
			if (h_dentry && h_dentry->d_inode)
				sz += i_size_read(h_dentry->d_inode);
		}
	}
	if (sz < KMALLOC_MAX_SIZE)
		sz = roundup_pow_of_two(sz);
	if (sz > KMALLOC_MAX_SIZE)
		sz = KMALLOC_MAX_SIZE;
	else if (sz < NAME_MAX) {
		BUILD_BUG_ON(AUFS_RDBLK_DEF < NAME_MAX);
		sz = AUFS_RDBLK_DEF;
	}
	return sz;
}
Esempio n. 9
0
static int do_open_dir(struct file *file, int flags)
{
	int err;
	aufs_bindex_t bindex, btail;
	struct dentry *dentry, *h_dentry;
	struct file *h_file;

	FiMustWriteLock(file);

	dentry = file->f_dentry;
	err = au_alive_dir(dentry);
	if (unlikely(err))
		goto out;

	file->f_version = dentry->d_inode->i_version;
	bindex = au_dbstart(dentry);
	au_set_fbstart(file, bindex);
	btail = au_dbtaildir(dentry);
	au_set_fbend_dir(file, btail);
	for (; !err && bindex <= btail; bindex++) {
		h_dentry = au_h_dptr(dentry, bindex);
		if (!h_dentry)
			continue;

		h_file = au_h_open(dentry, bindex, flags, file);
		if (IS_ERR(h_file)) {
			err = PTR_ERR(h_file);
			break;
		}
		au_set_h_fptr(file, bindex, h_file);
	}
	au_update_figen(file);
	/* todo: necessary? */
	/* file->f_ra = h_file->f_ra; */
	if (!err)
		return 0; /* success */

	/* close all */
	for (bindex = au_fbstart(file); bindex <= btail; bindex++)
		au_set_h_fptr(file, bindex, NULL);
	au_set_fbstart(file, -1);
	au_set_fbend_dir(file, -1);

out:
	return err;
}
Esempio n. 10
0
/*
 * after branch manipulating, refresh the file.
 */
static int refresh_file(struct file *file, int (*reopen)(struct file *file))
{
	int err, need_reopen;
	aufs_bindex_t bend, bindex;
	struct dentry *dentry;
	struct au_finfo *finfo;
	struct au_hfile *hfile;

	dentry = file->f_dentry;
	finfo = au_fi(file);
	if (!finfo->fi_hdir) {
		hfile = &finfo->fi_htop;
		AuDebugOn(!hfile->hf_file);
		bindex = au_br_index(dentry->d_sb, hfile->hf_br->br_id);
		AuDebugOn(bindex < 0);
		if (bindex != finfo->fi_btop)
			au_set_fbstart(file, bindex);
	} else {
		err = au_fidir_realloc(finfo, au_sbend(dentry->d_sb) + 1);
		if (unlikely(err))
			goto out;
		au_do_refresh_dir(file);
	}

	err = 0;
	need_reopen = 1;
	if (!au_test_mmapped(file))
		err = au_file_refresh_by_inode(file, &need_reopen);
	if (!err && need_reopen && !d_unlinked(dentry))
		err = reopen(file);
	if (!err) {
		au_update_figen(file);
		goto out; /* success */
	}

	/* error, close all lower files */
	if (finfo->fi_hdir) {
		bend = au_fbend_dir(file);
		for (bindex = au_fbstart(file); bindex <= bend; bindex++)
			au_set_h_fptr(file, bindex, NULL);
	}

out:
	return err;
}
Esempio n. 11
0
static int reopen_dir(struct file *file)
{
	int err;
	unsigned int flags;
	aufs_bindex_t bindex, btail, bstart;
	struct dentry *dentry, *h_dentry;
	struct file *h_file;

	/* open all lower dirs */
	dentry = file->f_dentry;
	bstart = au_dbstart(dentry);
	for (bindex = au_fbstart(file); bindex < bstart; bindex++)
		au_set_h_fptr(file, bindex, NULL);
	au_set_fbstart(file, bstart);

	btail = au_dbtaildir(dentry);
	for (bindex = au_fbend_dir(file); btail < bindex; bindex--)
		au_set_h_fptr(file, bindex, NULL);
	au_set_fbend_dir(file, btail);

	flags = vfsub_file_flags(file);
	for (bindex = bstart; bindex <= btail; bindex++) {
		h_dentry = au_h_dptr(dentry, bindex);
		if (!h_dentry)
			continue;
		h_file = au_hf_dir(file, bindex);
		if (h_file)
			continue;

		h_file = au_h_open(dentry, bindex, flags, file);
		err = PTR_ERR(h_file);
		if (IS_ERR(h_file))
			goto out; /* close all? */
		au_set_h_fptr(file, bindex, h_file);
	}
	au_update_figen(file);
	/* todo: necessary? */
	/* file->f_ra = h_file->f_ra; */
	err = 0;

out:
	return err;
}
Esempio n. 12
0
void au_finfo_fin(struct file *file)
{
	struct au_finfo *finfo;
	aufs_bindex_t bindex, bend;

	fi_write_lock(file);
	bend = au_fbend(file);
	bindex = au_fbstart(file);
	if (bindex >= 0)
		/*
		 * calls fput() instead of filp_close(),
		 * since no dnotify or lock for the lower file.
		 */
		for (; bindex <= bend; bindex++)
			au_set_h_fptr(file, bindex, NULL);

	finfo = au_fi(file);
	au_dbg_verify_hf(finfo);
	kfree(finfo->fi_hfile);
	fi_write_unlock(file);
	AuRwDestroy(&finfo->fi_rwsem);
	au_cache_free_finfo(finfo);
}
Esempio n. 13
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, struct au_do_open_args *args)
{
	int err, no_lock = args->no_lock;
	struct dentry *dentry;
	struct au_finfo *finfo;

	if (!no_lock)
		err = au_finfo_init(file, args->fidir);
	else {
		lockdep_off();
		err = au_finfo_init(file, args->fidir);
		lockdep_on();
	}
	if (unlikely(err))
		goto out;

	dentry = file->f_dentry;
	AuDebugOn(IS_ERR_OR_NULL(dentry));
	if (!no_lock) {
		di_write_lock_child(dentry);
		err = au_cmoo(dentry);
		di_downgrade_lock(dentry, AuLock_IR);
		if (!err)
			err = args->open(file, vfsub_file_flags(file), NULL);
		di_read_unlock(dentry, AuLock_IR);
	} else {
		err = au_cmoo(dentry);
		if (!err)
			err = args->open(file, vfsub_file_flags(file),
					 args->h_file);
		if (!err && au_fbstart(file) != au_dbstart(dentry))
			/*
			 * cmoo happens after h_file was opened.
			 * need to refresh file later.
			 */
			atomic_dec(&au_fi(file)->fi_generation);
	}

	finfo = au_fi(file);
	if (!err) {
		finfo->fi_file = file;
		au_sphl_add(&finfo->fi_hlist,
			    &au_sbi(file->f_dentry->d_sb)->si_files);
	}
	if (!no_lock)
		fi_write_unlock(file);
	else {
		lockdep_off();
		fi_write_unlock(file);
		lockdep_on();
	}
	if (unlikely(err)) {
		finfo->fi_hdir = NULL;
		au_finfo_fin(file);
	}

out:
	return err;
}
Esempio n. 14
0
/*
 * prepare the @file for writing.
 */
int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin)
{
	int err;
	aufs_bindex_t bstart, bcpup, dbstart;
	struct dentry *dentry, *parent, *h_dentry;
	struct inode *h_inode, *inode;
	struct super_block *sb;
	struct file *h_file;

	dentry = file->f_dentry;
	sb = dentry->d_sb;
	inode = dentry->d_inode;
	AuDebugOn(au_special_file(inode->i_mode));
	bstart = au_fbstart(file);
	err = au_test_ro(sb, bstart, inode);
	if (!err && (au_hf_top(file)->f_mode & FMODE_WRITE)) {
		err = au_pin(pin, dentry, bstart, AuOpt_UDBA_NONE, /*flags*/0);
		goto out;
	}

	/* need to cpup or reopen */
	parent = dget_parent(dentry);
	di_write_lock_parent(parent);
	err = AuWbrCopyup(au_sbi(sb), dentry);
	bcpup = err;
	if (unlikely(err < 0))
		goto out_dgrade;
	err = 0;

	if (!d_unhashed(dentry) && !au_h_dptr(parent, bcpup)) {
		err = au_cpup_dirs(dentry, bcpup);
		if (unlikely(err))
			goto out_dgrade;
	}

	err = au_pin(pin, dentry, bcpup, AuOpt_UDBA_NONE,
		     AuPin_DI_LOCKED | AuPin_MNT_WRITE);
	if (unlikely(err))
		goto out_dgrade;

	h_dentry = au_hf_top(file)->f_dentry;
	h_inode = h_dentry->d_inode;
	dbstart = au_dbstart(dentry);
	if (dbstart <= bcpup) {
		h_dentry = au_h_dptr(dentry, bcpup);
		AuDebugOn(!h_dentry);
		h_inode = h_dentry->d_inode;
		AuDebugOn(!h_inode);
		bstart = bcpup;
	}

	if (dbstart <= bcpup		/* just reopen */
	    || !d_unhashed(dentry)	/* copyup and reopen */
		) {
		mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
		h_file = au_h_open_pre(dentry, bstart);
		if (IS_ERR(h_file)) {
			err = PTR_ERR(h_file);
			h_file = NULL;
		} else {
			di_downgrade_lock(parent, AuLock_IR);
			if (dbstart > bcpup)
				err = au_sio_cpup_simple(dentry, bcpup, len,
							 AuCpup_DTIME);
			if (!err)
				err = au_reopen_nondir(file);
		}
		mutex_unlock(&h_inode->i_mutex);
		au_h_open_post(dentry, bstart, h_file);
	} else {			/* copyup as wh and reopen */
		/*
		 * since writable hfsplus branch is not supported,
		 * h_open_pre/post() are unnecessary.
		 */
		mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
		err = au_ready_to_write_wh(file, len, bcpup);
		di_downgrade_lock(parent, AuLock_IR);
		mutex_unlock(&h_inode->i_mutex);
	}

	if (!err) {
		au_pin_set_parent_lflag(pin, /*lflag*/0);
		goto out_dput; /* success */
	}
	au_unpin(pin);
	goto out_unlock;

out_dgrade:
	di_downgrade_lock(parent, AuLock_IR);
out_unlock:
	di_read_unlock(parent, AuLock_IR);
out_dput:
	dput(parent);
out:
	return err;
}
Esempio n. 15
0
static int au_ready_to_write_wh(struct file *file, loff_t len,
				aufs_bindex_t bcpup, struct au_pin *pin)
{
	int err;
	struct inode *inode, *h_inode;
	struct dentry *h_dentry, *hi_wh;
	struct au_cp_generic cpg = {
		.dentry	= file->f_dentry,
		.bdst	= bcpup,
		.bsrc	= -1,
		.len	= len,
		.pin	= pin
	};

	au_update_dbstart(cpg.dentry);
	inode = cpg.dentry->d_inode;
	h_inode = NULL;
	if (au_dbstart(cpg.dentry) <= bcpup
	    && au_dbend(cpg.dentry) >= bcpup) {
		h_dentry = au_h_dptr(cpg.dentry, bcpup);
		if (h_dentry)
			h_inode = h_dentry->d_inode;
	}
	hi_wh = au_hi_wh(inode, bcpup);
	if (!hi_wh && !h_inode)
		err = au_sio_cpup_wh(&cpg, file);
	else
		/* already copied-up after unlink */
		err = au_reopen_wh(file, bcpup, hi_wh);

	if (!err
	    && inode->i_nlink > 1
	    && au_opt_test(au_mntflags(cpg.dentry->d_sb), PLINK))
		au_plink_append(inode, bcpup, au_h_dptr(cpg.dentry, bcpup));

	return err;
}

/*
 * prepare the @file for writing.
 */
int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin)
{
	int err;
	aufs_bindex_t dbstart;
	struct dentry *parent, *h_dentry;
	struct inode *inode;
	struct super_block *sb;
	struct file *h_file;
	struct au_cp_generic cpg = {
		.dentry	= file->f_dentry,
		.bdst	= -1,
		.bsrc	= -1,
		.len	= len,
		.pin	= pin,
		.flags	= AuCpup_DTIME
	};

	sb = cpg.dentry->d_sb;
	inode = cpg.dentry->d_inode;
	AuDebugOn(au_special_file(inode->i_mode));
	cpg.bsrc = au_fbstart(file);
	err = au_test_ro(sb, cpg.bsrc, inode);
	if (!err && (au_hf_top(file)->f_mode & FMODE_WRITE)) {
		err = au_pin(pin, cpg.dentry, cpg.bsrc, AuOpt_UDBA_NONE,
			     /*flags*/0);
		goto out;
	}

	/* need to cpup or reopen */
	parent = dget_parent(cpg.dentry);
	di_write_lock_parent(parent);
	err = AuWbrCopyup(au_sbi(sb), cpg.dentry);
	cpg.bdst = err;
	if (unlikely(err < 0))
		goto out_dgrade;
	err = 0;

	if (!d_unhashed(cpg.dentry) && !au_h_dptr(parent, cpg.bdst)) {
		err = au_cpup_dirs(cpg.dentry, cpg.bdst);
		if (unlikely(err))
			goto out_dgrade;
	}

	err = au_pin(pin, cpg.dentry, cpg.bdst, AuOpt_UDBA_NONE,
		     AuPin_DI_LOCKED | AuPin_MNT_WRITE);
	if (unlikely(err))
		goto out_dgrade;

	h_dentry = au_hf_top(file)->f_dentry;
	dbstart = au_dbstart(cpg.dentry);
	if (dbstart <= cpg.bdst) {
		h_dentry = au_h_dptr(cpg.dentry, cpg.bdst);
		AuDebugOn(!h_dentry);
		cpg.bsrc = cpg.bdst;
	}

	if (dbstart <= cpg.bdst		/* just reopen */
	    || !d_unhashed(cpg.dentry)	/* copyup and reopen */
		) {
		h_file = au_h_open_pre(cpg.dentry, cpg.bsrc, /*force_wr*/0);
		if (IS_ERR(h_file))
			err = PTR_ERR(h_file);
		else {
			di_downgrade_lock(parent, AuLock_IR);
			if (dbstart > cpg.bdst)
				err = au_sio_cpup_simple(&cpg);
			if (!err)
				err = au_reopen_nondir(file);
			au_h_open_post(cpg.dentry, cpg.bsrc, h_file);
		}
	} else {			/* copyup as wh and reopen */
		/*
		 * since writable hfsplus branch is not supported,
		 * h_open_pre/post() are unnecessary.
		 */
		err = au_ready_to_write_wh(file, len, cpg.bdst, pin);
		di_downgrade_lock(parent, AuLock_IR);
	}

	if (!err) {
		au_pin_set_parent_lflag(pin, /*lflag*/0);
		goto out_dput; /* success */
	}
	au_unpin(pin);
	goto out_unlock;

out_dgrade:
	di_downgrade_lock(parent, AuLock_IR);
out_unlock:
	di_read_unlock(parent, AuLock_IR);
out_dput:
	dput(parent);
out:
	return err;
}

/* ---------------------------------------------------------------------- */

int au_do_flush(struct file *file, fl_owner_t id,
		int (*flush)(struct file *file, fl_owner_t id))
{
	int err;
	struct super_block *sb;
	struct inode *inode;

	inode = file_inode(file);
	sb = inode->i_sb;
	si_noflush_read_lock(sb);
	fi_read_lock(file);
	ii_read_lock_child(inode);

	err = flush(file, id);
	au_cpup_attr_timesizes(inode);

	ii_read_unlock(inode);
	fi_read_unlock(file);
	si_read_unlock(sb);
	return err;
}
Esempio n. 16
0
static int au_rdu(struct file *file, struct aufs_rdu *rdu)
{
	int err;
	aufs_bindex_t bend;
	struct au_rdu_arg arg;
	struct dentry *dentry;
	struct inode *inode;
	struct file *h_file;
	struct au_rdu_cookie *cookie = &rdu->cookie;

	err = !access_ok(VERIFY_WRITE, rdu->ent.e, rdu->sz);
	if (unlikely(err)) {
		err = -EFAULT;
		AuTraceErr(err);
		goto out;
	}
	rdu->rent = 0;
	rdu->tail = rdu->ent;
	rdu->full = 0;
	arg.rdu = rdu;
	arg.ent = rdu->ent;
	arg.end = arg.ent.ul;
	arg.end += rdu->sz;

	err = -ENOTDIR;
	if (unlikely(!file->f_op || !file->f_op->readdir))
		goto out;

	err = security_file_permission(file, MAY_READ);
	AuTraceErr(err);
	if (unlikely(err))
		goto out;

	dentry = file->f_dentry;
	inode = dentry->d_inode;
#if 1
	mutex_lock(&inode->i_mutex);
#else
	err = mutex_lock_killable(&inode->i_mutex);
	AuTraceErr(err);
	if (unlikely(err))
		goto out;
#endif
	err = -ENOENT;
	if (unlikely(IS_DEADDIR(inode)))
		goto out_mtx;

	arg.sb = inode->i_sb;
	si_read_lock(arg.sb, AuLock_FLUSH);
	fi_read_lock(file);

	err = -EAGAIN;
	if (unlikely(au_ftest_rdu(cookie->flags, CONT)
		     && cookie->generation != au_figen(file)))
		goto out_unlock;

	err = 0;
	if (!rdu->blk) {
		rdu->blk = au_sbi(arg.sb)->si_rdblk;
		if (!rdu->blk)
			rdu->blk = au_dir_size(file, /*dentry*/NULL);
	}
	bend = au_fbstart(file);
	if (cookie->bindex < bend)
		cookie->bindex = bend;
	bend = au_fbend_dir(file);
	/* AuDbg("b%d, b%d\n", cookie->bindex, bend); */
	for (; !err && cookie->bindex <= bend;
	     cookie->bindex++, cookie->h_pos = 0) {
		h_file = au_hf_dir(file, cookie->bindex);
		if (!h_file)
			continue;

		au_fclr_rdu(cookie->flags, FULL);
		err = au_rdu_do(h_file, &arg);
		AuTraceErr(err);
		if (unlikely(au_ftest_rdu(cookie->flags, FULL) || err))
			break;
	}
	AuDbg("rent %llu\n", rdu->rent);

	if (!err && !au_ftest_rdu(cookie->flags, CONT)) {
		rdu->shwh = !!au_opt_test(au_sbi(arg.sb)->si_mntflags, SHWH);
		au_fset_rdu(cookie->flags, CONT);
		cookie->generation = au_figen(file);
	}

	ii_read_lock_child(inode);
	fsstack_copy_attr_atime(inode, au_h_iptr(inode, au_ibstart(inode)));
	ii_read_unlock(inode);

 out_unlock:
	fi_read_unlock(file);
	si_read_unlock(arg.sb);
 out_mtx:
	mutex_unlock(&inode->i_mutex);
 out:
	AuTraceErr(err);
	return err;
}
Esempio n. 17
0
File: file.c Progetto: bojosos/linux
/*
 * prepare the @file for writing.
 */
int au_ready_to_write(struct file *file, loff_t len, struct au_pin *pin)
{
	int err;
	aufs_bindex_t bstart, bcpup;
	struct dentry *dentry, *parent, *h_dentry;
	struct inode *h_inode, *inode;
	struct super_block *sb;

	dentry = file->f_dentry;
	sb = dentry->d_sb;
	inode = dentry->d_inode;
	AuDebugOn(au_special_file(inode->i_mode));
	bstart = au_fbstart(file);
	err = au_test_ro(sb, bstart, inode);
	if (!err && (au_h_fptr(file, bstart)->f_mode & FMODE_WRITE)) {
		err = au_pin(pin, dentry, bstart, AuOpt_UDBA_NONE, /*flags*/0);
		goto out;
	}

	/* need to cpup */
	parent = dget_parent(dentry);
	di_write_lock_parent(parent);
	err = AuWbrCopyup(au_sbi(sb), dentry);
	bcpup = err;
	if (unlikely(err < 0))
		goto out_dgrade;
	err = 0;

	if (!au_h_dptr(parent, bcpup)) {
		err = au_cpup_dirs(dentry, bcpup);
		if (unlikely(err))
			goto out_dgrade;
	}

	err = au_pin(pin, dentry, bcpup, AuOpt_UDBA_NONE,
		     AuPin_DI_LOCKED | AuPin_MNT_WRITE);
	if (unlikely(err))
		goto out_dgrade;

	h_dentry = au_h_fptr(file, bstart)->f_dentry;
	h_inode = h_dentry->d_inode;
	mutex_lock_nested(&h_inode->i_mutex, AuLsc_I_CHILD);
	if (d_unhashed(dentry) /* || d_unhashed(h_dentry) */
	    /* || !h_inode->i_nlink */) {
		err = au_ready_to_write_wh(file, len, bcpup);
		di_downgrade_lock(parent, AuLock_IR);
	} else {
		di_downgrade_lock(parent, AuLock_IR);
		if (!au_h_dptr(dentry, bcpup))
			err = au_sio_cpup_simple(dentry, bcpup, len,
						 AuCpup_DTIME);
		if (!err)
			err = au_reopen_nondir(file);
	}
	mutex_unlock(&h_inode->i_mutex);

	if (!err) {
		au_pin_set_parent_lflag(pin, /*lflag*/0);
		goto out_dput; /* success */
	}
	au_unpin(pin);
	goto out_unlock;

 out_dgrade:
	di_downgrade_lock(parent, AuLock_IR);
 out_unlock:
	di_read_unlock(parent, AuLock_IR);
 out_dput:
	dput(parent);
 out:
	return err;
}