예제 #1
0
/**
 * 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;
}
예제 #3
0
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]",
					  &lttng_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;
}
예제 #4
0
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]",
					  &lttng_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;
}
예제 #5
0
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);
}
예제 #6
0
파일: api.c 프로젝트: Kirill2013/kasan
/* 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;
}
예제 #7
0
파일: tpm_vtpm_proxy.c 프로젝트: dznm/linux
/*
 * 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);
}
예제 #8
0
파일: memfd.c 프로젝트: marb73/kdbus
/* 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;
}
예제 #9
0
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);
}
예제 #10
0
파일: ktap.c 프로젝트: cfregly/ktap
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;
}
예제 #11
0
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;
}
예제 #12
0
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;
}
예제 #13
0
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;
}
예제 #14
0
/**
 * 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;
}
예제 #15
0
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 = &lttng_channel_fops;
		break;
	case METADATA_CHANNEL:
		fops = &lttng_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;
}
예제 #16
0
파일: memfd.c 프로젝트: RPajak/kdbus
/**
 * 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;
}
예제 #17
0
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]",
					&lttng_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;
}