Skip to content

Commit 1b5dd29

Browse files
committed
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() ...
2 parents ffbf700 + 0512bf9 commit 1b5dd29

38 files changed

Lines changed: 509 additions & 876 deletions

arch/powerpc/platforms/cell/spufs/inode.c

Lines changed: 10 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -267,22 +267,11 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
267267

268268
static int spufs_context_open(const struct path *path)
269269
{
270-
int ret;
271-
struct file *filp;
272-
273-
ret = get_unused_fd_flags(0);
274-
if (ret < 0)
275-
return ret;
276-
277-
filp = dentry_open(path, O_RDONLY, current_cred());
278-
if (IS_ERR(filp)) {
279-
put_unused_fd(ret);
280-
return PTR_ERR(filp);
281-
}
282-
283-
filp->f_op = &spufs_context_fops;
284-
fd_install(ret, filp);
285-
return ret;
270+
FD_PREPARE(fdf, 0, dentry_open(path, O_RDONLY, current_cred()));
271+
if (fdf.err)
272+
return fdf.err;
273+
fd_prepare_file(fdf)->f_op = &spufs_context_fops;
274+
return fd_publish(fdf);
286275
}
287276

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

509498
static int spufs_gang_open(const struct path *path)
510499
{
511-
int ret;
512-
struct file *filp;
513-
514-
ret = get_unused_fd_flags(0);
515-
if (ret < 0)
516-
return ret;
517-
518500
/*
519501
* get references for dget and mntget, will be released
520502
* in error path of *_open().
521503
*/
522-
filp = dentry_open(path, O_RDONLY, current_cred());
523-
if (IS_ERR(filp)) {
524-
put_unused_fd(ret);
525-
return PTR_ERR(filp);
526-
}
527-
528-
filp->f_op = &spufs_gang_fops;
529-
fd_install(ret, filp);
530-
return ret;
504+
FD_PREPARE(fdf, 0, dentry_open(path, O_RDONLY, current_cred()));
505+
if (fdf.err)
506+
return fdf.err;
507+
fd_prepare_file(fdf)->f_op = &spufs_gang_fops;
508+
return fd_publish(fdf);
531509
}
532510

533511
static int spufs_create_gang(struct inode *inode,

arch/powerpc/platforms/pseries/papr-hvpipe.c

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -479,10 +479,7 @@ static const struct file_operations papr_hvpipe_handle_ops = {
479479

480480
static int papr_hvpipe_dev_create_handle(u32 srcID)
481481
{
482-
struct hvpipe_source_info *src_info;
483-
struct file *file;
484-
long err;
485-
int fd;
482+
struct hvpipe_source_info *src_info __free(kfree) = NULL;
486483

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

509-
fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
510-
if (fd < 0) {
511-
err = fd;
512-
goto free_buf;
513-
}
514-
515-
file = anon_inode_getfile("[papr-hvpipe]",
516-
&papr_hvpipe_handle_ops, (void *)src_info,
517-
O_RDWR);
518-
if (IS_ERR(file)) {
519-
err = PTR_ERR(file);
520-
goto free_fd;
521-
}
506+
FD_PREPARE(fdf, O_RDONLY | O_CLOEXEC,
507+
anon_inode_getfile("[papr-hvpipe]", &papr_hvpipe_handle_ops,
508+
(void *)src_info, O_RDWR));
509+
if (fdf.err)
510+
return fdf.err;
522511

512+
retain_and_null_ptr(src_info);
523513
spin_lock(&hvpipe_src_list_lock);
524514
/*
525515
* If two processes are executing ioctl() for the same
@@ -528,22 +518,11 @@ static int papr_hvpipe_dev_create_handle(u32 srcID)
528518
*/
529519
if (hvpipe_find_source(srcID)) {
530520
spin_unlock(&hvpipe_src_list_lock);
531-
err = -EALREADY;
532-
goto free_file;
521+
return -EALREADY;
533522
}
534523
list_add(&src_info->list, &hvpipe_src_list);
535524
spin_unlock(&hvpipe_src_list_lock);
536-
537-
fd_install(fd, file);
538-
return fd;
539-
540-
free_file:
541-
fput(file);
542-
free_fd:
543-
put_unused_fd(fd);
544-
free_buf:
545-
kfree(src_info);
546-
return err;
525+
return fd_publish(fdf);
547526
}
548527

549528
/*

arch/powerpc/platforms/pseries/papr-platform-dump.c

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -303,8 +303,6 @@ static long papr_platform_dump_create_handle(u64 dump_tag)
303303
{
304304
struct ibm_platform_dump_params *params;
305305
u64 param_dump_tag;
306-
struct file *file;
307-
long err;
308306
int fd;
309307

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

337-
fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
335+
fd = FD_ADD(O_RDONLY | O_CLOEXEC,
336+
anon_inode_getfile_fmode("[papr-platform-dump]",
337+
&papr_platform_dump_handle_ops,
338+
(void *)params, O_RDONLY,
339+
FMODE_LSEEK | FMODE_PREAD));
338340
if (fd < 0) {
339-
err = fd;
340-
goto free_area;
341-
}
342-
343-
file = anon_inode_getfile_fmode("[papr-platform-dump]",
344-
&papr_platform_dump_handle_ops,
345-
(void *)params, O_RDONLY,
346-
FMODE_LSEEK | FMODE_PREAD);
347-
if (IS_ERR(file)) {
348-
err = PTR_ERR(file);
349-
goto put_fd;
341+
rtas_work_area_free(params->work_area);
342+
kfree(params);
343+
return fd;
350344
}
351345

352-
fd_install(fd, file);
353-
354346
list_add(&params->list, &platform_dump_list);
355347

356348
pr_info("%s (%d) initiated platform dump for dump tag %llu\n",
357349
current->comm, current->pid, dump_tag);
358350
return fd;
359-
put_fd:
360-
put_unused_fd(fd);
361-
free_area:
362-
rtas_work_area_free(params->work_area);
363-
kfree(params);
364-
return err;
365351
}
366352

367353
/*

arch/powerpc/platforms/pseries/papr-rtas-common.c

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -205,35 +205,18 @@ long papr_rtas_setup_file_interface(struct papr_rtas_sequence *seq,
205205
char *name)
206206
{
207207
const struct papr_rtas_blob *blob;
208-
struct file *file;
209-
long ret;
210208
int fd;
211209

212210
blob = papr_rtas_retrieve(seq);
213211
if (IS_ERR(blob))
214212
return PTR_ERR(blob);
215213

216-
fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
217-
if (fd < 0) {
218-
ret = fd;
219-
goto free_blob;
220-
}
221-
222-
file = anon_inode_getfile_fmode(name, fops, (void *)blob,
223-
O_RDONLY, FMODE_LSEEK | FMODE_PREAD);
224-
if (IS_ERR(file)) {
225-
ret = PTR_ERR(file);
226-
goto put_fd;
227-
}
228-
229-
fd_install(fd, file);
214+
fd = FD_ADD(O_RDONLY | O_CLOEXEC,
215+
anon_inode_getfile_fmode(name, fops, (void *)blob, O_RDONLY,
216+
FMODE_LSEEK | FMODE_PREAD));
217+
if (fd < 0)
218+
papr_rtas_blob_free(blob);
230219
return fd;
231-
232-
put_fd:
233-
put_unused_fd(fd);
234-
free_blob:
235-
papr_rtas_blob_free(blob);
236-
return ret;
237220
}
238221

239222
/*

drivers/dma-buf/dma-buf.c

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -768,18 +768,10 @@ EXPORT_SYMBOL_NS_GPL(dma_buf_export, "DMA_BUF");
768768
*/
769769
int dma_buf_fd(struct dma_buf *dmabuf, int flags)
770770
{
771-
int fd;
772-
773771
if (!dmabuf || !dmabuf->file)
774772
return -EINVAL;
775773

776-
fd = get_unused_fd_flags(flags);
777-
if (fd < 0)
778-
return fd;
779-
780-
fd_install(fd, dmabuf->file);
781-
782-
return fd;
774+
return FD_ADD(flags, dmabuf->file);
783775
}
784776
EXPORT_SYMBOL_NS_GPL(dma_buf_fd, "DMA_BUF");
785777

drivers/gpio/gpiolib-cdev.c

Lines changed: 21 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -298,12 +298,13 @@ static const struct file_operations linehandle_fileops = {
298298
#endif
299299
};
300300

301+
DEFINE_FREE(linehandle_free, struct linehandle_state *, if (!IS_ERR_OR_NULL(_T)) linehandle_free(_T))
302+
301303
static int linehandle_create(struct gpio_device *gdev, void __user *ip)
302304
{
303305
struct gpiohandle_request handlereq;
304-
struct linehandle_state *lh;
305-
struct file *file;
306-
int fd, i, ret;
306+
struct linehandle_state *lh __free(linehandle_free) = NULL;
307+
int i, ret;
307308
u32 lflags;
308309

309310
if (copy_from_user(&handlereq, ip, sizeof(handlereq)))
@@ -327,10 +328,8 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
327328
lh->label = kstrndup(handlereq.consumer_label,
328329
sizeof(handlereq.consumer_label) - 1,
329330
GFP_KERNEL);
330-
if (!lh->label) {
331-
ret = -ENOMEM;
332-
goto out_free_lh;
333-
}
331+
if (!lh->label)
332+
return -ENOMEM;
334333
}
335334

336335
lh->num_descs = handlereq.lines;
@@ -340,20 +339,18 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
340339
u32 offset = handlereq.lineoffsets[i];
341340
struct gpio_desc *desc = gpio_device_get_desc(gdev, offset);
342341

343-
if (IS_ERR(desc)) {
344-
ret = PTR_ERR(desc);
345-
goto out_free_lh;
346-
}
342+
if (IS_ERR(desc))
343+
return PTR_ERR(desc);
347344

348345
ret = gpiod_request_user(desc, lh->label);
349346
if (ret)
350-
goto out_free_lh;
347+
return ret;
351348
lh->descs[i] = desc;
352349
linehandle_flags_to_desc_flags(handlereq.flags, &desc->flags);
353350

354351
ret = gpiod_set_transitory(desc, false);
355352
if (ret < 0)
356-
goto out_free_lh;
353+
return ret;
357354

358355
/*
359356
* Lines have to be requested explicitly for input
@@ -364,11 +361,11 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
364361

365362
ret = gpiod_direction_output_nonotify(desc, val);
366363
if (ret)
367-
goto out_free_lh;
364+
return ret;
368365
} else if (lflags & GPIOHANDLE_REQUEST_INPUT) {
369366
ret = gpiod_direction_input_nonotify(desc);
370367
if (ret)
371-
goto out_free_lh;
368+
return ret;
372369
}
373370

374371
gpiod_line_state_notify(desc, GPIO_V2_LINE_CHANGED_REQUESTED);
@@ -377,44 +374,23 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
377374
offset);
378375
}
379376

380-
fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC);
381-
if (fd < 0) {
382-
ret = fd;
383-
goto out_free_lh;
384-
}
377+
FD_PREPARE(fdf, O_RDONLY | O_CLOEXEC,
378+
anon_inode_getfile("gpio-linehandle", &linehandle_fileops,
379+
lh, O_RDONLY | O_CLOEXEC));
380+
if (fdf.err)
381+
return fdf.err;
382+
retain_and_null_ptr(lh);
385383

386-
file = anon_inode_getfile("gpio-linehandle",
387-
&linehandle_fileops,
388-
lh,
389-
O_RDONLY | O_CLOEXEC);
390-
if (IS_ERR(file)) {
391-
ret = PTR_ERR(file);
392-
goto out_put_unused_fd;
393-
}
394-
395-
handlereq.fd = fd;
396-
if (copy_to_user(ip, &handlereq, sizeof(handlereq))) {
397-
/*
398-
* fput() will trigger the release() callback, so do not go onto
399-
* the regular error cleanup path here.
400-
*/
401-
fput(file);
402-
put_unused_fd(fd);
384+
handlereq.fd = fd_prepare_fd(fdf);
385+
if (copy_to_user(ip, &handlereq, sizeof(handlereq)))
403386
return -EFAULT;
404-
}
405387

406-
fd_install(fd, file);
388+
fd_publish(fdf);
407389

408390
dev_dbg(&gdev->dev, "registered chardev handle for %d lines\n",
409391
lh->num_descs);
410392

411393
return 0;
412-
413-
out_put_unused_fd:
414-
put_unused_fd(fd);
415-
out_free_lh:
416-
linehandle_free(lh);
417-
return ret;
418394
}
419395
#endif /* CONFIG_GPIO_CDEV_V1 */
420396

0 commit comments

Comments
 (0)