/** * eventfd_file_create - Creates an eventfd file pointer. * @count: Initial eventfd counter value. * @flags: Flags for the eventfd file. * * This function creates an eventfd file pointer, w/out installing it into * the fd table. This is useful when the eventfd file is used during the * initialization of data structures that require extra setup after the eventfd * creation. So the eventfd creation is split into the file pointer creation * phase, and the file descriptor installation phase. * In this way races with userspace closing the newly installed file descriptor * can be avoided. * Returns an eventfd file pointer, or a proper error pointer. */ struct file *eventfd_file_create(unsigned int count, int flags) { struct file *file; struct eventfd_ctx *ctx; /* Check the EFD_* constants for consistency. */ BUILD_BUG_ON(EFD_CLOEXEC != O_CLOEXEC); BUILD_BUG_ON(EFD_NONBLOCK != O_NONBLOCK); if (flags & ~EFD_FLAGS_SET) return ERR_PTR(-EINVAL); ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return ERR_PTR(-ENOMEM); kref_init(&ctx->kref); init_waitqueue_head(&ctx->wqh); ctx->count = count; ctx->flags = flags; file = anon_inode_getfile("[eventfd]", &eventfd_fops, ctx, O_RDWR | (flags & EFD_SHARED_FCNTL_FLAGS)); if (IS_ERR(file)) eventfd_free_ctx(ctx); return file; }
static struct sync_file *sync_file_alloc(void) { struct sync_file *sync_file; sync_file = kzalloc(sizeof(*sync_file), GFP_KERNEL); if (!sync_file) return NULL; sync_file->file = anon_inode_getfile("sync_file", &sync_file_fops, sync_file, 0); if (IS_ERR(sync_file->file)) goto err; kref_init(&sync_file->kref); init_waitqueue_head(&sync_file->wq); INIT_LIST_HEAD(&sync_file->cb.node); return sync_file; err: kfree(sync_file); return NULL; }
static int lttng_abi_create_session(void) { struct lttng_session *session; struct file *session_file; int session_fd, ret; session = lttng_session_create(); if (!session) return -ENOMEM; session_fd = lttng_get_unused_fd(); if (session_fd < 0) { ret = session_fd; goto fd_error; } session_file = anon_inode_getfile("[lttng_session]", <tng_session_fops, session, O_RDWR); if (IS_ERR(session_file)) { ret = PTR_ERR(session_file); goto file_error; } session->file = session_file; fd_install(session_fd, session_file); return session_fd; file_error: put_unused_fd(session_fd); fd_error: lttng_session_destroy(session); return ret; }
static int lttng_abi_syscall_list(void) { struct file *syscall_list_file; int file_fd, ret; file_fd = lttng_get_unused_fd(); if (file_fd < 0) { ret = file_fd; goto fd_error; } syscall_list_file = anon_inode_getfile("[lttng_syscall_list]", <tng_syscall_list_fops, NULL, O_RDWR); if (IS_ERR(syscall_list_file)) { ret = PTR_ERR(syscall_list_file); goto file_error; } ret = lttng_syscall_list_fops.open(NULL, syscall_list_file); if (ret < 0) goto open_error; fd_install(file_fd, syscall_list_file); return file_fd; open_error: fput(syscall_list_file); file_error: put_unused_fd(file_fd); fd_error: return ret; }
static struct file *siw_event_file_new(struct siw_ucontext *ctx, int *event_fd) { struct file *filp; int rv; /* Create a file to communicate events between our userspace verbs * library and this kernel verbs driver, which cannot be communicated * (cleanly) using the uverbs interface. */ rv = get_unused_fd_flags(O_CLOEXEC); if (rv < 0) { goto out; } *event_fd = rv; ctx->event_file = kzalloc(sizeof(*ctx->event_file), GFP_KERNEL); if (!ctx->event_file) { rv = -ENOMEM; goto free_fd; } ctx->event_file->ctx = ctx; spin_lock_init(&ctx->event_file->lock); filp = anon_inode_getfile("[siwevent]", &siw_event_file_ops, ctx->event_file, O_WRONLY|O_NONBLOCK); if (IS_ERR(filp)) { rv = PTR_ERR(filp); goto free_event_file; } return filp; free_event_file: kfree(ctx->event_file); free_fd: put_unused_fd(*event_fd); out: return ERR_PTR(rv); }
/* Get a struct file and fd for a context and attach the ops */ struct file *cxl_get_fd(struct cxl_context *ctx, struct file_operations *fops, int *fd) { struct file *file; int rc, flags, fdtmp; flags = O_RDWR | O_CLOEXEC; /* This code is similar to anon_inode_getfd() */ rc = get_unused_fd_flags(flags); if (rc < 0) return ERR_PTR(rc); fdtmp = rc; /* * Patch the file ops. Needs to be careful that this is rentrant safe. */ if (fops) { PATCH_FOPS(open); PATCH_FOPS(poll); PATCH_FOPS(read); PATCH_FOPS(release); PATCH_FOPS(unlocked_ioctl); PATCH_FOPS(compat_ioctl); PATCH_FOPS(mmap); } else /* use default ops */ fops = (struct file_operations *)&afu_fops; file = anon_inode_getfile("cxl", fops, ctx, flags); if (IS_ERR(file)) put_unused_fd(fdtmp); *fd = fdtmp; return file; }
/* * Create a /dev/tpm%d and 'server side' file descriptor pair * * Return value: * Returns file pointer on success, an error value otherwise */ static struct file *vtpm_proxy_create_device( struct vtpm_proxy_new_dev *vtpm_new_dev) { struct proxy_dev *proxy_dev; int rc, fd; struct file *file; if (vtpm_new_dev->flags & ~VTPM_PROXY_FLAGS_ALL) return ERR_PTR(-EOPNOTSUPP); proxy_dev = vtpm_proxy_create_proxy_dev(); if (IS_ERR(proxy_dev)) return ERR_CAST(proxy_dev); proxy_dev->flags = vtpm_new_dev->flags; /* setup an anonymous file for the server-side */ fd = get_unused_fd_flags(O_RDWR); if (fd < 0) { rc = fd; goto err_delete_proxy_dev; } file = anon_inode_getfile("[vtpms]", &vtpm_proxy_fops, proxy_dev, O_RDWR); if (IS_ERR(file)) { rc = PTR_ERR(file); goto err_put_unused_fd; } /* from now on we can unwind with put_unused_fd() + fput() */ /* simulate an open() on the server side */ vtpm_proxy_fops_open(file); if (proxy_dev->flags & VTPM_PROXY_FLAG_TPM2) proxy_dev->chip->flags |= TPM_CHIP_FLAG_TPM2; vtpm_proxy_work_start(proxy_dev); vtpm_new_dev->fd = fd; vtpm_new_dev->major = MAJOR(proxy_dev->chip->dev.devt); vtpm_new_dev->minor = MINOR(proxy_dev->chip->dev.devt); vtpm_new_dev->tpm_num = proxy_dev->chip->dev_num; return file; err_put_unused_fd: put_unused_fd(fd); err_delete_proxy_dev: vtpm_proxy_delete_proxy_dev(proxy_dev); return ERR_PTR(rc); }
/* create file and install a new file descriptor */ int kdbus_memfd_new(int *fd) { struct kdbus_memfile *mf; struct file *shmemfp; struct file *fp; int f; int ret; mf = kzalloc(sizeof(struct kdbus_memfile), GFP_KERNEL); if (!mf) return -ENOMEM; mutex_init(&mf->lock); /* allocate a new unlinked shmem file */ shmemfp = shmem_file_setup("kdbus-memfd", 0, 0); if (IS_ERR(shmemfp)) { ret = PTR_ERR(shmemfp); goto exit; } mf->fp = shmemfp; f = get_unused_fd_flags(O_CLOEXEC); if (f < 0) { ret = f; goto exit_shmem; } /* The anonymous exported inode ops cannot reach the otherwise * invisible shmem inode. We rely on the fact that nothing else * can create a new file for the shmem inode, like by opening the * fd in /proc/$PID/fd/ */ fp = anon_inode_getfile("[kdbus]", &kdbus_memfd_fops, mf, O_RDWR); if (IS_ERR(fp)) { ret = PTR_ERR(fp); goto exit_fd; } fp->f_mode |= FMODE_LSEEK|FMODE_PREAD|FMODE_PWRITE; fp->f_mapping = shmemfp->f_mapping; fd_install(f, fp); *fd = f; return 0; exit_fd: put_unused_fd(f); exit_shmem: fput(shmemfp); exit: kfree(mf); return ret; }
struct file * gfsk_evfd_file_create(unsigned int count) { struct file *file; struct gfsk_evfd_ctx *ctx; ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return (ERR_PTR(-ENOMEM)); init_waitqueue_head(&ctx->wqh); ctx->count = count; file = anon_inode_getfile("[gfsk_evfd]", &gfsk_evfd_fops, ctx, O_RDWR); if (IS_ERR(file)) gfsk_evfd_free_ctx(ctx); return (file); }
static long ktapvm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int new_fd, err; struct file *new_file; new_fd = get_unused_fd(); if (new_fd < 0) return new_fd; new_file = anon_inode_getfile("[ktap]", &ktap_fops, NULL, O_RDWR); if (IS_ERR(new_file)) { err = PTR_ERR(new_file); put_unused_fd(new_fd); return err; } file->private_data = NULL; fd_install(new_fd, new_file); return new_fd; }
static int gk20a_ctrl_alloc_as( struct gk20a *g, struct nvgpu_alloc_as_args *args) { struct platform_device *dev = g->dev; struct gk20a_as_share *as_share; int err; int fd; struct file *file; char *name; err = get_unused_fd_flags(O_RDWR); if (err < 0) return err; fd = err; name = kasprintf(GFP_KERNEL, "nvhost-%s-fd%d", dev_name(&dev->dev), fd); file = anon_inode_getfile(name, g->as.cdev.ops, NULL, O_RDWR); kfree(name); if (IS_ERR(file)) { err = PTR_ERR(file); goto clean_up; } fd_install(fd, file); err = gk20a_as_alloc_share(&g->as, args->big_page_size, &as_share); if (err) goto clean_up; file->private_data = as_share; args->as_fd = fd; return 0; clean_up: put_unused_fd(fd); return err; }
static int gk20a_ctrl_open_tsg(struct gk20a *g, struct nvgpu_gpu_open_tsg_args *args) { struct platform_device *dev = g->dev; int err; int fd; struct file *file; char *name; err = get_unused_fd_flags(O_RDWR); if (err < 0) return err; fd = err; name = kasprintf(GFP_KERNEL, "nvgpu-%s-tsg%d", dev_name(&dev->dev), fd); file = anon_inode_getfile(name, g->tsg.cdev.ops, NULL, O_RDWR); kfree(name); if (IS_ERR(file)) { err = PTR_ERR(file); goto clean_up; } fd_install(fd, file); err = gk20a_tsg_open(g, file); if (err) goto clean_up_file; args->tsg_fd = fd; return 0; clean_up_file: fput(file); clean_up: put_unused_fd(fd); return err; }
static int lttng_abi_create_stream_fd(struct file *channel_file, void *stream_priv, const struct file_operations *fops) { int stream_fd, ret; struct file *stream_file; stream_fd = lttng_get_unused_fd(); if (stream_fd < 0) { ret = stream_fd; goto fd_error; } stream_file = anon_inode_getfile("[lttng_stream]", fops, stream_priv, O_RDWR); if (IS_ERR(stream_file)) { ret = PTR_ERR(stream_file); goto file_error; } /* * OPEN_FMODE, called within anon_inode_getfile/alloc_file, don't honor * FMODE_LSEEK, FMODE_PREAD nor FMODE_PWRITE. We need to read from this * file descriptor, so we set FMODE_PREAD here. */ stream_file->f_mode |= FMODE_PREAD; fd_install(stream_fd, stream_file); /* * The stream holds a reference to the channel within the generic ring * buffer library, so no need to hold a refcount on the channel and * session files here. */ return stream_fd; file_error: put_unused_fd(stream_fd); fd_error: return ret; }
/** * anon_inode_getfd - creates a new file instance by hooking it up to an * anonymous inode, and a dentry that describe the "class" * of the file * * @name: [in] name of the "class" of the new file * @fops: [in] file operations for the new file * @priv: [in] private data for the new file (will be file's private_data) * @flags: [in] flags * * Creates a new file by hooking it on a single inode. This is useful for files * that do not need to have a full-fledged inode in order to operate correctly. * All the files created with anon_inode_getfd() will share a single inode, * hence saving memory and avoiding code duplication for the file/inode/dentry * setup. Returns new descriptor or an error code. */ int anon_inode_getfd(const char *name, const struct file_operations *fops, void *priv, int flags) { int error, fd; struct file *file; error = get_unused_fd_flags(flags); if (error < 0) return error; fd = error; file = anon_inode_getfile(name, fops, priv, flags); if (IS_ERR(file)) { error = PTR_ERR(file); goto err_put_unused_fd; } fd_install(fd, file); return fd; err_put_unused_fd: put_unused_fd(fd); return error; }
static int lttng_abi_create_channel(struct file *session_file, struct lttng_kernel_channel *chan_param, enum channel_type channel_type) { struct lttng_session *session = session_file->private_data; const struct file_operations *fops = NULL; const char *transport_name; struct lttng_channel *chan; struct file *chan_file; int chan_fd; int ret = 0; chan_fd = lttng_get_unused_fd(); if (chan_fd < 0) { ret = chan_fd; goto fd_error; } switch (channel_type) { case PER_CPU_CHANNEL: fops = <tng_channel_fops; break; case METADATA_CHANNEL: fops = <tng_metadata_fops; break; } chan_file = anon_inode_getfile("[lttng_channel]", fops, NULL, O_RDWR); if (IS_ERR(chan_file)) { ret = PTR_ERR(chan_file); goto file_error; } switch (channel_type) { case PER_CPU_CHANNEL: if (chan_param->output == LTTNG_KERNEL_SPLICE) { transport_name = chan_param->overwrite ? "relay-overwrite" : "relay-discard"; } else if (chan_param->output == LTTNG_KERNEL_MMAP) { transport_name = chan_param->overwrite ? "relay-overwrite-mmap" : "relay-discard-mmap"; } else { return -EINVAL; } break; case METADATA_CHANNEL: if (chan_param->output == LTTNG_KERNEL_SPLICE) transport_name = "relay-metadata"; else if (chan_param->output == LTTNG_KERNEL_MMAP) transport_name = "relay-metadata-mmap"; else return -EINVAL; break; default: transport_name = "<unknown>"; break; } if (atomic_long_add_unless(&session_file->f_count, 1, INT_MAX) == INT_MAX) { goto refcount_error; } /* * We tolerate no failure path after channel creation. It will stay * invariant for the rest of the session. */ chan = lttng_channel_create(session, transport_name, NULL, chan_param->subbuf_size, chan_param->num_subbuf, chan_param->switch_timer_interval, chan_param->read_timer_interval, channel_type); if (!chan) { ret = -EINVAL; goto chan_error; } chan->file = chan_file; chan_file->private_data = chan; fd_install(chan_fd, chan_file); return chan_fd; chan_error: atomic_long_dec(&session_file->f_count); refcount_error: fput(chan_file); file_error: put_unused_fd(chan_fd); fd_error: return ret; }
/** * kdbus_memfd_new() - create and install a memfd and file descriptor * @name: Name of the (deleted) file which shows up in * /proc, used for debugging * @size: Initial size of the file * @fd: Installed file descriptor * * Return: 0 on success, negative errno on failure. */ int kdbus_memfd_new(const char *name, size_t size, int *fd) { const char *shmem_name = NULL; const char *anon_name = NULL; struct kdbus_memfile *mf; struct file *shmemfp; struct file *fp; int f, ret; mf = kzalloc(sizeof(*mf), GFP_KERNEL); if (!mf) return -ENOMEM; mutex_init(&mf->lock); if (name) { mf->name = kstrdup(name, GFP_KERNEL); shmem_name = kasprintf(GFP_KERNEL, KBUILD_MODNAME "-memfd:%s", name); anon_name = kasprintf(GFP_KERNEL, "[" KBUILD_MODNAME "-memfd:%s]", name); if (!mf->name || !shmem_name || !anon_name) { ret = -ENOMEM; goto exit; } } /* allocate a new unlinked shmem file */ shmemfp = shmem_file_setup(name ? shmem_name : KBUILD_MODNAME "-memfd", size, 0); if (IS_ERR(shmemfp)) { ret = PTR_ERR(shmemfp); goto exit; } mf->fp = shmemfp; f = get_unused_fd_flags(O_CLOEXEC); if (f < 0) { ret = f; goto exit_shmem; } /* * The anonymous exported inode ops cannot reach the otherwise * invisible shmem inode. We rely on the fact that nothing else * can create a new file for the shmem inode, like by opening the * fd in /proc/$PID/fd/ */ fp = anon_inode_getfile(name ? anon_name : "[" KBUILD_MODNAME "-memfd]", &kdbus_memfd_fops, mf, O_RDWR); if (IS_ERR(fp)) { ret = PTR_ERR(fp); goto exit_fd; } fp->f_mode |= FMODE_LSEEK|FMODE_PREAD|FMODE_PWRITE; fp->f_mapping = shmemfp->f_mapping; fd_install(f, fp); kfree(anon_name); kfree(shmem_name); *fd = f; return 0; exit_fd: put_unused_fd(f); exit_shmem: fput(shmemfp); exit: kfree(anon_name); kfree(shmem_name); kfree(mf->name); kfree(mf); return ret; }
static int lttng_abi_create_event(struct file *channel_file, struct lttng_kernel_event *event_param) { struct lttng_channel *channel = channel_file->private_data; int event_fd, ret; struct file *event_file; void *priv; event_param->name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; switch (event_param->instrumentation) { case LTTNG_KERNEL_KRETPROBE: event_param->u.kretprobe.symbol_name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; break; case LTTNG_KERNEL_KPROBE: event_param->u.kprobe.symbol_name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; break; case LTTNG_KERNEL_FUNCTION: event_param->u.ftrace.symbol_name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; break; default: break; } event_fd = lttng_get_unused_fd(); if (event_fd < 0) { ret = event_fd; goto fd_error; } event_file = anon_inode_getfile("[lttng_event]", <tng_event_fops, NULL, O_RDWR); if (IS_ERR(event_file)) { ret = PTR_ERR(event_file); goto file_error; } /* The event holds a reference on the channel */ if (atomic_long_add_unless(&channel_file->f_count, 1, INT_MAX) == INT_MAX) { ret = -EOVERFLOW; goto refcount_error; } if (event_param->instrumentation == LTTNG_KERNEL_TRACEPOINT || event_param->instrumentation == LTTNG_KERNEL_SYSCALL) { struct lttng_enabler *enabler; if (event_param->name[strlen(event_param->name) - 1] == '*') { enabler = lttng_enabler_create(LTTNG_ENABLER_WILDCARD, event_param, channel); } else { enabler = lttng_enabler_create(LTTNG_ENABLER_NAME, event_param, channel); } priv = enabler; } else { struct lttng_event *event; /* * We tolerate no failure path after event creation. It * will stay invariant for the rest of the session. */ event = lttng_event_create(channel, event_param, NULL, NULL, event_param->instrumentation); WARN_ON_ONCE(!event); if (IS_ERR(event)) { ret = PTR_ERR(event); goto event_error; } priv = event; } event_file->private_data = priv; fd_install(event_fd, event_file); return event_fd; event_error: atomic_long_dec(&channel_file->f_count); refcount_error: fput(event_file); file_error: put_unused_fd(event_fd); fd_error: return ret; }