Exemplo n.º 1
0
/* 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, exec_flag;

	/* 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);
	h_file = ERR_PTR(-EACCES);
	exec_flag = flags & __FMODE_EXEC;
	if (exec_flag && (au_br_mnt(br)->mnt_flags & MNT_NOEXEC))
		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);
	if (!au_special_file(h_inode->i_mode))
		h_file = vfsub_dentry_open(&h_path, flags);
	else {
		/* this block depends upon the configuration */
		di_read_unlock(dentry, AuLock_IR);
		fi_write_unlock(file);
		si_read_unlock(sb);
		h_file = vfsub_dentry_open(&h_path, flags);
		si_noflush_read_lock(sb);
		fi_write_lock(file);
		di_read_lock_child(dentry, AuLock_IR);
	}
	if (IS_ERR(h_file))
		goto out_br;

	if (exec_flag) {
		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;
}
Exemplo n.º 2
0
static int au_mvd_args(const unsigned char dmsg, struct au_mvd_args *a)
{
    int err;
    struct au_branch *br;

    err = -EISDIR;
    if (unlikely(S_ISDIR(a->inode->i_mode)))
        goto out;

    err = -EINVAL;
    if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_UPPER))
        a->mvd_bsrc = au_ibstart(a->inode);
    else {
        a->mvd_bsrc = au_br_index(a->sb, a->mvd_src_brid);
        if (unlikely(a->mvd_bsrc < 0
                     || (a->mvd_bsrc < au_dbstart(a->dentry)
                         || au_dbend(a->dentry) < a->mvd_bsrc
                         || !au_h_dptr(a->dentry, a->mvd_bsrc))
                     || (a->mvd_bsrc < au_ibstart(a->inode)
                         || au_ibend(a->inode) < a->mvd_bsrc
                         || !au_h_iptr(a->inode, a->mvd_bsrc)))) {
            a->mvd_errno = EAU_MVDOWN_NOUPPER;
            AU_MVD_PR(dmsg, "no upper\n");
            goto out;
        }
    }
    if (unlikely(a->mvd_bsrc == au_sbend(a->sb))) {
        a->mvd_errno = EAU_MVDOWN_BOTTOM;
        AU_MVD_PR(dmsg, "on the bottom\n");
        goto out;
    }
    a->mvd_h_src_inode = au_h_iptr(a->inode, a->mvd_bsrc);
    br = au_sbr(a->sb, a->mvd_bsrc);
    err = au_br_rdonly(br);
    if (!(a->mvdown.flags & AUFS_MVDOWN_ROUPPER)) {
        if (unlikely(err))
            goto out;
    } else if (!(vfsub_native_ro(a->mvd_h_src_inode)
                 || IS_APPEND(a->mvd_h_src_inode))) {
        if (err)
            a->mvdown.flags |= AUFS_MVDOWN_ROUPPER_R;
        /* go on */
    } else
        goto out;

    err = -EINVAL;
    if (!(a->mvdown.flags & AUFS_MVDOWN_BRID_LOWER)) {
        a->mvd_bdst = find_lower_writable(a);
        if (unlikely(a->mvd_bdst < 0)) {
            a->mvd_errno = EAU_MVDOWN_BOTTOM;
            AU_MVD_PR(dmsg, "no writable lower branch\n");
            goto out;
        }
    } else {
        a->mvd_bdst = au_br_index(a->sb, a->mvd_dst_brid);
        if (unlikely(a->mvd_bdst < 0
                     || au_sbend(a->sb) < a->mvd_bdst)) {
            a->mvd_errno = EAU_MVDOWN_NOLOWERBR;
            AU_MVD_PR(dmsg, "no lower brid\n");
            goto out;
        }
    }

    err = au_mvd_args_busy(dmsg, a);
    if (!err)
        err = au_mvd_args_parent(dmsg, a);
    if (!err)
        err = au_mvd_args_intermediate(dmsg, a);
    if (!err)
        err = au_mvd_args_exist(dmsg, a);
    if (!err)
        AuDbg("b%d, b%d\n", a->mvd_bsrc, a->mvd_bdst);

out:
    AuTraceErr(err);
    return err;
}
Exemplo n.º 3
0
/* 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;
}