Commit 1b5dd298 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'vfs-6.19-rc1.fd_prepare.fs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull fd prepare updates from Christian Brauner:
 "This adds the FD_ADD() and FD_PREPARE() primitive. They simplify the
  common pattern of get_unused_fd_flags() + create file + fd_install()
  that is used extensively throughout the kernel and currently requires
  cumbersome cleanup paths.

  FD_ADD() - For simple cases where a file is installed immediately:

      fd = FD_ADD(O_CLOEXEC, vfio_device_open_file(device));
      if (fd < 0)
          vfio_device_put_registration(device);
      return fd;

  FD_PREPARE() - For cases requiring access to the fd or file, or
  additional work before publishing:

      FD_PREPARE(fdf, O_CLOEXEC, sync_file->file);
      if (fdf.err) {
          fput(sync_file->file);
          return fdf.err;
      }

      data.fence = fd_prepare_fd(fdf);
      if (copy_to_user((void __user *)arg, &data, sizeof(data)))
          return -EFAULT;

      return fd_publish(fdf);

  The primitives are centered around struct fd_prepare. FD_PREPARE()
  encapsulates all allocation and cleanup logic and must be followed by
  a call to fd_publish() which associates the fd with the file and
  installs it into the caller's fdtable. If fd_publish() isn't called,
  both are deallocated automatically. FD_ADD() is a shorthand that does
  fd_publish() immediately and never exposes the struct to the caller.

  I've implemented this in a way that it's compatible with the cleanup
  infrastructure while also being usable separately. IOW, it's centered
  around struct fd_prepare which is aliased to class_fd_prepare_t and so
  we can make use of all the basica guard infrastructure"

* tag 'vfs-6.19-rc1.fd_prepare.fs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (42 commits)
  io_uring: convert io_create_mock_file() to FD_PREPARE()
  file: convert replace_fd() to FD_PREPARE()
  vfio: convert vfio_group_ioctl_get_device_fd() to FD_ADD()
  tty: convert ptm_open_peer() to FD_ADD()
  ntsync: convert ntsync_obj_get_fd() to FD_PREPARE()
  media: convert media_request_alloc() to FD_PREPARE()
  hv: convert mshv_ioctl_create_partition() to FD_ADD()
  gpio: convert linehandle_create() to FD_PREPARE()
  pseries: port papr_rtas_setup_file_interface() to FD_ADD()
  pseries: convert papr_platform_dump_create_handle() to FD_ADD()
  spufs: convert spufs_gang_open() to FD_PREPARE()
  papr-hvpipe: convert papr_hvpipe_dev_create_handle() to FD_PREPARE()
  spufs: convert spufs_context_open() to FD_PREPARE()
  net/socket: convert __sys_accept4_file() to FD_ADD()
  net/socket: convert sock_map_fd() to FD_ADD()
  net/kcm: convert kcm_ioctl() to FD_PREPARE()
  net/handshake: convert handshake_nl_accept_doit() to FD_PREPARE()
  secretmem: convert memfd_secret() to FD_ADD()
  memfd: convert memfd_create() to FD_ADD()
  bpf: convert bpf_token_create() to FD_PREPARE()
  ...
parents ffbf700d 0512bf97
Loading
Loading
Loading
Loading
+10 −32
Original line number Diff line number Diff line
@@ -267,22 +267,11 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,

static int spufs_context_open(const struct path *path)
{
	int ret;
	struct file *filp;

	ret = get_unused_fd_flags(0);
	if (ret < 0)
		return ret;

	filp = dentry_open(path, O_RDONLY, current_cred());
	if (IS_ERR(filp)) {
		put_unused_fd(ret);
		return PTR_ERR(filp);
	}

	filp->f_op = &spufs_context_fops;
	fd_install(ret, filp);
	return ret;
	FD_PREPARE(fdf, 0, dentry_open(path, O_RDONLY, current_cred()));
	if (fdf.err)
		return fdf.err;
	fd_prepare_file(fdf)->f_op = &spufs_context_fops;
	return fd_publish(fdf);
}

static struct spu_context *
@@ -508,26 +497,15 @@ static const struct file_operations spufs_gang_fops = {

static int spufs_gang_open(const struct path *path)
{
	int ret;
	struct file *filp;

	ret = get_unused_fd_flags(0);
	if (ret < 0)
		return ret;

	/*
	 * get references for dget and mntget, will be released
	 * in error path of *_open().
	 */
	filp = dentry_open(path, O_RDONLY, current_cred());
	if (IS_ERR(filp)) {
		put_unused_fd(ret);
		return PTR_ERR(filp);
	}

	filp->f_op = &spufs_gang_fops;
	fd_install(ret, filp);
	return ret;
	FD_PREPARE(fdf, 0, dentry_open(path, O_RDONLY, current_cred()));
	if (fdf.err)
		return fdf.err;
	fd_prepare_file(fdf)->f_op = &spufs_gang_fops;
	return fd_publish(fdf);
}

static int spufs_create_gang(struct inode *inode,
+9 −30
Original line number Diff line number Diff line
@@ -479,10 +479,7 @@ static const struct file_operations papr_hvpipe_handle_ops = {

static int papr_hvpipe_dev_create_handle(u32 srcID)
{
	struct hvpipe_source_info *src_info;
	struct file *file;
	long err;
	int fd;
	struct hvpipe_source_info *src_info __free(kfree) = NULL;

	spin_lock(&hvpipe_src_list_lock);
	/*
@@ -506,20 +503,13 @@ static int papr_hvpipe_dev_create_handle(u32 srcID)
	src_info->tsk = current;
	init_waitqueue_head(&src_info->recv_wqh);

	fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
	if (fd < 0) {
		err = fd;
		goto free_buf;
	}

	file = anon_inode_getfile("[papr-hvpipe]",
			&papr_hvpipe_handle_ops, (void *)src_info,
			O_RDWR);
	if (IS_ERR(file)) {
		err = PTR_ERR(file);
		goto free_fd;
	}
	FD_PREPARE(fdf, O_RDONLY | O_CLOEXEC,
		   anon_inode_getfile("[papr-hvpipe]", &papr_hvpipe_handle_ops,
				      (void *)src_info, O_RDWR));
	if (fdf.err)
		return fdf.err;

	retain_and_null_ptr(src_info);
	spin_lock(&hvpipe_src_list_lock);
	/*
	 * If two processes are executing ioctl() for the same
@@ -528,22 +518,11 @@ static int papr_hvpipe_dev_create_handle(u32 srcID)
	 */
	if (hvpipe_find_source(srcID)) {
		spin_unlock(&hvpipe_src_list_lock);
		err = -EALREADY;
		goto free_file;
		return -EALREADY;
	}
	list_add(&src_info->list, &hvpipe_src_list);
	spin_unlock(&hvpipe_src_list_lock);

	fd_install(fd, file);
	return fd;

free_file:
	fput(file);
free_fd:
	put_unused_fd(fd);
free_buf:
	kfree(src_info);
	return err;
	return fd_publish(fdf);
}

/*
+8 −22
Original line number Diff line number Diff line
@@ -303,8 +303,6 @@ static long papr_platform_dump_create_handle(u64 dump_tag)
{
	struct ibm_platform_dump_params *params;
	u64 param_dump_tag;
	struct file *file;
	long err;
	int fd;

	/*
@@ -334,34 +332,22 @@ static long papr_platform_dump_create_handle(u64 dump_tag)
	params->dump_tag_lo = (u32)(dump_tag & 0x00000000ffffffffULL);
	params->status = RTAS_IBM_PLATFORM_DUMP_START;

	fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
	if (fd < 0) {
		err = fd;
		goto free_area;
	}

	file = anon_inode_getfile_fmode("[papr-platform-dump]",
	fd = FD_ADD(O_RDONLY | O_CLOEXEC,
		    anon_inode_getfile_fmode("[papr-platform-dump]",
					     &papr_platform_dump_handle_ops,
					     (void *)params, O_RDONLY,
				FMODE_LSEEK | FMODE_PREAD);
	if (IS_ERR(file)) {
		err = PTR_ERR(file);
		goto put_fd;
					     FMODE_LSEEK | FMODE_PREAD));
	if (fd < 0) {
		rtas_work_area_free(params->work_area);
		kfree(params);
		return fd;
	}

	fd_install(fd, file);

	list_add(&params->list, &platform_dump_list);

	pr_info("%s (%d) initiated platform dump for dump tag %llu\n",
		current->comm, current->pid, dump_tag);
	return fd;
put_fd:
	put_unused_fd(fd);
free_area:
	rtas_work_area_free(params->work_area);
	kfree(params);
	return err;
}

/*
+5 −22
Original line number Diff line number Diff line
@@ -205,35 +205,18 @@ long papr_rtas_setup_file_interface(struct papr_rtas_sequence *seq,
				char *name)
{
	const struct papr_rtas_blob *blob;
	struct file *file;
	long ret;
	int fd;

	blob = papr_rtas_retrieve(seq);
	if (IS_ERR(blob))
		return PTR_ERR(blob);

	fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
	if (fd < 0) {
		ret = fd;
		goto free_blob;
	}

	file = anon_inode_getfile_fmode(name, fops, (void *)blob,
			O_RDONLY, FMODE_LSEEK | FMODE_PREAD);
	if (IS_ERR(file)) {
		ret = PTR_ERR(file);
		goto put_fd;
	}

	fd_install(fd, file);
	return fd;

put_fd:
	put_unused_fd(fd);
free_blob:
	fd = FD_ADD(O_RDONLY | O_CLOEXEC,
		   anon_inode_getfile_fmode(name, fops, (void *)blob, O_RDONLY,
					    FMODE_LSEEK | FMODE_PREAD));
	if (fd < 0)
		papr_rtas_blob_free(blob);
	return ret;
	return fd;
}

/*
+1 −9
Original line number Diff line number Diff line
@@ -768,18 +768,10 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_export, "DMA_BUF");
 */
int dma_buf_fd(struct dma_buf *dmabuf, int flags)
{
	int fd;

	if (!dmabuf || !dmabuf->file)
		return -EINVAL;

	fd = get_unused_fd_flags(flags);
	if (fd < 0)
		return fd;

	fd_install(fd, dmabuf->file);

	return fd;
	return FD_ADD(flags, dmabuf->file);
}
EXPORT_SYMBOL_NS_GPL(dma_buf_fd, "DMA_BUF");

Loading