]> err.no Git - linux-2.6/blobdiff - net/sunrpc/rpc_pipe.c
Merge master.kernel.org:/home/rmk/linux-2.6-serial
[linux-2.6] / net / sunrpc / rpc_pipe.c
index 649d609e7d9484a8b323f1f07dfeb2526789b7e4..24cc23af9b95d7d0ca1950ce7bcaf5ac098bdc6f 100644 (file)
@@ -39,23 +39,26 @@ static kmem_cache_t *rpc_inode_cachep __read_mostly;
 #define RPC_UPCALL_TIMEOUT (30*HZ)
 
 static void
-__rpc_purge_upcall(struct inode *inode, int err)
+__rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, int err)
 {
-       struct rpc_inode *rpci = RPC_I(inode);
        struct rpc_pipe_msg *msg;
+       void (*destroy_msg)(struct rpc_pipe_msg *);
 
-       while (!list_empty(&rpci->pipe)) {
-               msg = list_entry(rpci->pipe.next, struct rpc_pipe_msg, list);
-               list_del_init(&msg->list);
-               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);
+       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;
-               rpci->ops->destroy_msg(msg);
+               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);
 }
@@ -67,8 +70,11 @@ rpc_timeout_upcall_queue(void *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);
 }
 
@@ -76,48 +82,54 @@ int
 rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg)
 {
        struct rpc_inode *rpci = RPC_I(inode);
-       int res = 0;
+       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;
-       } else
-               res = -EPIPE;
+               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 inline void
-rpc_inode_setowner(struct inode *inode, void *private)
-{
-       RPC_I(inode)->private = private;
+       cancel_delayed_work(&rpci->queue_timeout);
+       flush_scheduled_work();
 }
 
 static struct inode *
@@ -157,7 +169,7 @@ rpc_pipe_open(struct inode *inode, struct file *filp)
 static int
 rpc_pipe_release(struct inode *inode, struct file *filp)
 {
-       struct rpc_inode *rpci = RPC_I(filp->f_dentry->d_inode);
+       struct rpc_inode *rpci = RPC_I(inode);
        struct rpc_pipe_msg *msg;
 
        down(&inode->i_sem);
@@ -165,7 +177,7 @@ rpc_pipe_release(struct inode *inode, struct file *filp)
                goto out;
        msg = (struct rpc_pipe_msg *)filp->private_data;
        if (msg != NULL) {
-               msg->errno = -EPIPE;
+               msg->errno = -EAGAIN;
                list_del_init(&msg->list);
                rpci->ops->destroy_msg(msg);
        }
@@ -174,11 +186,9 @@ rpc_pipe_release(struct inode *inode, struct file *filp)
        if (filp->f_mode & FMODE_READ)
                rpci->nreaders --;
        if (!rpci->nreaders)
-               __rpc_purge_upcall(inode, -EPIPE);
+               __rpc_purge_upcall(inode, -EAGAIN);
        if (rpci->ops->release_pipe)
                rpci->ops->release_pipe(inode);
-       if (!rpci->nreaders && !rpci->nwriters)
-               rpci->ops = NULL;
 out:
        up(&inode->i_sem);
        return 0;
@@ -503,7 +513,6 @@ repeat:
                        dentry = dvec[--n];
                        if (dentry->d_inode) {
                                rpc_close_pipes(dentry->d_inode);
-                               rpc_inode_setowner(dentry->d_inode, NULL);
                                simple_unlink(dir, dentry);
                        }
                        dput(dentry);
@@ -578,10 +587,8 @@ __rpc_rmdir(struct inode *dir, struct dentry *dentry)
        int error;
 
        shrink_dcache_parent(dentry);
-       if (dentry->d_inode) {
+       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) {
@@ -603,7 +610,7 @@ rpc_lookup_negative(char *path, struct nameidata *nd)
                return ERR_PTR(error);
        dir = nd->dentry->d_inode;
        down(&dir->i_sem);
-       dentry = lookup_hash(&nd->last, nd->dentry);
+       dentry = lookup_hash(nd);
        if (IS_ERR(dentry))
                goto out_err;
        if (dentry->d_inode) {
@@ -665,7 +672,7 @@ rpc_rmdir(char *path)
                return error;
        dir = nd.dentry->d_inode;
        down(&dir->i_sem);
-       dentry = lookup_hash(&nd.last, nd.dentry);
+       dentry = lookup_hash(&nd);
        if (IS_ERR(dentry)) {
                error = PTR_ERR(dentry);
                goto out_release;
@@ -726,7 +733,7 @@ rpc_unlink(char *path)
                return error;
        dir = nd.dentry->d_inode;
        down(&dir->i_sem);
-       dentry = lookup_hash(&nd.last, nd.dentry);
+       dentry = lookup_hash(&nd);
        if (IS_ERR(dentry)) {
                error = PTR_ERR(dentry);
                goto out_release;
@@ -734,7 +741,6 @@ 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);
        }
        dput(dentry);