]> git.hungrycats.org Git - linux/commitdiff
RPCSEC_GSS: Make the upcalls detect if the userland daemon
authorTrond Myklebust <trond.myklebust@fys.uio.no>
Sat, 7 Feb 2004 15:25:51 +0000 (16:25 +0100)
committerTrond Myklebust <trond.myklebust@fys.uio.no>
Sat, 7 Feb 2004 15:25:51 +0000 (16:25 +0100)
dies while processing a request.

include/linux/sunrpc/rpc_pipe_fs.h
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/rpc_pipe.c

index c3752710c74c10ef74d5f0787d03edbf7c71cbba..63929349571fe643eecfd1636636daabb6aac2a4 100644 (file)
@@ -14,6 +14,7 @@ struct rpc_pipe_msg {
 struct rpc_pipe_ops {
        ssize_t (*upcall)(struct file *, struct rpc_pipe_msg *, char __user *, size_t);
        ssize_t (*downcall)(struct file *, const char __user *, size_t);
+       void (*release_pipe)(struct inode *);
        void (*destroy_msg)(struct rpc_pipe_msg *);
 };
 
@@ -21,8 +22,10 @@ struct rpc_inode {
        struct inode vfs_inode;
        void *private;
        struct list_head pipe;
+       struct list_head in_upcall;
        int pipelen;
        int nreaders;
+       int nwriters;
        wait_queue_head_t waitq;
 #define RPC_PIPE_WAIT_FOR_OPEN 1
        int flags;
@@ -36,7 +39,6 @@ RPC_I(struct inode *inode)
        return container_of(inode, struct rpc_inode, vfs_inode);
 }
 
-extern void rpc_inode_setowner(struct inode *, void *);
 extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *);
 
 extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *);
index 6892bb79d8daf751b6ab5692642b4f99d2b1052c..af67459e1cc4af4c17ea1225136eb2a9d2eae6d7 100644 (file)
@@ -482,6 +482,33 @@ err:
        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)
 {
@@ -774,6 +801,7 @@ static struct rpc_pipe_ops gss_upcall_ops = {
        .upcall         = gss_pipe_upcall,
        .downcall       = gss_pipe_downcall,
        .destroy_msg    = gss_pipe_destroy_msg,
+       .release_pipe   = gss_pipe_release,
 };
 
 /*
index 1841ac8cb0dab80003d7b1c24a4dac7b430fb7de..409e6aef143de0acc5063f36b58f9f2424ae65d8 100644 (file)
@@ -50,18 +50,16 @@ __rpc_purge_upcall(struct inode *inode, int err)
                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)
 {
@@ -97,20 +95,31 @@ rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg)
        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)
 {
@@ -134,9 +143,11 @@ rpc_pipe_open(struct inode *inode, struct file *filp)
        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);
@@ -149,16 +160,24 @@ 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 = -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;
 }
@@ -172,7 +191,7 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
        int res = 0;
 
        down(&inode->i_sem);
-       if (!rpci->private) {
+       if (rpci->ops == NULL) {
                res = -EPIPE;
                goto out_unlock;
        }
@@ -182,7 +201,7 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
                        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;
@@ -194,6 +213,7 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
        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:
@@ -210,7 +230,7 @@ rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *of
 
        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;
@@ -226,7 +246,7 @@ rpc_pipe_poll(struct file *filp, struct poll_table_struct *wait)
        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;
@@ -242,7 +262,7 @@ rpc_pipe_ioctl(struct inode *ino, struct file *filp,
 
        switch (cmd) {
        case FIONREAD:
-               if (!rpci->private)
+               if (rpci->ops == NULL)
                        return -EPIPE;
                len = rpci->pipelen;
                if (filp->private_data) {
@@ -484,6 +504,7 @@ repeat:
                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);
                        }
@@ -563,7 +584,10 @@ __rpc_rmdir(struct inode *dir, struct dentry *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) {
@@ -715,6 +739,7 @@ rpc_unlink(char *path)
        }
        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);
        }
@@ -790,6 +815,8 @@ init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
                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);