<commit_before>/*
 * net/sunrpc/rpc_pipe.c
 *
 * Userland/kernel interface for rpcauth_gss.
 * Code shamelessly plagiarized from fs/nfsd/nfsctl.c
 * and fs/sysfs/inode.c
 *
 * Copyright (c) 2002, <NAME> <<EMAIL>>
 *
 */
#include <linux/config.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/pagemap.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/dnotify.h>
#include <linux/kernel.h>

#include <asm/ioctls.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/wait.h>
#include <linux/seq_file.h>

#include <linux/sunrpc/clnt.h>
#include <linux/workqueue.h>
#include <linux/sunrpc/rpc_pipe_fs.h>

static struct vfsmount *rpc_mount __read_mostly;
static int rpc_mount_count;

static struct file_system_type rpc_pipe_fs_type;


static kmem_cache_t *rpc_inode_cachep __read_mostly;

#define RPC_UPCALL_TIMEOUT (30*HZ)

static void
__rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, int err)
{
	struct rpc_pipe_msg *msg;
	void (*destroy_msg)(struct rpc_pipe_msg *);

	destroy_msg = rpci->ops->destroy_msg;
	while (!list_empty(head)) {
		msg = list_entry(head->next, struct rpc_pipe_msg, list);
		list_del_init(&msg->list);
		msg->errno = err;
		destroy_msg(msg);
	}
}

static void
__rpc_purge_upcall(struct inode *inode, int err)
{
	struct rpc_inode *rpci = RPC_I(inode);

	__rpc_purge_list(rpci, &rpci->pipe, err);
	rpci->pipelen = 0;
	wake_up(&rpci->waitq);
}

static void
rpc_timeout_upcall_queue(void *data)
{
	struct rpc_inode *rpci = (struct rpc_inode *)data;
	struct inode *inode = &rpci->vfs_inode;

	down(&inode->i_sem);
	if (rpci->nreaders == 0 && !list_empty(&rpci->pipe))
		__rpc_purge_upcall(inode, -ETIMEDOUT);
	up(&inode->i_sem);
}

int
rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg)
{
	struct rpc_inode *rpci = RPC_I(inode);
	int res = -EPIPE;

	down(&inode->i_sem);
	if (rpci->ops == NULL)
		goto out;
	if (rpci->nreaders) {
		list_add_tail(&msg->list, &rpci->pipe);
		rpci->pipelen += msg->len;
		res = 0;
	} else if (rpci->flags & RPC_PIPE_WAIT_FOR_OPEN) {
		if (list_empty(&rpci->pipe))
			schedule_delayed_work(&rpci->queue_timeout,
					RPC_UPCALL_TIMEOUT);
		list_add_tail(&msg->list, &rpci->pipe);
		rpci->pipelen += msg->len;
		res = 0;
	}
out:
	up(&inode->i_sem);
	wake_up(&rpci->waitq);
	return res;
}

static inline void
rpc_inode_setowner(struct inode *inode, void *private)
{
	RPC_I(inode)->private = private;
}

static void
rpc_close_pipes(struct inode *inode)
{
	struct rpc_inode *rpci = RPC_I(inode);

	cancel_delayed_work(&rpci->queue_timeout);
	flush_scheduled_work();
	down(&inode->i_sem);
	if (rpci->ops != NULL) {
		rpci->nreaders = 0;
		__rpc_purge_list(rpci, &rpci->in_upcall, -EPIPE);
		__rpc_purge_upcall(inode, -EPIPE);
		rpci->nwriters = 0;
		if (rpci->ops->release_pipe)
			rpci->ops->release_pipe(inode);
		rpci->ops = NULL;
	}
	rpc_inode_setowner(inode, NULL);
	up(&inode->i_sem);
}

static struct inode *
rpc_alloc_inode(struct super_block *sb)
{
	struct rpc_inode *rpci;
	rpci = (struct rpc_inode *)kmem_cache_alloc(rpc_inode_cachep, SLAB_KERNEL);
	if (!rpci)
		return NULL;
	return &rpci->vfs_inode;
}

static void
rpc_destroy_inode(struct inode *inode)
{
	kmem_cache_free(rpc_inode_cachep, RPC_I(inode));
}

static int
rpc_pipe_open(struct inode *inode, struct file *filp)
{
	struct rpc_inode *rpci = RPC_I(inode);
	int res = -ENXIO;

	down(&inode->i_sem);
	if (rpci->ops != NULL) {
		if (filp->f_mode & FMODE_READ)
			rpci->nreaders ++;
		if (filp->f_mode & FMODE_WRITE)
			rpci->nwriters ++;
		res = 0;
	}
	up(&inode->i_sem);
	return res;
}

static int
rpc_pipe_release(struct inode *inode, struct file *filp)
{
	struct rpc_inode *rpci = RPC_I(filp->f_dentry->d_inode);
	struct rpc_pipe_msg *msg;

	down(&inode->i_sem);
	if (rpci->ops == NULL)
		goto out;
	msg = (struct rpc_pipe_msg *)filp->private_data;
	if (msg != NULL) {
		msg->errno = -EAGAIN;
		list_del_init(&msg->list);
		rpci->ops->destroy_msg(msg);
	}
	if (filp->f_mode & FMODE_WRITE)
		rpci->nwriters --;
	if (filp->f_mode & FMODE_READ)
		rpci->nreaders --;
	if (!rpci->nreaders)
		__rpc_purge_upcall(inode, -EAGAIN);
	if (rpci->ops->release_pipe)
		rpci->ops->release_pipe(inode);
out:
	up(&inode->i_sem);
	return 0;
}<commit_msg>SUNRPC: Fix a potential race in rpc_pipefs.<commit_after>/*
 * net/sunrpc/rpc_pipe.c
 *
 * Userland/kernel interface for rpcauth_gss.
 * Code shamelessly plagiarized from fs/nfsd/nfsctl.c
 * and fs/sysfs/inode.c
 *
 * Copyright (c) 2002, <NAME> <<EMAIL>>
 *
 */
#include <linux/config.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/pagemap.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/dnotify.h>
#include <linux/kernel.h>

#include <asm/ioctls.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/wait.h>
#include <linux/seq_file.h>

#include <linux/sunrpc/clnt.h>
#include <linux/workqueue.h>
#include <linux/sunrpc/rpc_pipe_fs.h>

static struct vfsmount *rpc_mount __read_mostly;
static int rpc_mount_count;

static struct file_system_type rpc_pipe_fs_type;


static kmem_cache_t *rpc_inode_cachep __read_mostly;

#define RPC_UPCALL_TIMEOUT (30*HZ)

static void
__rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, int err)
{
	struct rpc_pipe_msg *msg;
	void (*destroy_msg)(struct rpc_pipe_msg *);

	destroy_msg = rpci->ops->destroy_msg;
	while (!list_empty(head)) {
		msg = list_entry(head->next, struct rpc_pipe_msg, list);
		list_del_init(&msg->list);
		msg->errno = err;
		destroy_msg(msg);
	}
}

static void
__rpc_purge_upcall(struct inode *inode, int err)
{
	struct rpc_inode *rpci = RPC_I(inode);

	__rpc_purge_list(rpci, &rpci->pipe, err);
	rpci->pipelen = 0;
	wake_up(&rpci->waitq);
}

static void
rpc_timeout_upcall_queue(void *data)
{
	struct rpc_inode *rpci = (struct rpc_inode *)data;
	struct inode *inode = &rpci->vfs_inode;

	down(&inode->i_sem);
	if (rpci->ops == NULL)
		goto out;
	if (rpci->nreaders == 0 && !list_empty(&rpci->pipe))
		__rpc_purge_upcall(inode, -ETIMEDOUT);
out:
	up(&inode->i_sem);
}

int
rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg)
{
	struct rpc_inode *rpci = RPC_I(inode);
	int res = -EPIPE;

	down(&inode->i_sem);
	if (rpci->ops == NULL)
		goto out;
	if (rpci->nreaders) {
		list_add_tail(&msg->list, &rpci->pipe);
		rpci->pipelen += msg->len;
		res = 0;
	} else if (rpci->flags & RPC_PIPE_WAIT_FOR_OPEN) {
		if (list_empty(&rpci->pipe))
			schedule_delayed_work(&rpci->queue_timeout,
					RPC_UPCALL_TIMEOUT);
		list_add_tail(&msg->list, &rpci->pipe);
		rpci->pipelen += msg->len;
		res = 0;
	}
out:
	up(&inode->i_sem);
	wake_up(&rpci->waitq);
	return res;
}

static inline void
rpc_inode_setowner(struct inode *inode, void *private)
{
	RPC_I(inode)->private = private;
}

static void
rpc_close_pipes(struct inode *inode)
{
	struct rpc_inode *rpci = RPC_I(inode);

	down(&inode->i_sem);
	if (rpci->ops != NULL) {
		rpci->nreaders = 0;
		__rpc_purge_list(rpci, &rpci->in_upcall, -EPIPE);
		__rpc_purge_upcall(inode, -EPIPE);
		rpci->nwriters = 0;
		if (rpci->ops->release_pipe)
			rpci->ops->release_pipe(inode);
		rpci->ops = NULL;
	}
	rpc_inode_setowner(inode, NULL);
	up(&inode->i_sem);
	cancel_delayed_work(&rpci->queue_timeout);
	flush_scheduled_work();
}

static struct inode *
rpc_alloc_inode(struct super_block *sb)
{
	struct rpc_inode *rpci;
	rpci = (struct rpc_inode *)kmem_cache_alloc(rpc_inode_cachep, SLAB_KERNEL);
	if (!rpci)
		return NULL;
	return &rpci->vfs_inode;
}

static void
rpc_destroy_inode(struct inode *inode)
{
	kmem_cache_free(rpc_inode_cachep, RPC_I(inode));
}

static int
rpc_pipe_open(struct inode *inode, struct file *filp)
{
	struct rpc_inode *rpci = RPC_I(inode);
	int res = -ENXIO;

	down(&inode->i_sem);
	if (rpci->ops != NULL) {
		if (filp->f_mode & FMODE_READ)
			rpci->nreaders ++;
		if (filp->f_mode & FMODE_WRITE)
			rpci->nwriters ++;
		res = 0;
	}
	up(&inode->i_sem);
	return res;
}

static int
rpc_pipe_release(struct inode *inode, struct file *filp)
{
	struct rpc_inode *rpci = RPC_I(inode);
	struct rpc_pipe_msg *msg;

	down(&inode->i_sem);
	if (rpci->ops == NULL)
		goto out;
	msg = (struct rpc_pipe_msg *)filp->private_data;
	if (msg != NULL) {
		msg->errno = -EAGAIN;
		list_del_init(&msg->list);
		rpci->ops->destroy_msg(msg);
	}
	if (filp->f_mode & FMODE_WRITE)
		rpci->nwriters --;
	if (filp->f_mode & FMODE_READ)
		rpci->nreaders --;
	if (!rpci->nreaders)
		__rpc_purge_upcall(inode, -EAGAIN);
	if (rpci->ops->release_pipe)
		rpci->ops->release_pipe(inode);
out:
	up(&inode->i_sem);
	return 0;
}
{'fraction_non_alphanumeric': 0.15686732904734074, 'fraction_numerical': 0.0032729398012857976, 'mean_word_length': 4.872340425531915, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 180, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3355141', 'n_tokens_mistral': 3769, 'n_tokens_neox': 3625, 'n_words': 688}