Exemple #1
0
/*
 * Ideally this function should call VFS:do_last() in order to keep all its
 * checkings. But it is very hard for aufs to regenerate several VFS internal
 * structure such as nameidata. This is a second (or third) best approach.
 * cf. linux/fs/namei.c:do_last(), lookup_open() and atomic_open().
 */
int vfsub_atomic_open(struct inode *dir, struct dentry *dentry,
		      struct vfsub_aopen_args *args, struct au_branch *br)
{
	int err;
	struct file *file = args->file;
	/* copied from linux/fs/namei.c:atomic_open() */
	struct dentry *const DENTRY_NOT_SET = (void *)-1UL;

	IMustLock(dir);
	AuDebugOn(!dir->i_op->atomic_open);

	err = au_br_test_oflag(args->open_flag, br);
	if (unlikely(err))
		goto out;

	args->file->f_path.dentry = DENTRY_NOT_SET;
	args->file->f_path.mnt = au_br_mnt(br);
	err = dir->i_op->atomic_open(dir, dentry, file, args->open_flag,
				     args->create_mode, args->opened);
	if (err >= 0) {
		/* some filesystems don't set FILE_CREATED while succeeded? */
		if (*args->opened & FILE_CREATED)
			fsnotify_create(dir, dentry);
	} else
		goto out;


	if (!err) {
		/* todo: call VFS:may_open() here */
		err = open_check_o_direct(file);
		/* todo: ima_file_check() too? */
		if (!err && (args->open_flag & __FMODE_EXEC))
			err = deny_write_access(file);
		if (unlikely(err))
			/* note that the file is created and still opened */
			goto out;
	}

	atomic_inc(&br->br_count);
	fsnotify_open(file);

out:
	return err;
}
/* common functions to regular file and dir */
struct file *au_h_open(struct dentry *dentry, aufs_bindex_t bindex, int flags,
		       struct file *file, int force_wr)
{
	struct file *h_file;
	struct dentry *h_dentry;
	struct inode *h_inode;
	struct super_block *sb;
	struct au_branch *br;
	struct path h_path;
	int err;

	/* a race condition can happen between open and unlink/rmdir */
	h_file = ERR_PTR(-ENOENT);
	h_dentry = au_h_dptr(dentry, bindex);
	if (au_test_nfsd() && !h_dentry)
		goto out;
	h_inode = h_dentry->d_inode;
	if (au_test_nfsd() && !h_inode)
		goto out;
	spin_lock(&h_dentry->d_lock);
	err = (!d_unhashed(dentry) && d_unlinked(h_dentry))
		|| !h_inode
		/* || !dentry->d_inode->i_nlink */
		;
	spin_unlock(&h_dentry->d_lock);
	if (unlikely(err))
		goto out;

	sb = dentry->d_sb;
	br = au_sbr(sb, bindex);
	err = au_br_test_oflag(flags, br);
	h_file = ERR_PTR(err);
	if (unlikely(err))
		goto out;

	/* drop flags for writing */
	if (au_test_ro(sb, bindex, dentry->d_inode)) {
		if (force_wr && !(flags & O_WRONLY))
			force_wr = 0;
		flags = au_file_roflags(flags);
		if (force_wr) {
			h_file = ERR_PTR(-EROFS);
			flags = au_file_roflags(flags);
			if (unlikely(vfsub_native_ro(h_inode)
				     || IS_APPEND(h_inode)))
				goto out;
			flags &= ~O_ACCMODE;
			flags |= O_WRONLY;
		}
	}
	flags &= ~O_CREAT;
	atomic_inc(&br->br_count);
	h_path.dentry = h_dentry;
	h_path.mnt = au_br_mnt(br);
	h_file = vfsub_dentry_open(&h_path, flags);
	if (IS_ERR(h_file))
		goto out_br;

	if (flags & __FMODE_EXEC) {
		err = deny_write_access(h_file);
		if (unlikely(err)) {
			fput(h_file);
			h_file = ERR_PTR(err);
			goto out_br;
		}
	}
	fsnotify_open(h_file);
	goto out; /* success */

out_br:
	atomic_dec(&br->br_count);
out:
	return h_file;
}