示例#1
0
static int ovl_do_lookup(struct dentry *dentry)
{
	struct ovl_entry *oe;
	struct dentry *upperdir;
	struct dentry *lowerdir;
	struct dentry *upperdentry = NULL;
	struct dentry *lowerdentry = NULL;
	struct inode *inode = NULL;
	int err;

	err = -ENOMEM;
	oe = ovl_alloc_entry();
	if (!oe)
		goto out;

	upperdir = ovl_dentry_upper(dentry->d_parent);
	lowerdir = ovl_dentry_lower(dentry->d_parent);

	if (upperdir) {
		upperdentry = ovl_lookup_real(upperdir, &dentry->d_name);
		err = PTR_ERR(upperdentry);
		if (IS_ERR(upperdentry))
			goto out_put_dir;

		if (lowerdir && upperdentry &&
		    (S_ISLNK(upperdentry->d_inode->i_mode) ||
		     S_ISDIR(upperdentry->d_inode->i_mode))) {
			const struct cred *old_cred;
			struct cred *override_cred;

			err = -ENOMEM;
			override_cred = prepare_creds();
			if (!override_cred)
				goto out_dput_upper;

			/* CAP_SYS_ADMIN needed for getxattr */
			cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
			old_cred = override_creds(override_cred);

			if (ovl_is_opaquedir(upperdentry)) {
				oe->opaque = true;
			} else if (ovl_is_whiteout(upperdentry)) {
				dput(upperdentry);
				upperdentry = NULL;
				oe->opaque = true;
			}
			revert_creds(old_cred);
			put_cred(override_cred);
		}
	}
	if (lowerdir && !oe->opaque) {
		lowerdentry = ovl_lookup_real(lowerdir, &dentry->d_name);
		err = PTR_ERR(lowerdentry);
		if (IS_ERR(lowerdentry))
			goto out_dput_upper;
	}

	if (lowerdentry && upperdentry &&
	    (!S_ISDIR(upperdentry->d_inode->i_mode) ||
	     !S_ISDIR(lowerdentry->d_inode->i_mode))) {
		dput(lowerdentry);
		lowerdentry = NULL;
		oe->opaque = true;
	}

	if (lowerdentry || upperdentry) {
		struct dentry *realdentry;

		realdentry = upperdentry ? upperdentry : lowerdentry;
		err = -ENOMEM;
		inode = ovl_new_inode(dentry->d_sb, realdentry->d_inode->i_mode,
				      oe);
		if (!inode)
			goto out_dput;
		ovl_copyattr(realdentry->d_inode, inode);
	}

	if (upperdentry)
		oe->__upperdentry = dget(upperdentry);

	if (lowerdentry)
		oe->lowerdentry = lowerdentry;

	dentry->d_fsdata = oe;
	dentry->d_op = &ovl_dentry_operations;
	d_add(dentry, inode);

	return 0;

out_dput:
	dput(lowerdentry);
out_dput_upper:
	dput(upperdentry);
out_put_dir:
	kfree(oe);
out:
	return err;
}
示例#2
0
static int ovl_do_lookup(struct dentry *dentry)
{
	struct ovl_entry *oe;
	struct dentry *upperdir;
	struct dentry *lowerdir;
	struct dentry *upperdentry = NULL;
	struct dentry *lowerdentry = NULL;
	struct inode *inode = NULL;
	int err;

	err = -ENOMEM;
	oe = ovl_alloc_entry();
	if (!oe)
		goto out;

	upperdir = ovl_dentry_upper(dentry->d_parent);
	lowerdir = ovl_dentry_lower(dentry->d_parent);

	if (upperdir) {
		upperdentry = ovl_lookup_real(upperdir, &dentry->d_name);
		err = PTR_ERR(upperdentry);
		if (IS_ERR(upperdentry))
			goto out_put_dir;

		if (lowerdir && upperdentry) {
			if (ovl_is_whiteout(upperdentry)) {
				dput(upperdentry);
				upperdentry = NULL;
				oe->opaque = true;
			} else if (ovl_is_opaquedir(upperdentry)) {
				oe->opaque = true;
			}
		}
	}
	if (lowerdir && !oe->opaque) {
		lowerdentry = ovl_lookup_real(lowerdir, &dentry->d_name);
		err = PTR_ERR(lowerdentry);
		if (IS_ERR(lowerdentry))
			goto out_dput_upper;
	}

	if (lowerdentry && upperdentry &&
	    (!S_ISDIR(upperdentry->d_inode->i_mode) ||
	     !S_ISDIR(lowerdentry->d_inode->i_mode))) {
		dput(lowerdentry);
		lowerdentry = NULL;
		oe->opaque = true;
	}

	if (lowerdentry || upperdentry) {
		struct dentry *realdentry;

		realdentry = upperdentry ? upperdentry : lowerdentry;
		err = -ENOMEM;
		inode = ovl_new_inode(dentry->d_sb, realdentry->d_inode->i_mode,
				      oe);
		if (!inode)
			goto out_dput;
		ovl_copyattr(realdentry->d_inode, inode);
	}

	if (upperdentry)
		oe->__upperdentry = dget(upperdentry);

	if (lowerdentry)
		oe->lowerdentry = lowerdentry;

	dentry->d_fsdata = oe;
	dentry->d_op = &ovl_dentry_operations;
	d_add(dentry, inode);

	return 0;

out_dput:
	dput(lowerdentry);
out_dput_upper:
	dput(upperdentry);
out_put_dir:
	kfree(oe);
out:
	return err;
}