示例#1
0
文件: acl.c 项目: Lyude/linux
int orangefs_init_acl(struct inode *inode, struct inode *dir)
{
	struct posix_acl *default_acl, *acl;
	umode_t mode = inode->i_mode;
	struct iattr iattr;
	int error = 0;

	error = posix_acl_create(dir, &mode, &default_acl, &acl);
	if (error)
		return error;

	if (default_acl) {
		error = __orangefs_set_acl(inode, default_acl,
					   ACL_TYPE_DEFAULT);
		posix_acl_release(default_acl);
	}

	if (acl) {
		if (!error)
			error = __orangefs_set_acl(inode, acl, ACL_TYPE_ACCESS);
		posix_acl_release(acl);
	}

	/* If mode of the inode was changed, then do a forcible ->setattr */
	if (mode != inode->i_mode) {
		memset(&iattr, 0, sizeof iattr);
		inode->i_mode = mode;
		iattr.ia_mode = mode;
		iattr.ia_valid |= ATTR_MODE;
		orangefs_inode_setattr(inode, &iattr);
	}

	return error;
}
示例#2
0
/*
 * No need for i_mutex because the inode is not yet exposed to the VFS.
 */
int
xfs_inherit_acl(struct inode *inode, struct posix_acl *acl)
{
	umode_t mode = inode->i_mode;
	int error = 0, inherit = 0;

	if (S_ISDIR(inode->i_mode)) {
		error = xfs_set_acl(inode, ACL_TYPE_DEFAULT, acl);
		if (error)
			goto out;
	}

	error = posix_acl_create(&acl, GFP_KERNEL, &mode);
	if (error < 0)
		return error;

	/*
	 * If posix_acl_create returns a positive value we need to
	 * inherit a permission that can't be represented using the Unix
	 * mode bits and we actually need to set an ACL.
	 */
	if (error > 0)
		inherit = 1;

	error = xfs_set_mode(inode, mode);
	if (error)
		goto out;

	if (inherit)
		error = xfs_set_acl(inode, ACL_TYPE_ACCESS, acl);

out:
	posix_acl_release(acl);
	return error;
}
示例#3
0
文件: acl.c 项目: AshishNamdev/linux
int orangefs_init_acl(struct inode *inode, struct inode *dir)
{
	struct orangefs_inode_s *orangefs_inode = ORANGEFS_I(inode);
	struct posix_acl *default_acl, *acl;
	umode_t mode = inode->i_mode;
	int error = 0;

	ClearModeFlag(orangefs_inode);

	error = posix_acl_create(dir, &mode, &default_acl, &acl);
	if (error)
		return error;

	if (default_acl) {
		error = orangefs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
		posix_acl_release(default_acl);
	}

	if (acl) {
		if (!error)
			error = orangefs_set_acl(inode, acl, ACL_TYPE_ACCESS);
		posix_acl_release(acl);
	}

	/* If mode of the inode was changed, then do a forcible ->setattr */
	if (mode != inode->i_mode) {
		SetModeFlag(orangefs_inode);
		inode->i_mode = mode;
		orangefs_flush_inode(inode);
	}

	return error;
}
示例#4
0
int f2fs_init_acl(struct inode *inode, struct inode *dir)
{
	struct posix_acl *acl = NULL;
	struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
	int error = 0;

	if (!S_ISLNK(inode->i_mode)) {
		if (test_opt(sbi, POSIX_ACL)) {
			acl = f2fs_get_acl(dir, ACL_TYPE_DEFAULT);
			if (IS_ERR(acl))
				return PTR_ERR(acl);
		}
		if (!acl)
			inode->i_mode &= ~current_umask();
	}

	if (test_opt(sbi, POSIX_ACL) && acl) {

		if (S_ISDIR(inode->i_mode)) {
			error = f2fs_set_acl(inode, ACL_TYPE_DEFAULT, acl);
			if (error)
				goto cleanup;
		}
		error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
		if (error < 0)
			return error;
		if (error > 0)
			error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl);
	}
cleanup:
	posix_acl_release(acl);
	return error;
}
示例#5
0
文件: acl.c 项目: CSCLOG/beaglebone
int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir)
{
	struct posix_acl *acl = NULL;
	int rc = 0;

	if (S_ISLNK(inode->i_mode))
		return 0;

	acl = jfs_get_acl(dir, ACL_TYPE_DEFAULT);
	if (IS_ERR(acl))
		return PTR_ERR(acl);

	if (acl) {
		if (S_ISDIR(inode->i_mode)) {
			rc = jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, acl);
			if (rc)
				goto cleanup;
		}
		rc = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
		if (rc < 0)
			goto cleanup; /* posix_acl_release(NULL) is no-op */
		if (rc > 0)
			rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, acl);
cleanup:
		posix_acl_release(acl);
	} else
		inode->i_mode &= ~current_umask();

	JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) |
			       inode->i_mode;

	return rc;
}
示例#6
0
int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, umode_t *i_mode)
{
	struct posix_acl *acl;
	int rc;

	cache_no_acl(inode);

	if (S_ISLNK(*i_mode))
		return 0;	/* Symlink always has no-ACL */

	acl = jffs2_get_acl(dir_i, ACL_TYPE_DEFAULT);
	if (IS_ERR(acl))
		return PTR_ERR(acl);

	if (!acl) {
		*i_mode &= ~current_umask();
	} else {
		if (S_ISDIR(*i_mode))
			set_cached_acl(inode, ACL_TYPE_DEFAULT, acl);

		rc = posix_acl_create(&acl, GFP_KERNEL, i_mode);
		if (rc < 0)
			return rc;
		if (rc > 0)
			set_cached_acl(inode, ACL_TYPE_ACCESS, acl);

		posix_acl_release(acl);
	}
	return 0;
}
示例#7
0
文件: acl.c 项目: AshishNamdev/linux
/*
 * btrfs_init_acl is already generally called under fs_mutex, so the locking
 * stuff has been fixed to work with that.  If the locking stuff changes, we
 * need to re-evaluate the acl locking stuff.
 */
int btrfs_init_acl(struct btrfs_trans_handle *trans,
		   struct inode *inode, struct inode *dir)
{
	struct posix_acl *default_acl, *acl;
	int ret = 0;

	/* this happens with subvols */
	if (!dir)
		return 0;

	ret = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
	if (ret)
		return ret;

	if (default_acl) {
		ret = __btrfs_set_acl(trans, inode, default_acl,
				      ACL_TYPE_DEFAULT);
		posix_acl_release(default_acl);
	}

	if (acl) {
		if (!ret)
			ret = __btrfs_set_acl(trans, inode, acl,
					      ACL_TYPE_ACCESS);
		posix_acl_release(acl);
	}

	if (!default_acl && !acl)
		cache_no_acl(inode);
	return ret;
}
示例#8
0
文件: acl.c 项目: AshishNamdev/linux
int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir)
{
	struct posix_acl *default_acl, *acl;
	int rc = 0;

	rc = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
	if (rc)
		return rc;

	if (default_acl) {
		rc = __jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, default_acl);
		posix_acl_release(default_acl);
	}

	if (acl) {
		if (!rc)
			rc = __jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, acl);
		posix_acl_release(acl);
	}

	JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) |
			       inode->i_mode;

	return rc;
}
示例#9
0
/*
 * Initialize the ACLs of a new inode. Called from ext2_new_inode.
 *
 * dir->i_mutex: down
 * inode->i_mutex: up (access to inode is still exclusive)
 */
int
ext2_init_acl(struct inode *inode, struct inode *dir)
{
	struct posix_acl *acl = NULL;
	int error = 0;

	if (!S_ISLNK(inode->i_mode)) {
		if (test_opt(dir->i_sb, POSIX_ACL)) {
			acl = ext2_get_acl(dir, ACL_TYPE_DEFAULT);
			if (IS_ERR(acl))
				return PTR_ERR(acl);
		}
		if (!acl)
			inode->i_mode &= ~current_umask();
	}
	if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
		if (S_ISDIR(inode->i_mode)) {
			error = ext2_set_acl(inode, ACL_TYPE_DEFAULT, acl);
			if (error)
				goto cleanup;
		}
		error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
		if (error < 0)
			return error;
		if (error > 0) {
			/* This is an extended ACL */
			error = ext2_set_acl(inode, ACL_TYPE_ACCESS, acl);
		}
	}
cleanup:
       posix_acl_release(acl);
       return error;
}
示例#10
0
int v9fs_acl_mode(struct inode *dir, mode_t *modep,
		  struct posix_acl **dpacl, struct posix_acl **pacl)
{
	int retval = 0;
	mode_t mode = *modep;
	struct posix_acl *acl = NULL;

	if (!S_ISLNK(mode)) {
		acl = v9fs_get_cached_acl(dir, ACL_TYPE_DEFAULT);
		if (IS_ERR(acl))
			return PTR_ERR(acl);
		if (!acl)
			mode &= ~current_umask();
	}
	if (acl) {
		if (S_ISDIR(mode))
			*dpacl = posix_acl_dup(acl);
		retval = posix_acl_create(&acl, GFP_NOFS, &mode);
		if (retval < 0)
			return retval;
		if (retval > 0)
			*pacl = acl;
		else
			posix_acl_release(acl);
	}
	*modep  = mode;
	return 0;
}
示例#11
0
文件: posix_acl.c 项目: 020gzh/linux
int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir)
{
	int err = 0;
	struct posix_acl *default_acl, *acl;

	hfs_dbg(ACL_MOD,
		"[%s]: ino %lu, dir->ino %lu\n",
		__func__, inode->i_ino, dir->i_ino);

	if (S_ISLNK(inode->i_mode))
		return 0;

	err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
	if (err)
		return err;

	if (default_acl) {
		err = hfsplus_set_posix_acl(inode, default_acl,
					    ACL_TYPE_DEFAULT);
		posix_acl_release(default_acl);
	}

	if (acl) {
		if (!err)
			err = hfsplus_set_posix_acl(inode, acl,
						    ACL_TYPE_ACCESS);
		posix_acl_release(acl);
	}
	return err;
}
示例#12
0
/*
 * Initialize the ACLs of a new inode. If parent directory has default ACL,
 * then clone to new inode. Called from ocfs2_mknod.
 */
int ocfs2_init_acl(handle_t *handle,
		   struct inode *inode,
		   struct inode *dir,
		   struct buffer_head *di_bh,
		   struct buffer_head *dir_bh,
		   struct ocfs2_alloc_context *meta_ac,
		   struct ocfs2_alloc_context *data_ac)
{
	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
	struct posix_acl *acl = NULL;
	int ret = 0, ret2;
	umode_t mode;

	if (!S_ISLNK(inode->i_mode)) {
		if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) {
			acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT,
						   dir_bh);
			if (IS_ERR(acl))
				return PTR_ERR(acl);
		}
		if (!acl) {
			mode = inode->i_mode & ~current_umask();
			ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode);
			if (ret) {
				mlog_errno(ret);
				goto cleanup;
			}
		}
	}
	if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) {
		if (S_ISDIR(inode->i_mode)) {
			ret = ocfs2_set_acl(handle, inode, di_bh,
					    ACL_TYPE_DEFAULT, acl,
					    meta_ac, data_ac);
			if (ret)
				goto cleanup;
		}
		mode = inode->i_mode;
		ret = posix_acl_create(&acl, GFP_NOFS, &mode);
		if (ret < 0)
			return ret;

		ret2 = ocfs2_acl_set_mode(inode, di_bh, handle, mode);
		if (ret2) {
			mlog_errno(ret2);
			ret = ret2;
			goto cleanup;
		}
		if (ret > 0) {
			ret = ocfs2_set_acl(handle, inode,
					    di_bh, ACL_TYPE_ACCESS,
					    acl, meta_ac, data_ac);
		}
	}
cleanup:
	posix_acl_release(acl);
	return ret;
}
/* dir->i_mutex: locked,
 * inode is new and not released into the wild yet */
int
reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
			     struct inode *dir, struct dentry *dentry,
			     struct inode *inode)
{
	struct posix_acl *acl;
	int err = 0;

	/* ACLs only get applied to files and directories */
	if (S_ISLNK(inode->i_mode))
		return 0;

	/* ACLs can only be used on "new" objects, so if it's an old object
	 * there is nothing to inherit from */
	if (get_inode_sd_version(dir) == STAT_DATA_V1)
		goto apply_umask;

	/* Don't apply ACLs to objects in the .reiserfs_priv tree.. This
	 * would be useless since permissions are ignored, and a pain because
	 * it introduces locking cycles */
	if (IS_PRIVATE(dir)) {
		inode->i_flags |= S_PRIVATE;
		goto apply_umask;
	}

	acl = reiserfs_get_acl(dir, ACL_TYPE_DEFAULT);
	if (IS_ERR(acl))
		return PTR_ERR(acl);

	if (acl) {
		/* Copy the default ACL to the default ACL of a new directory */
		if (S_ISDIR(inode->i_mode)) {
			err = reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT,
					       acl);
			if (err)
				goto cleanup;
		}

		/* Now we reconcile the new ACL and the mode,
		   potentially modifying both */
		err = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
		if (err < 0)
			return err;

		/* If we need an ACL.. */
		if (err > 0)
			err = reiserfs_set_acl(th, inode, ACL_TYPE_ACCESS, acl);
	      cleanup:
		posix_acl_release(acl);
	} else {
	      apply_umask:
		/* no ACL, apply umask */
		inode->i_mode &= ~current_umask();
	}

	return err;
}
示例#14
0
/*
 * dir->i_mutex: locked,
 * inode is new and not released into the wild yet
 */
int
reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
			     struct inode *dir, struct dentry *dentry,
			     struct inode *inode)
{
	struct posix_acl *default_acl, *acl;
	int err = 0;

	/* ACLs only get applied to files and directories */
	if (S_ISLNK(inode->i_mode))
		return 0;

	/*
	 * ACLs can only be used on "new" objects, so if it's an old object
	 * there is nothing to inherit from
	 */
	if (get_inode_sd_version(dir) == STAT_DATA_V1)
		goto apply_umask;

	/*
	 * Don't apply ACLs to objects in the .reiserfs_priv tree.. This
	 * would be useless since permissions are ignored, and a pain because
	 * it introduces locking cycles
	 */
	if (IS_PRIVATE(dir)) {
		inode->i_flags |= S_PRIVATE;
		goto apply_umask;
	}

	err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
	if (err)
		return err;

	if (default_acl) {
		err = __reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT,
					 default_acl);
		posix_acl_release(default_acl);
	}
	if (acl) {
		if (!err)
			err = __reiserfs_set_acl(th, inode, ACL_TYPE_ACCESS,
						 acl);
		posix_acl_release(acl);
	}

	return err;

apply_umask:
	/* no ACL, apply umask */
	inode->i_mode &= ~current_umask();
	return err;
}
示例#15
0
int
zpl_init_acl(struct inode *ip, struct inode *dir)
{
	struct posix_acl *acl = NULL;
	int error = 0;

	if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIXACL)
		return (0);

	if (!S_ISLNK(ip->i_mode)) {
		if (ITOZSB(ip)->z_acl_type == ZFS_ACLTYPE_POSIXACL) {
			acl = zpl_get_acl(dir, ACL_TYPE_DEFAULT);
			if (IS_ERR(acl))
				return (PTR_ERR(acl));
		}

		if (!acl) {
			ip->i_mode &= ~current_umask();
			ip->i_ctime = current_fs_time(ITOZSB(ip)->z_sb);
			mark_inode_dirty(ip);
			return (0);
		}
	}

	if ((ITOZSB(ip)->z_acl_type == ZFS_ACLTYPE_POSIXACL) && acl) {
		umode_t mode;

		if (S_ISDIR(ip->i_mode)) {
			error = zpl_set_acl(ip, ACL_TYPE_DEFAULT, acl);
			if (error)
				goto out;
		}

		mode = ip->i_mode;
		error = posix_acl_create(&acl,GFP_KERNEL, &mode);
		if (error >= 0) {
			ip->i_mode = mode;
			mark_inode_dirty(ip);
			if (error > 0)
				error = zpl_set_acl(ip, ACL_TYPE_ACCESS, acl);
		}
	}
out:
	zpl_posix_acl_release(acl);

	return (error);
}
示例#16
0
/*
 * btrfs_init_acl is already generally called under fs_mutex, so the locking
 * stuff has been fixed to work with that.  If the locking stuff changes, we
 * need to re-evaluate the acl locking stuff.
 */
int btrfs_init_acl(struct btrfs_trans_handle *trans,
		   struct inode *inode, struct inode *dir)
{
	struct posix_acl *acl = NULL;
	int ret = 0;

	/* this happens with subvols */
	if (!dir)
		return 0;

	if (!S_ISLNK(inode->i_mode)) {
		if (IS_POSIXACL(dir)) {
			acl = btrfs_get_acl(dir, ACL_TYPE_DEFAULT);
			if (IS_ERR(acl))
				return PTR_ERR(acl);
		}

		if (!acl)
			inode->i_mode &= ~current_umask();
	}

	if (IS_POSIXACL(dir) && acl) {
		if (S_ISDIR(inode->i_mode)) {
			ret = btrfs_set_acl(trans, inode, acl,
					    ACL_TYPE_DEFAULT);
			if (ret)
				goto failed;
		}
		ret = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
		if (ret < 0)
			return ret;

		if (ret > 0) {
			/* we need an acl */
			ret = btrfs_set_acl(trans, inode, acl, ACL_TYPE_ACCESS);
		} else if (ret < 0) {
			cache_no_acl(inode);
		}
	} else {
		cache_no_acl(inode);
	}
failed:
	posix_acl_release(acl);

	return ret;
}
示例#17
0
int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode)
{
	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
	struct posix_acl *acl;
	umode_t mode = inode->i_mode;
	int error = 0;

	if (!sdp->sd_args.ar_posix_acl)
		return 0;
	if (S_ISLNK(inode->i_mode))
		return 0;

	acl = gfs2_get_acl(&dip->i_inode, ACL_TYPE_DEFAULT);
	if (IS_ERR(acl))
		return PTR_ERR(acl);
	if (!acl) {
		mode &= ~current_umask();
		if (mode != inode->i_mode)
			error = gfs2_set_mode(inode, mode);
		return error;
	}

	if (S_ISDIR(inode->i_mode)) {
		error = gfs2_acl_set(inode, ACL_TYPE_DEFAULT, acl);
		if (error)
			goto out;
	}

	error = posix_acl_create(&acl, GFP_NOFS, &mode);
	if (error < 0)
		return error;

	if (error == 0)
		goto munge;

	error = gfs2_acl_set(inode, ACL_TYPE_ACCESS, acl);
	if (error)
		goto out;
munge:
	error = gfs2_set_mode(inode, mode);
out:
	posix_acl_release(acl);
	return error;
}
示例#18
0
int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, umode_t *i_mode)
{
	struct posix_acl *default_acl, *acl;
	int rc;

	cache_no_acl(inode);

	rc = posix_acl_create(dir_i, i_mode, &default_acl, &acl);
	if (rc)
		return rc;

	if (default_acl) {
		set_cached_acl(inode, ACL_TYPE_DEFAULT, default_acl);
		posix_acl_release(default_acl);
	}
	if (acl) {
		set_cached_acl(inode, ACL_TYPE_ACCESS, acl);
		posix_acl_release(acl);
	}
	return 0;
}
示例#19
0
文件: acl.c 项目: AshishNamdev/linux
/*
 * Initialize the ACLs of a new inode. Called from ext2_new_inode.
 *
 * dir->i_mutex: down
 * inode->i_mutex: up (access to inode is still exclusive)
 */
int
ext2_init_acl(struct inode *inode, struct inode *dir)
{
	struct posix_acl *default_acl, *acl;
	int error;

	error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
	if (error)
		return error;

	if (default_acl) {
		error = ext2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
		posix_acl_release(default_acl);
	}
	if (acl) {
		if (!error)
			error = ext2_set_acl(inode, acl, ACL_TYPE_ACCESS);
		posix_acl_release(acl);
	}
	return error;
}
示例#20
0
int ceph_init_acl(struct dentry *dentry, struct inode *inode, struct inode *dir)
{
	struct posix_acl *default_acl, *acl;
	umode_t new_mode = inode->i_mode;
	int error;

	error = posix_acl_create(dir, &new_mode, &default_acl, &acl);
	if (error)
		return error;

	if (!default_acl && !acl) {
		cache_no_acl(inode);
		if (new_mode != inode->i_mode) {
			struct iattr newattrs = {
				.ia_mode = new_mode,
				.ia_valid = ATTR_MODE,
			};
			error = ceph_setattr(dentry, &newattrs);
		}
		return error;
	}
示例#21
0
文件: acl.c 项目: acton393/linux
/*
 * Initialize the ACLs of a new inode. Called from ext4_new_inode.
 *
 * dir->i_mutex: down
 * inode->i_mutex: up (access to inode is still exclusive)
 */
int
ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
{
	struct posix_acl *default_acl, *acl;
	int error;

	error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
	if (error)
		return error;

	if (default_acl) {
		error = __ext4_set_acl(handle, inode, ACL_TYPE_DEFAULT,
				       default_acl);
		posix_acl_release(default_acl);
	}
	if (acl) {
		if (!error)
			error = __ext4_set_acl(handle, inode, ACL_TYPE_ACCESS,
					       acl);
		posix_acl_release(acl);
	}
	return error;
}
示例#22
0
int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage)
{
	struct posix_acl *default_acl, *acl;
	int error = 0;

	error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
	if (error)
		return error;

	if (default_acl) {
		error = __f2fs_set_acl(inode, ACL_TYPE_DEFAULT, default_acl,
				       ipage);
		posix_acl_release(default_acl);
	}
	if (acl) {
		if (error)
			error = __f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl,
					       ipage);
		posix_acl_release(acl);
	}

	return error;
}
示例#23
0
int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage)
{
	struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
	struct posix_acl *acl = NULL;
	int error = 0;

	if (!S_ISLNK(inode->i_mode)) {
		if (test_opt(sbi, POSIX_ACL)) {
			acl = f2fs_get_acl(dir, ACL_TYPE_DEFAULT);
			if (IS_ERR(acl))
				return PTR_ERR(acl);
		}
#ifdef CONFIG_F2FS_ANDROID_EMULATION_SUPPORT
		if (!acl && !(test_opt(sbi, ANDROID_EMU) &&
				F2FS_I(inode)->i_advise & FADVISE_ANDROID_EMU))
#else
		if (!acl)
			inode->i_mode &= ~current_umask();
	}

	if (!test_opt(sbi, POSIX_ACL) || !acl)
		goto cleanup;

	if (S_ISDIR(inode->i_mode)) {
		error = f2fs_set_acl(inode, ACL_TYPE_DEFAULT, acl, ipage);
		if (error)
			goto cleanup;
	}
	error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
	if (error < 0)
		return error;
	if (error > 0)
		error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, ipage);
cleanup:
	posix_acl_release(acl);
	return error;
}
示例#24
0
/**
 * generic_acl_init  -  Take care of acl inheritance at @inode create time
 *
 * Files created inside a directory with a default ACL inherit the
 * directory's default ACL.
 */
int
generic_acl_init(struct inode *inode, struct inode *dir)
{
	struct posix_acl *acl = NULL;
	int error;

	if (!S_ISLNK(inode->i_mode))
		acl = get_cached_acl(dir, ACL_TYPE_DEFAULT);
	if (acl) {
		if (S_ISDIR(inode->i_mode))
			set_cached_acl(inode, ACL_TYPE_DEFAULT, acl);
		error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
		if (error < 0)
			return error;
		if (error > 0)
			set_cached_acl(inode, ACL_TYPE_ACCESS, acl);
	} else {
		inode->i_mode &= ~current_umask();
	}
	error = 0;

	posix_acl_release(acl);
	return error;
}
示例#25
0
文件: nfs3proc.c 项目: a342604203/nfs
static int
nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
{
    struct nfs3_linkargs	arg = {
        .fromfh		= NFS_FH(inode),
        .tofh		= NFS_FH(dir),
        .toname		= name->name,
        .tolen		= name->len
    };
    struct nfs3_linkres	res;
    struct rpc_message msg = {
        .rpc_proc	= &nfs3_procedures[NFS3PROC_LINK],
        .rpc_argp	= &arg,
        .rpc_resp	= &res,
    };
    int status = -ENOMEM;

    dprintk("NFS call  link %s\n", name->name);
    res.fattr = nfs_alloc_fattr();
    res.dir_attr = nfs_alloc_fattr();
    if (res.fattr == NULL || res.dir_attr == NULL)
        goto out;

    zql_control_test(NFS_SERVER(inode));
    status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
    nfs_post_op_update_inode(dir, res.dir_attr);
    nfs_post_op_update_inode(inode, res.fattr);
out:
    nfs_free_fattr(res.dir_attr);
    nfs_free_fattr(res.fattr);
    dprintk("NFS reply link: %d\n", status);
    return status;
}

static int
nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page,
                  unsigned int len, struct iattr *sattr)
{
    struct nfs3_createdata *data;
    int status = -ENOMEM;

    if (len > NFS3_MAXPATHLEN)
        return -ENAMETOOLONG;

    dprintk("NFS call  symlink %pd\n", dentry);

    data = nfs3_alloc_createdata();
    if (data == NULL)
        goto out;
    data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_SYMLINK];
    data->arg.symlink.fromfh = NFS_FH(dir);
    data->arg.symlink.fromname = dentry->d_name.name;
    data->arg.symlink.fromlen = dentry->d_name.len;
    data->arg.symlink.pages = &page;
    data->arg.symlink.pathlen = len;
    data->arg.symlink.sattr = sattr;

    zql_control_test(NFS_SERVER(dir));
    status = nfs3_do_create(dir, dentry, data);

    nfs3_free_createdata(data);
out:
    dprintk("NFS reply symlink: %d\n", status);
    return status;
}

static int
nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
{
    struct posix_acl *default_acl, *acl;
    struct nfs3_createdata *data;
    int status = -ENOMEM;

    dprintk("NFS call  mkdir %pd\n", dentry);

    data = nfs3_alloc_createdata();
    if (data == NULL)
        goto out;

    status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl);
    if (status)
        goto out;

    data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR];
    data->arg.mkdir.fh = NFS_FH(dir);
    data->arg.mkdir.name = dentry->d_name.name;
    data->arg.mkdir.len = dentry->d_name.len;
    data->arg.mkdir.sattr = sattr;

    zql_control_test(NFS_SERVER(dir));
    status = nfs3_do_create(dir, dentry, data);
    if (status != 0)
        goto out_release_acls;

    status = nfs3_proc_setacls(dentry->d_inode, acl, default_acl);

out_release_acls:
    posix_acl_release(acl);
    posix_acl_release(default_acl);
out:
    nfs3_free_createdata(data);
    dprintk("NFS reply mkdir: %d\n", status);
    return status;
}

static int
nfs3_proc_rmdir(struct inode *dir, struct qstr *name)
{
    struct nfs_fattr	*dir_attr;
    struct nfs3_diropargs	arg = {
        .fh		= NFS_FH(dir),
        .name		= name->name,
        .len		= name->len
    };
    struct rpc_message msg = {
        .rpc_proc	= &nfs3_procedures[NFS3PROC_RMDIR],
        .rpc_argp	= &arg,
    };
    int status = -ENOMEM;

    dprintk("NFS call  rmdir %s\n", name->name);
    dir_attr = nfs_alloc_fattr();
    if (dir_attr == NULL)
        goto out;

    msg.rpc_resp = dir_attr;
    zql_control_test(NFS_SERVER(dir));
    status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
    nfs_post_op_update_inode(dir, dir_attr);
    nfs_free_fattr(dir_attr);
out:
    dprintk("NFS reply rmdir: %d\n", status);
    return status;
}

/*
 * The READDIR implementation is somewhat hackish - we pass the user buffer
 * to the encode function, which installs it in the receive iovec.
 * The decode function itself doesn't perform any decoding, it just makes
 * sure the reply is syntactically correct.
 *
 * Also note that this implementation handles both plain readdir and
 * readdirplus.
 */
static int
nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
                  u64 cookie, struct page **pages, unsigned int count, int plus)
{
    struct inode		*dir = dentry->d_inode;
    __be32			*verf = NFS_I(dir)->cookieverf;
    struct nfs3_readdirargs	arg = {
        .fh		= NFS_FH(dir),
        .cookie		= cookie,
        .verf		= {verf[0], verf[1]},
        .plus		= plus,
        .count		= count,
        .pages		= pages
    };
    struct nfs3_readdirres	res = {
        .verf		= verf,
        .plus		= plus
    };
    struct rpc_message	msg = {
        .rpc_proc	= &nfs3_procedures[NFS3PROC_READDIR],
        .rpc_argp	= &arg,
        .rpc_resp	= &res,
        .rpc_cred	= cred
    };
    int status = -ENOMEM;

    if (plus)
        msg.rpc_proc = &nfs3_procedures[NFS3PROC_READDIRPLUS];

    dprintk("NFS call  readdir%s %d\n",
            plus? "plus" : "", (unsigned int) cookie);

    res.dir_attr = nfs_alloc_fattr();
    if (res.dir_attr == NULL)
        goto out;

    zql_control_test(NFS_SERVER(dir));
    status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);

    nfs_invalidate_atime(dir);
    nfs_refresh_inode(dir, res.dir_attr);

    nfs_free_fattr(res.dir_attr);
out:
    dprintk("NFS reply readdir%s: %d\n",
            plus? "plus" : "", status);
    return status;
}

static int
nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
                dev_t rdev)
{
    struct posix_acl *default_acl, *acl;
    struct nfs3_createdata *data;
    int status = -ENOMEM;

    dprintk("NFS call  mknod %pd %u:%u\n", dentry,
            MAJOR(rdev), MINOR(rdev));

    data = nfs3_alloc_createdata();
    if (data == NULL)
        goto out;

    status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl);
    if (status)
        goto out;

    data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKNOD];
    data->arg.mknod.fh = NFS_FH(dir);
    data->arg.mknod.name = dentry->d_name.name;
    data->arg.mknod.len = dentry->d_name.len;
    data->arg.mknod.sattr = sattr;
    data->arg.mknod.rdev = rdev;

    switch (sattr->ia_mode & S_IFMT) {
    case S_IFBLK:
        data->arg.mknod.type = NF3BLK;
        break;
    case S_IFCHR:
        data->arg.mknod.type = NF3CHR;
        break;
    case S_IFIFO:
        data->arg.mknod.type = NF3FIFO;
        break;
    case S_IFSOCK:
        data->arg.mknod.type = NF3SOCK;
        break;
    default:
        status = -EINVAL;
        goto out;
    }

    zql_control_test(NFS_SERVER(dir));
    status = nfs3_do_create(dir, dentry, data);
    if (status != 0)
        goto out_release_acls;

    status = nfs3_proc_setacls(dentry->d_inode, acl, default_acl);

out_release_acls:
    posix_acl_release(acl);
    posix_acl_release(default_acl);
out:
    nfs3_free_createdata(data);
    dprintk("NFS reply mknod: %d\n", status);
    return status;
}

static int
nfs3_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
                 struct nfs_fsstat *stat)
{
    struct rpc_message msg = {
        .rpc_proc	= &nfs3_procedures[NFS3PROC_FSSTAT],
        .rpc_argp	= fhandle,
        .rpc_resp	= stat,
    };
    int	status;

    dprintk("NFS call  fsstat\n");
    nfs_fattr_init(stat->fattr);
    zql_control_test(server);
    status = rpc_call_sync(server->client, &msg, 0);
    dprintk("NFS reply fsstat: %d\n", status);
    return status;
}

static int
do_proc_fsinfo(struct rpc_clnt *client, struct nfs_fh *fhandle,
               struct nfs_fsinfo *info)
{
    struct rpc_message msg = {
        .rpc_proc	= &nfs3_procedures[NFS3PROC_FSINFO],
        .rpc_argp	= fhandle,
        .rpc_resp	= info,
    };
    int	status;

    dprintk("NFS call  fsinfo\n");
    nfs_fattr_init(info->fattr);
    status = rpc_call_sync(client, &msg, 0);
    dprintk("NFS reply fsinfo: %d\n", status);
    return status;
}

/*
 * Bare-bones access to fsinfo: this is for nfs_get_root/nfs_get_sb via
 * nfs_create_server
 */
static int
nfs3_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
                 struct nfs_fsinfo *info)
{
    int	status;

    zql_control_test(server);
    status = do_proc_fsinfo(server->client, fhandle, info);
    if (status && server->nfs_client->cl_rpcclient != server->client)
        status = do_proc_fsinfo(server->nfs_client->cl_rpcclient, fhandle, info);
    return status;
}
示例#26
0
文件: nfs3proc.c 项目: a342604203/nfs
/*
 * Create a regular file.
 */
static int
nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
                 int flags)
{
    struct posix_acl *default_acl, *acl;
    struct nfs3_createdata *data;
    int status = -ENOMEM;

    dprintk("NFS call  create %pd\n", dentry);

    data = nfs3_alloc_createdata();
    if (data == NULL)
        goto out;

    data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_CREATE];
    data->arg.create.fh = NFS_FH(dir);
    data->arg.create.name = dentry->d_name.name;
    data->arg.create.len = dentry->d_name.len;
    data->arg.create.sattr = sattr;

    data->arg.create.createmode = NFS3_CREATE_UNCHECKED;
    if (flags & O_EXCL) {
        data->arg.create.createmode  = NFS3_CREATE_EXCLUSIVE;
        data->arg.create.verifier[0] = cpu_to_be32(jiffies);
        data->arg.create.verifier[1] = cpu_to_be32(current->pid);
    }

    status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl);
    if (status)
        goto out;

    zql_control_test(NFS_SERVER(dir));
    for (;;) {
        status = nfs3_do_create(dir, dentry, data);

        if (status != -ENOTSUPP)
            break;
        /* If the server doesn't support the exclusive creation
         * semantics, try again with simple 'guarded' mode. */
        switch (data->arg.create.createmode) {
        case NFS3_CREATE_EXCLUSIVE:
            data->arg.create.createmode = NFS3_CREATE_GUARDED;
            break;

        case NFS3_CREATE_GUARDED:
            data->arg.create.createmode = NFS3_CREATE_UNCHECKED;
            break;

        case NFS3_CREATE_UNCHECKED:
            goto out;
        }
        nfs_fattr_init(data->res.dir_attr);
        nfs_fattr_init(data->res.fattr);
    }

    if (status != 0)
        goto out_release_acls;

    /* When we created the file with exclusive semantics, make
     * sure we set the attributes afterwards. */
    if (data->arg.create.createmode == NFS3_CREATE_EXCLUSIVE) {
        dprintk("NFS call  setattr (post-create)\n");

        if (!(sattr->ia_valid & ATTR_ATIME_SET))
            sattr->ia_valid |= ATTR_ATIME;
        if (!(sattr->ia_valid & ATTR_MTIME_SET))
            sattr->ia_valid |= ATTR_MTIME;

        /* Note: we could use a guarded setattr here, but I'm
         * not sure this buys us anything (and I'd have
         * to revamp the NFSv3 XDR code) */
        status = nfs3_proc_setattr(dentry, data->res.fattr, sattr);
        nfs_post_op_update_inode(dentry->d_inode, data->res.fattr);
        dprintk("NFS reply setattr (post-create): %d\n", status);
        if (status != 0)
            goto out_release_acls;
    }

    status = nfs3_proc_setacls(dentry->d_inode, acl, default_acl);

out_release_acls:
    posix_acl_release(acl);
    posix_acl_release(default_acl);
out:
    nfs3_free_createdata(data);
    dprintk("NFS reply create: %d\n", status);
    return status;
}
示例#27
0
文件: xfs_iops.c 项目: luyanseu/linux
STATIC int
xfs_vn_mknod(
	struct inode	*dir,
	struct dentry	*dentry,
	umode_t		mode,
	dev_t		rdev)
{
	struct inode	*inode;
	struct xfs_inode *ip = NULL;
	struct posix_acl *default_acl, *acl;
	struct xfs_name	name;
	int		error;

	/*
	 * Irix uses Missed'em'V split, but doesn't want to see
	 * the upper 5 bits of (14bit) major.
	 */
	if (S_ISCHR(mode) || S_ISBLK(mode)) {
		if (unlikely(!sysv_valid_dev(rdev) || MAJOR(rdev) & ~0x1ff))
			return -EINVAL;
		rdev = sysv_encode_dev(rdev);
	} else {
		rdev = 0;
	}

	error = posix_acl_create(dir, &mode, &default_acl, &acl);
	if (error)
		return error;

	xfs_dentry_to_name(&name, dentry, mode);
	error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip);
	if (unlikely(error))
		goto out_free_acl;

	inode = VFS_I(ip);

	error = xfs_init_security(inode, dir, &dentry->d_name);
	if (unlikely(error))
		goto out_cleanup_inode;

#ifdef CONFIG_XFS_POSIX_ACL
	if (default_acl) {
		error = xfs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
		if (error)
			goto out_cleanup_inode;
	}
	if (acl) {
		error = xfs_set_acl(inode, acl, ACL_TYPE_ACCESS);
		if (error)
			goto out_cleanup_inode;
	}
#endif

	d_instantiate(dentry, inode);
 out_free_acl:
	if (default_acl)
		posix_acl_release(default_acl);
	if (acl)
		posix_acl_release(acl);
	return -error;

 out_cleanup_inode:
	xfs_cleanup_inode(dir, inode, dentry);
	goto out_free_acl;
}
示例#28
0
static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
		       struct gfs2_inode *ip, struct gfs2_diradd *da)
{
	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
	struct gfs2_alloc_parms ap = { .target = da->nr_blocks, };
	int error;

	if (da->nr_blocks) {
		error = gfs2_quota_lock_check(dip);
		if (error)
			goto fail_quota_locks;

		error = gfs2_inplace_reserve(dip, &ap);
		if (error)
			goto fail_quota_locks;

		error = gfs2_trans_begin(sdp, gfs2_trans_da_blks(dip, da, 2), 0);
		if (error)
			goto fail_ipreserv;
	} else {
		error = gfs2_trans_begin(sdp, RES_LEAF + 2 * RES_DINODE, 0);
		if (error)
			goto fail_quota_locks;
	}

	error = gfs2_dir_add(&dip->i_inode, name, ip, da);
	if (error)
		goto fail_end_trans;

fail_end_trans:
	gfs2_trans_end(sdp);
fail_ipreserv:
	gfs2_inplace_release(dip);
fail_quota_locks:
	gfs2_quota_unlock(dip);
	return error;
}

static int gfs2_initxattrs(struct inode *inode, const struct xattr *xattr_array,
		    void *fs_info)
{
	const struct xattr *xattr;
	int err = 0;

	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
		err = __gfs2_xattr_set(inode, xattr->name, xattr->value,
				       xattr->value_len, 0,
				       GFS2_EATYPE_SECURITY);
		if (err < 0)
			break;
	}
	return err;
}

static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip,
			      const struct qstr *qstr)
{
	return security_inode_init_security(&ip->i_inode, &dip->i_inode, qstr,
					    &gfs2_initxattrs, NULL);
}

/**
 * gfs2_create_inode - Create a new inode
 * @dir: The parent directory
 * @dentry: The new dentry
 * @file: If non-NULL, the file which is being opened
 * @mode: The permissions on the new inode
 * @dev: For device nodes, this is the device number
 * @symname: For symlinks, this is the link destination
 * @size: The initial size of the inode (ignored for directories)
 *
 * Returns: 0 on success, or error code
 */

static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
			     struct file *file,
			     umode_t mode, dev_t dev, const char *symname,
			     unsigned int size, int excl, int *opened)
{
	const struct qstr *name = &dentry->d_name;
	struct posix_acl *default_acl, *acl;
	struct gfs2_holder ghs[2];
	struct inode *inode = NULL;
	struct gfs2_inode *dip = GFS2_I(dir), *ip;
	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
	struct gfs2_glock *io_gl;
	struct dentry *d;
	int error;
	u32 aflags = 0;
	struct gfs2_diradd da = { .bh = NULL, };

	if (!name->len || name->len > GFS2_FNAMESIZE)
		return -ENAMETOOLONG;

	error = gfs2_rs_alloc(dip);
	if (error)
		return error;

	error = gfs2_rindex_update(sdp);
	if (error)
		return error;

	error = gfs2_glock_nq_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
	if (error)
		goto fail;

	error = create_ok(dip, name, mode);
	if (error)
		goto fail_gunlock;

	inode = gfs2_dir_search(dir, &dentry->d_name, !S_ISREG(mode) || excl);
	error = PTR_ERR(inode);
	if (!IS_ERR(inode)) {
		d = d_splice_alias(inode, dentry);
		error = PTR_ERR(d);
		if (IS_ERR(d)) {
			inode = ERR_CAST(d);
			goto fail_gunlock;
		}
		error = 0;
		if (file) {
			if (S_ISREG(inode->i_mode)) {
				WARN_ON(d != NULL);
				error = finish_open(file, dentry, gfs2_open_common, opened);
			} else {
				error = finish_no_open(file, d);
			}
		} else {
			dput(d);
		}
		gfs2_glock_dq_uninit(ghs);
		return error;
	} else if (error != -ENOENT) {
		goto fail_gunlock;
	}

	error = gfs2_diradd_alloc_required(dir, name, &da);
	if (error < 0)
		goto fail_gunlock;

	inode = new_inode(sdp->sd_vfs);
	error = -ENOMEM;
	if (!inode)
		goto fail_gunlock;

	error = posix_acl_create(dir, &mode, &default_acl, &acl);
	if (error)
		goto fail_free_vfs_inode;

	ip = GFS2_I(inode);
	error = gfs2_rs_alloc(ip);
	if (error)
		goto fail_free_acls;

	inode->i_mode = mode;
	set_nlink(inode, S_ISDIR(mode) ? 2 : 1);
	inode->i_rdev = dev;
	inode->i_size = size;
	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
	gfs2_set_inode_blocks(inode, 1);
	munge_mode_uid_gid(dip, inode);
	ip->i_goal = dip->i_goal;
	ip->i_diskflags = 0;
	ip->i_eattr = 0;
	ip->i_height = 0;
	ip->i_depth = 0;
	ip->i_entries = 0;

	switch(mode & S_IFMT) {
	case S_IFREG:
		if ((dip->i_diskflags & GFS2_DIF_INHERIT_JDATA) ||
		    gfs2_tune_get(sdp, gt_new_files_jdata))
			ip->i_diskflags |= GFS2_DIF_JDATA;
		gfs2_set_aops(inode);
		break;
	case S_IFDIR:
		ip->i_diskflags |= (dip->i_diskflags & GFS2_DIF_INHERIT_JDATA);
		ip->i_diskflags |= GFS2_DIF_JDATA;
		ip->i_entries = 2;
		break;
	}
	gfs2_set_inode_flags(inode);

	if ((GFS2_I(sdp->sd_root_dir->d_inode) == dip) ||
	    (dip->i_diskflags & GFS2_DIF_TOPDIR))
		aflags |= GFS2_AF_ORLOV;

	error = alloc_dinode(ip, aflags);
	if (error)
		goto fail_free_inode;

	error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl);
	if (error)
		goto fail_free_inode;

	ip->i_gl->gl_object = ip;
	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_SKIP, ghs + 1);
	if (error)
		goto fail_free_inode;

	error = gfs2_trans_begin(sdp, RES_DINODE, 0);
	if (error)
		goto fail_gunlock2;

	init_dinode(dip, ip, symname);
	gfs2_trans_end(sdp);

	error = gfs2_glock_get(sdp, ip->i_no_addr, &gfs2_iopen_glops, CREATE, &io_gl);
	if (error)
		goto fail_gunlock2;

	error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
	if (error)
		goto fail_gunlock2;

	ip->i_iopen_gh.gh_gl->gl_object = ip;
	gfs2_glock_put(io_gl);
	gfs2_set_iop(inode);
	insert_inode_hash(inode);

	if (default_acl) {
		error = gfs2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
		posix_acl_release(default_acl);
	}
	if (acl) {
		if (!error)
			error = gfs2_set_acl(inode, acl, ACL_TYPE_ACCESS);
		posix_acl_release(acl);
	}

	if (error)
		goto fail_gunlock3;

	error = gfs2_security_init(dip, ip, name);
	if (error)
		goto fail_gunlock3;

	error = link_dinode(dip, name, ip, &da);
	if (error)
		goto fail_gunlock3;

	mark_inode_dirty(inode);
	d_instantiate(dentry, inode);
	if (file) {
		*opened |= FILE_CREATED;
		error = finish_open(file, dentry, gfs2_open_common, opened);
	}
	gfs2_glock_dq_uninit(ghs);
	gfs2_glock_dq_uninit(ghs + 1);
	return error;

fail_gunlock3:
	gfs2_glock_dq_uninit(ghs + 1);
	if (ip->i_gl)
		gfs2_glock_put(ip->i_gl);
	goto fail_gunlock;

fail_gunlock2:
	gfs2_glock_dq_uninit(ghs + 1);
fail_free_inode:
	if (ip->i_gl)
		gfs2_glock_put(ip->i_gl);
	gfs2_rs_delete(ip, NULL);
fail_free_acls:
	if (default_acl)
		posix_acl_release(default_acl);
	if (acl)
		posix_acl_release(acl);
fail_free_vfs_inode:
	free_inode_nonrcu(inode);
	inode = NULL;
fail_gunlock:
	gfs2_dir_no_add(&da);
	gfs2_glock_dq_uninit(ghs);
	if (inode && !IS_ERR(inode)) {
		clear_nlink(inode);
		mark_inode_dirty(inode);
		set_bit(GIF_ALLOC_FAILED, &GFS2_I(inode)->i_flags);
		iput(inode);
	}
fail:
	return error;
}

/**
 * gfs2_create - Create a file
 * @dir: The directory in which to create the file
 * @dentry: The dentry of the new file
 * @mode: The mode of the new file
 *
 * Returns: errno
 */

static int gfs2_create(struct inode *dir, struct dentry *dentry,
		       umode_t mode, bool excl)
{
	return gfs2_create_inode(dir, dentry, NULL, S_IFREG | mode, 0, NULL, 0, excl, NULL);
}

/**
 * __gfs2_lookup - Look up a filename in a directory and return its inode
 * @dir: The directory inode
 * @dentry: The dentry of the new inode
 * @file: File to be opened
 * @opened: atomic_open flags
 *
 *
 * Returns: errno
 */

static struct dentry *__gfs2_lookup(struct inode *dir, struct dentry *dentry,
				    struct file *file, int *opened)
{
	struct inode *inode;
	struct dentry *d;
	struct gfs2_holder gh;
	struct gfs2_glock *gl;
	int error;

	inode = gfs2_lookupi(dir, &dentry->d_name, 0);
	if (!inode)
		return NULL;
	if (IS_ERR(inode))
		return ERR_CAST(inode);

	gl = GFS2_I(inode)->i_gl;
	error = gfs2_glock_nq_init(gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
	if (error) {
		iput(inode);
		return ERR_PTR(error);
	}

	d = d_splice_alias(inode, dentry);
	if (IS_ERR(d)) {
		gfs2_glock_dq_uninit(&gh);
		return d;
	}
	if (file && S_ISREG(inode->i_mode))
		error = finish_open(file, dentry, gfs2_open_common, opened);

	gfs2_glock_dq_uninit(&gh);
	if (error) {
		dput(d);
		return ERR_PTR(error);
	}
	return d;
}

static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry,
				  unsigned flags)
{
	return __gfs2_lookup(dir, dentry, NULL, NULL);
}

/**
 * gfs2_link - Link to a file
 * @old_dentry: The inode to link
 * @dir: Add link to this directory
 * @dentry: The name of the link
 *
 * Link the inode in "old_dentry" into the directory "dir" with the
 * name in "dentry".
 *
 * Returns: errno
 */

static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
		     struct dentry *dentry)
{
	struct gfs2_inode *dip = GFS2_I(dir);
	struct gfs2_sbd *sdp = GFS2_SB(dir);
	struct inode *inode = old_dentry->d_inode;
	struct gfs2_inode *ip = GFS2_I(inode);
	struct gfs2_holder ghs[2];
	struct buffer_head *dibh;
	struct gfs2_diradd da = { .bh = NULL, };
	int error;

	if (S_ISDIR(inode->i_mode))
		return -EPERM;

	error = gfs2_rs_alloc(dip);
	if (error)
		return error;

	gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);

	error = gfs2_glock_nq(ghs); /* parent */
	if (error)
		goto out_parent;

	error = gfs2_glock_nq(ghs + 1); /* child */
	if (error)
		goto out_child;

	error = -ENOENT;
	if (inode->i_nlink == 0)
		goto out_gunlock;

	error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC);
	if (error)
		goto out_gunlock;

	error = gfs2_dir_check(dir, &dentry->d_name, NULL);
	switch (error) {
	case -ENOENT:
		break;
	case 0:
		error = -EEXIST;
	default:
		goto out_gunlock;
	}

	error = -EINVAL;
	if (!dip->i_inode.i_nlink)
		goto out_gunlock;
	error = -EFBIG;
	if (dip->i_entries == (u32)-1)
		goto out_gunlock;
	error = -EPERM;
	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
		goto out_gunlock;
	error = -EINVAL;
	if (!ip->i_inode.i_nlink)
		goto out_gunlock;
	error = -EMLINK;
	if (ip->i_inode.i_nlink == (u32)-1)
		goto out_gunlock;

	error = gfs2_diradd_alloc_required(dir, &dentry->d_name, &da);
	if (error < 0)
		goto out_gunlock;

	if (da.nr_blocks) {
		struct gfs2_alloc_parms ap = { .target = da.nr_blocks, };
		error = gfs2_quota_lock_check(dip);
		if (error)
			goto out_gunlock;

		error = gfs2_inplace_reserve(dip, &ap);
		if (error)
			goto out_gunlock_q;

		error = gfs2_trans_begin(sdp, gfs2_trans_da_blks(dip, &da, 2), 0);
		if (error)
			goto out_ipres;
	} else {
		error = gfs2_trans_begin(sdp, 2 * RES_DINODE + RES_LEAF, 0);
		if (error)
			goto out_ipres;
	}

	error = gfs2_meta_inode_buffer(ip, &dibh);
	if (error)
		goto out_end_trans;

	error = gfs2_dir_add(dir, &dentry->d_name, ip, &da);
	if (error)
		goto out_brelse;

	gfs2_trans_add_meta(ip->i_gl, dibh);
	inc_nlink(&ip->i_inode);
	ip->i_inode.i_ctime = CURRENT_TIME;
	ihold(inode);
	d_instantiate(dentry, inode);
	mark_inode_dirty(inode);

out_brelse:
	brelse(dibh);
out_end_trans:
	gfs2_trans_end(sdp);
out_ipres:
	if (da.nr_blocks)
		gfs2_inplace_release(dip);
out_gunlock_q:
	if (da.nr_blocks)
		gfs2_quota_unlock(dip);
out_gunlock:
	gfs2_dir_no_add(&da);
	gfs2_glock_dq(ghs + 1);
out_child:
	gfs2_glock_dq(ghs);
out_parent:
	gfs2_holder_uninit(ghs);
	gfs2_holder_uninit(ghs + 1);
	return error;
}

/*
 * gfs2_unlink_ok - check to see that a inode is still in a directory
 * @dip: the directory
 * @name: the name of the file
 * @ip: the inode
 *
 * Assumes that the lock on (at least) @dip is held.
 *
 * Returns: 0 if the parent/child relationship is correct, errno if it isn't
 */

static int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
			  const struct gfs2_inode *ip)
{
	int error;

	if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode))
		return -EPERM;

	if ((dip->i_inode.i_mode & S_ISVTX) &&
	    !uid_eq(dip->i_inode.i_uid, current_fsuid()) &&
	    !uid_eq(ip->i_inode.i_uid, current_fsuid()) && !capable(CAP_FOWNER))
		return -EPERM;

	if (IS_APPEND(&dip->i_inode))
		return -EPERM;

	error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC);
	if (error)
		return error;

	error = gfs2_dir_check(&dip->i_inode, name, ip);
	if (error)
		return error;

	return 0;
}
示例#29
0
文件: dir.c 项目: Lyude/linux
static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
				    struct ovl_cattr *cattr)
{
	struct dentry *workdir = ovl_workdir(dentry);
	struct inode *wdir = workdir->d_inode;
	struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent);
	struct inode *udir = upperdir->d_inode;
	struct dentry *upper;
	struct dentry *newdentry;
	int err;
	struct posix_acl *acl, *default_acl;
	bool hardlink = !!cattr->hardlink;

	if (WARN_ON(!workdir))
		return -EROFS;

	if (!hardlink) {
		err = posix_acl_create(dentry->d_parent->d_inode,
				       &cattr->mode, &default_acl, &acl);
		if (err)
			return err;
	}

	err = ovl_lock_rename_workdir(workdir, upperdir);
	if (err)
		goto out;

	upper = lookup_one_len(dentry->d_name.name, upperdir,
			       dentry->d_name.len);
	err = PTR_ERR(upper);
	if (IS_ERR(upper))
		goto out_unlock;

	newdentry = ovl_create_temp(workdir, cattr);
	err = PTR_ERR(newdentry);
	if (IS_ERR(newdentry))
		goto out_dput;

	/*
	 * mode could have been mutilated due to umask (e.g. sgid directory)
	 */
	if (!hardlink &&
	    !S_ISLNK(cattr->mode) &&
	    newdentry->d_inode->i_mode != cattr->mode) {
		struct iattr attr = {
			.ia_valid = ATTR_MODE,
			.ia_mode = cattr->mode,
		};
		inode_lock(newdentry->d_inode);
		err = notify_change(newdentry, &attr, NULL);
		inode_unlock(newdentry->d_inode);
		if (err)
			goto out_cleanup;
	}
	if (!hardlink) {
		err = ovl_set_upper_acl(newdentry, XATTR_NAME_POSIX_ACL_ACCESS,
					acl);
		if (err)
			goto out_cleanup;

		err = ovl_set_upper_acl(newdentry, XATTR_NAME_POSIX_ACL_DEFAULT,
					default_acl);
		if (err)
			goto out_cleanup;
	}

	if (!hardlink && S_ISDIR(cattr->mode)) {
		err = ovl_set_opaque(dentry, newdentry);
		if (err)
			goto out_cleanup;

		err = ovl_do_rename(wdir, newdentry, udir, upper,
				    RENAME_EXCHANGE);
		if (err)
			goto out_cleanup;

		ovl_cleanup(wdir, upper);
	} else {
		err = ovl_do_rename(wdir, newdentry, udir, upper, 0);
		if (err)
			goto out_cleanup;
	}
	err = ovl_instantiate(dentry, inode, newdentry, hardlink);
	if (err)
		goto out_cleanup;
out_dput:
	dput(upper);
out_unlock:
	unlock_rename(workdir, upperdir);
out:
	if (!hardlink) {
		posix_acl_release(acl);
		posix_acl_release(default_acl);
	}
	return err;

out_cleanup:
	ovl_cleanup(wdir, newdentry);
	dput(newdentry);
	goto out_dput;
}

static int ovl_create_or_link(struct dentry *dentry, struct inode *inode,
			      struct ovl_cattr *attr, bool origin)
{
	int err;
	const struct cred *old_cred;
	struct cred *override_cred;
	struct dentry *parent = dentry->d_parent;

	err = ovl_copy_up(parent);
	if (err)
		return err;

	old_cred = ovl_override_creds(dentry->d_sb);

	/*
	 * When linking a file with copy up origin into a new parent, mark the
	 * new parent dir "impure".
	 */
	if (origin) {
		err = ovl_set_impure(parent, ovl_dentry_upper(parent));
		if (err)
			goto out_revert_creds;
	}

	err = -ENOMEM;
	override_cred = prepare_creds();
	if (override_cred) {
		override_cred->fsuid = inode->i_uid;
		override_cred->fsgid = inode->i_gid;
		if (!attr->hardlink) {
			err = security_dentry_create_files_as(dentry,
					attr->mode, &dentry->d_name, old_cred,
					override_cred);
			if (err) {
				put_cred(override_cred);
				goto out_revert_creds;
			}
		}
		put_cred(override_creds(override_cred));
		put_cred(override_cred);

		if (!ovl_dentry_is_whiteout(dentry))
			err = ovl_create_upper(dentry, inode, attr);
		else
			err = ovl_create_over_whiteout(dentry, inode, attr);
	}
out_revert_creds:
	revert_creds(old_cred);
	return err;
}
示例#30
0
int ceph_pre_init_acls(struct inode *dir, umode_t *mode,
                       struct ceph_acls_info *info)
{
    struct posix_acl *acl, *default_acl;
    size_t val_size1 = 0, val_size2 = 0;
    struct ceph_pagelist *pagelist = NULL;
    void *tmp_buf = NULL;
    int err;

    err = posix_acl_create(dir, mode, &default_acl, &acl);
    if (err)
        return err;

    if (acl) {
        int ret = posix_acl_equiv_mode(acl, mode);
        if (ret < 0)
            goto out_err;
        if (ret == 0) {
            posix_acl_release(acl);
            acl = NULL;
        }
    }

    if (!default_acl && !acl)
        return 0;

    if (acl)
        val_size1 = posix_acl_xattr_size(acl->a_count);
    if (default_acl)
        val_size2 = posix_acl_xattr_size(default_acl->a_count);

    err = -ENOMEM;
    tmp_buf = kmalloc(max(val_size1, val_size2), GFP_KERNEL);
    if (!tmp_buf)
        goto out_err;
    pagelist = kmalloc(sizeof(struct ceph_pagelist), GFP_KERNEL);
    if (!pagelist)
        goto out_err;
    ceph_pagelist_init(pagelist);

    err = ceph_pagelist_reserve(pagelist, PAGE_SIZE);
    if (err)
        goto out_err;

    ceph_pagelist_encode_32(pagelist, acl && default_acl ? 2 : 1);

    if (acl) {
        size_t len = strlen(XATTR_NAME_POSIX_ACL_ACCESS);
        err = ceph_pagelist_reserve(pagelist, len + val_size1 + 8);
        if (err)
            goto out_err;
        ceph_pagelist_encode_string(pagelist, XATTR_NAME_POSIX_ACL_ACCESS,
                                    len);
        err = posix_acl_to_xattr(&init_user_ns, acl,
                                 tmp_buf, val_size1);
        if (err < 0)
            goto out_err;
        ceph_pagelist_encode_32(pagelist, val_size1);
        ceph_pagelist_append(pagelist, tmp_buf, val_size1);
    }
    if (default_acl) {
        size_t len = strlen(XATTR_NAME_POSIX_ACL_DEFAULT);
        err = ceph_pagelist_reserve(pagelist, len + val_size2 + 8);
        if (err)
            goto out_err;
        err = ceph_pagelist_encode_string(pagelist,
                                          XATTR_NAME_POSIX_ACL_DEFAULT, len);
        err = posix_acl_to_xattr(&init_user_ns, default_acl,
                                 tmp_buf, val_size2);
        if (err < 0)
            goto out_err;
        ceph_pagelist_encode_32(pagelist, val_size2);
        ceph_pagelist_append(pagelist, tmp_buf, val_size2);
    }

    kfree(tmp_buf);

    info->acl = acl;
    info->default_acl = default_acl;
    info->pagelist = pagelist;
    return 0;

out_err:
    posix_acl_release(acl);
    posix_acl_release(default_acl);
    kfree(tmp_buf);
    if (pagelist)
        ceph_pagelist_release(pagelist);
    return err;
}