return err;
}
+static void
+gss_pipe_release(struct inode *inode)
+{
+ struct rpc_inode *rpci = RPC_I(inode);
+ struct rpc_clnt *clnt;
+ struct rpc_auth *auth;
+ struct gss_auth *gss_auth;
+
+ clnt = rpci->private;
+ auth = clnt->cl_auth;
+ gss_auth = container_of(auth, struct gss_auth, rpc_auth);
+ spin_lock(&gss_auth->lock);
+ while (!list_empty(&gss_auth->upcalls)) {
+ struct gss_upcall_msg *gss_msg;
+
+ gss_msg = list_entry(gss_auth->upcalls.next,
+ struct gss_upcall_msg, list);
+ gss_msg->msg.errno = -EPIPE;
+ atomic_inc(&gss_msg->count);
+ __gss_unhash_msg(gss_msg);
+ spin_unlock(&gss_auth->lock);
+ gss_release_msg(gss_msg);
+ spin_lock(&gss_auth->lock);
+ }
+ spin_unlock(&gss_auth->lock);
+}
+
void
gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
{
.upcall = gss_pipe_upcall,
.downcall = gss_pipe_downcall,
.destroy_msg = gss_pipe_destroy_msg,
+ .release_pipe = gss_pipe_release,
};
/*
msg->errno = err;
rpci->ops->destroy_msg(msg);
}
+ while (!list_empty(&rpci->in_upcall)) {
+ msg = list_entry(rpci->pipe.next, struct rpc_pipe_msg, list);
+ list_del_init(&msg->list);
+ msg->errno = err;
+ rpci->ops->destroy_msg(msg);
+ }
rpci->pipelen = 0;
wake_up(&rpci->waitq);
}
-void
-rpc_purge_upcall(struct inode *inode, int err)
-{
- down(&inode->i_sem);
- __rpc_purge_upcall(inode, err);
- up(&inode->i_sem);
-}
-
static void
rpc_timeout_upcall_queue(void *data)
{
return res;
}
-void
-rpc_inode_setowner(struct inode *inode, void *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);
- rpci->private = private;
- if (!private)
+ if (rpci->ops != NULL) {
+ rpci->nreaders = 0;
__rpc_purge_upcall(inode, -EPIPE);
+ rpci->nwriters = 0;
+ if (rpci->ops->release_pipe)
+ rpci->ops->release_pipe(inode);
+ rpci->ops = NULL;
+ }
up(&inode->i_sem);
}
+static inline void
+rpc_inode_setowner(struct inode *inode, void *private)
+{
+ RPC_I(inode)->private = private;
+}
+
static struct inode *
rpc_alloc_inode(struct super_block *sb)
{
int res = -ENXIO;
down(&inode->i_sem);
- if (rpci->private != NULL) {
+ 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);
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 = -EPIPE;
+ list_del_init(&msg->list);
rpci->ops->destroy_msg(msg);
}
- down(&inode->i_sem);
+ if (filp->f_mode & FMODE_WRITE)
+ rpci->nwriters --;
if (filp->f_mode & FMODE_READ)
rpci->nreaders --;
if (!rpci->nreaders)
__rpc_purge_upcall(inode, -EPIPE);
+ if (rpci->ops->release_pipe)
+ rpci->ops->release_pipe(inode);
+out:
up(&inode->i_sem);
return 0;
}
int res = 0;
down(&inode->i_sem);
- if (!rpci->private) {
+ if (rpci->ops == NULL) {
res = -EPIPE;
goto out_unlock;
}
msg = list_entry(rpci->pipe.next,
struct rpc_pipe_msg,
list);
- list_del_init(&msg->list);
+ list_move(&msg->list, &rpci->in_upcall);
rpci->pipelen -= msg->len;
filp->private_data = msg;
msg->copied = 0;
res = rpci->ops->upcall(filp, msg, buf, len);
if (res < 0 || msg->len == msg->copied) {
filp->private_data = NULL;
+ list_del_init(&msg->list);
rpci->ops->destroy_msg(msg);
}
out_unlock:
down(&inode->i_sem);
res = -EPIPE;
- if (rpci->private != NULL)
+ if (rpci->ops != NULL)
res = rpci->ops->downcall(filp, buf, len);
up(&inode->i_sem);
return res;
poll_wait(filp, &rpci->waitq, wait);
mask = POLLOUT | POLLWRNORM;
- if (rpci->private == NULL)
+ if (rpci->ops == NULL)
mask |= POLLERR | POLLHUP;
if (!list_empty(&rpci->pipe))
mask |= POLLIN | POLLRDNORM;
switch (cmd) {
case FIONREAD:
- if (!rpci->private)
+ if (rpci->ops == NULL)
return -EPIPE;
len = rpci->pipelen;
if (filp->private_data) {
do {
dentry = dvec[--n];
if (dentry->d_inode) {
+ rpc_close_pipes(dentry->d_inode);
rpc_inode_setowner(dentry->d_inode, NULL);
simple_unlink(dir, dentry);
}
int error;
shrink_dcache_parent(dentry);
- rpc_inode_setowner(dentry->d_inode, NULL);
+ if (dentry->d_inode) {
+ rpc_close_pipes(dentry->d_inode);
+ rpc_inode_setowner(dentry->d_inode, NULL);
+ }
if ((error = simple_rmdir(dir, dentry)) != 0)
return error;
if (!error) {
}
d_drop(dentry);
if (dentry->d_inode) {
+ rpc_close_pipes(dentry->d_inode);
rpc_inode_setowner(dentry->d_inode, NULL);
error = simple_unlink(dir, dentry);
}
inode_init_once(&rpci->vfs_inode);
rpci->private = NULL;
rpci->nreaders = 0;
+ rpci->nwriters = 0;
+ INIT_LIST_HEAD(&rpci->in_upcall);
INIT_LIST_HEAD(&rpci->pipe);
rpci->pipelen = 0;
init_waitqueue_head(&rpci->waitq);