Update the NFS code in OFED 1.5 to lastest linux-2.6.30-rc4 version

Signed-Off-By: Jon Mason <[email protected]>
----

diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 5a97bcf..ec7e27d 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -517,10 +517,10 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct 
*vma, struct vm_fault *vmf)
 
        ret = nfs_updatepage(filp, page, 0, pagelen);
 out_unlock:
+       if (!ret)
+               return VM_FAULT_LOCKED;
        unlock_page(page);
-       if (ret)
-               ret = VM_FAULT_SIGBUS;
-       return ret;
+       return VM_FAULT_SIGBUS;
 }
 
 static struct vm_operations_struct nfs_file_vm_ops = {
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index e6a1932..35869a4 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -713,7 +713,8 @@ nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
        if (args->npages != 0)
                xdr_encode_pages(buf, args->pages, 0, args->len);
        else
-               req->rq_slen += args->len;
+               req->rq_slen = xdr_adjust_iovec(req->rq_svec,
+                               p + XDR_QUADLEN(args->len));
 
        err = nfsacl_encode(buf, base, args->inode,
                            (args->mask & NFS_ACL) ?
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index 3444c00..5275097 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -229,21 +229,23 @@ nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f)
                goto out;
        status = vfs_readdir(filp, nfsd4_build_namelist, &names);
        fput(filp);
+       mutex_lock(&dir->d_inode->i_mutex);
        while (!list_empty(&names)) {
                entry = list_entry(names.next, struct name_list, list);
 
                dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1);
                if (IS_ERR(dentry)) {
                        status = PTR_ERR(dentry);
-                       goto out;
+                       break;
                }
                status = f(dir, dentry);
                dput(dentry);
                if (status)
-                       goto out;
+                       break;
                list_del(&entry->list);
                kfree(entry);
        }
+       mutex_unlock(&dir->d_inode->i_mutex);
 out:
        while (!list_empty(&names)) {
                entry = list_entry(names.next, struct name_list, list);
@@ -255,36 +257,6 @@ out:
 }
 
 static int
-nfsd4_remove_clid_file(struct dentry *dir, struct dentry *dentry)
-{
-       int status;
-
-       if (!S_ISREG(dir->d_inode->i_mode)) {
-               printk("nfsd4: non-file found in client recovery directory\n");
-               return -EINVAL;
-       }
-       mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
-       status = vfs_unlink(dir->d_inode, dentry);
-       mutex_unlock(&dir->d_inode->i_mutex);
-       return status;
-}
-
-static int
-nfsd4_clear_clid_dir(struct dentry *dir, struct dentry *dentry)
-{
-       int status;
-
-       /* For now this directory should already be empty, but we empty it of
-        * any regular files anyway, just in case the directory was created by
-        * a kernel from the future.... */
-       nfsd4_list_rec_dir(dentry, nfsd4_remove_clid_file);
-       mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
-       status = vfs_rmdir(dir->d_inode, dentry);
-       mutex_unlock(&dir->d_inode->i_mutex);
-       return status;
-}
-
-static int
 nfsd4_unlink_clid_dir(char *name, int namlen)
 {
        struct dentry *dentry;
@@ -294,18 +266,18 @@ nfsd4_unlink_clid_dir(char *name, int namlen)
 
        mutex_lock(&rec_dir.dentry->d_inode->i_mutex);
        dentry = lookup_one_len(name, rec_dir.dentry, namlen);
-       mutex_unlock(&rec_dir.dentry->d_inode->i_mutex);
        if (IS_ERR(dentry)) {
                status = PTR_ERR(dentry);
-               return status;
+               goto out_unlock;
        }
        status = -ENOENT;
        if (!dentry->d_inode)
                goto out;
-
-       status = nfsd4_clear_clid_dir(rec_dir.dentry, dentry);
+       status = vfs_rmdir(rec_dir.dentry->d_inode, dentry);
 out:
        dput(dentry);
+out_unlock:
+       mutex_unlock(&rec_dir.dentry->d_inode->i_mutex);
        return status;
 }
 
@@ -348,7 +320,7 @@ purge_old(struct dentry *parent, struct dentry *child)
        if (nfs4_has_reclaimed_state(child->d_name.name, false))
                return 0;
 
-       status = nfsd4_clear_clid_dir(parent, child);
+       status = vfs_rmdir(parent->d_inode, child);
        if (status)
                printk("failed to remove client recovery directory %s\n",
                                child->d_name.name);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index ab93fcf..6c68ffd 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -116,10 +116,15 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry 
**dpp,
        }
        if ((exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2)) {
                /* successfully crossed mount point */
-               exp_put(exp);
-               *expp = exp2;
+               /*
+                * This is subtle: dentry is *not* under mnt at this point.
+                * The only reason we are safe is that original mnt is pinned
+                * down by exp, so we should dput before putting exp.
+                */
                dput(dentry);
                *dpp = mounts;
+               exp_put(exp);
+               *expp = exp2;
        } else {
                exp_put(exp2);
                dput(mounts);
@@ -1885,8 +1890,8 @@ static int nfsd_buffered_filldir(void *__buf, const char 
*name, int namlen,
        return 0;
 }
 
-static int nfsd_buffered_readdir(struct file *file, filldir_t func,
-                                struct readdir_cd *cdp, loff_t *offsetp)
+static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func,
+                                   struct readdir_cd *cdp, loff_t *offsetp)
 {
        struct readdir_data buf;
        struct buffered_dirent *de;
@@ -1896,11 +1901,12 @@ static int nfsd_buffered_readdir(struct file *file, 
filldir_t func,
 
        buf.dirent = (void *)__get_free_page(GFP_KERNEL);
        if (!buf.dirent)
-               return -ENOMEM;
+               return nfserrno(-ENOMEM);
 
        offset = *offsetp;
 
        while (1) {
+               struct inode *dir_inode = file->f_path.dentry->d_inode;
                unsigned int reclen;
 
                cdp->err = nfserr_eof; /* will be cleared on successful read */
@@ -1919,26 +1925,38 @@ static int nfsd_buffered_readdir(struct file *file, 
filldir_t func,
                if (!size)
                        break;
 
+               /*
+                * Various filldir functions may end up calling back into
+                * lookup_one_len() and the file system's ->lookup() method.
+                * These expect i_mutex to be held, as it would within readdir.
+                */
+               host_err = mutex_lock_killable(&dir_inode->i_mutex);
+               if (host_err)
+                       break;
+
                de = (struct buffered_dirent *)buf.dirent;
                while (size > 0) {
                        offset = de->offset;
 
                        if (func(cdp, de->name, de->namlen, de->offset,
                                 de->ino, de->d_type))
-                               goto done;
+                               break;
 
                        if (cdp->err != nfs_ok)
-                               goto done;
+                               break;
 
                        reclen = ALIGN(sizeof(*de) + de->namlen,
                                       sizeof(u64));
                        size -= reclen;
                        de = (struct buffered_dirent *)((char *)de + reclen);
                }
+               mutex_unlock(&dir_inode->i_mutex);
+               if (size > 0) /* We bailed out early */
+                       break;
+
                offset = vfs_llseek(file, 0, SEEK_CUR);
        }
 
- done:
        free_page((unsigned long)(buf.dirent));
 
        if (host_err)
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index 1758d9f..08afe43 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -261,6 +261,7 @@ void                        
xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie);
 #define XPRT_BINDING           (5)
 #define XPRT_CLOSING           (6)
 #define XPRT_CONNECTION_ABORT  (7)
+#define XPRT_CONNECTION_CLOSE  (8)
 
 static inline void xprt_set_connected(struct rpc_xprt *xprt)
 {
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index a0bfe53..06ca058 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -672,10 +672,8 @@ xprt_init_autodisconnect(unsigned long data)
        if (test_and_set_bit(XPRT_LOCKED, &xprt->state))
                goto out_abort;
        spin_unlock(&xprt->transport_lock);
-       if (xprt_connecting(xprt))
-               xprt_release_write(xprt, NULL);
-       else
-               queue_work(rpciod_workqueue, &xprt->task_cleanup);
+       set_bit(XPRT_CONNECTION_CLOSE, &xprt->state);
+       queue_work(rpciod_workqueue, &xprt->task_cleanup);
        return;
 out_abort:
        spin_unlock(&xprt->transport_lock);
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index d40ff50..e185961 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -807,6 +807,9 @@ static void xs_reset_transport(struct sock_xprt *transport)
  *
  * This is used when all requests are complete; ie, no DRC state remains
  * on the server we want to save.
+ *
+ * The caller _must_ be holding XPRT_LOCKED in order to avoid issues with
+ * xs_reset_transport() zeroing the socket from underneath a writer.
  */
 static void xs_close(struct rpc_xprt *xprt)
 {
@@ -824,6 +827,14 @@ static void xs_close(struct rpc_xprt *xprt)
        xprt_disconnect_done(xprt);
 }
 
+static void xs_tcp_close(struct rpc_xprt *xprt)
+{
+       if (test_and_clear_bit(XPRT_CONNECTION_CLOSE, &xprt->state))
+               xs_close(xprt);
+       else
+               xs_tcp_shutdown(xprt);
+}
+
 /**
  * xs_destroy - prepare to shutdown a transport
  * @xprt: doomed transport
@@ -1772,6 +1783,15 @@ static void xs_tcp_setup_socket(struct rpc_xprt *xprt,
                        xprt, -status, xprt_connected(xprt),
                        sock->sk->sk_state);
        switch (status) {
+       default:
+               printk("%s: connect returned unhandled error %d\n",
+                       __func__, status);
+       case -EADDRNOTAVAIL:
+               /* We're probably in TIME_WAIT. Get rid of existing socket,
+                * and retry
+                */
+               set_bit(XPRT_CONNECTION_CLOSE, &xprt->state);
+               xprt_force_disconnect(xprt);
        case -ECONNREFUSED:
        case -ECONNRESET:
        case -ENETUNREACH:
@@ -1782,10 +1802,6 @@ static void xs_tcp_setup_socket(struct rpc_xprt *xprt,
                xprt_clear_connecting(xprt);
                return;
        }
-       /* get rid of existing socket, and retry */
-       xs_tcp_shutdown(xprt);
-       printk("%s: connect returned unhandled error %d\n",
-                       __func__, status);
 out_eagain:
        status = -EAGAIN;
 out:
@@ -1994,7 +2010,7 @@ static struct rpc_xprt_ops xs_tcp_ops = {
        .buf_free               = rpc_free,
        .send_request           = xs_tcp_send_request,
        .set_retrans_timeout    = xprt_set_retrans_timeout_def,
-       .close                  = xs_tcp_shutdown,
+       .close                  = xs_tcp_close,
        .destroy                = xs_destroy,
        .print_stats            = xs_tcp_print_stats,
 };
_______________________________________________
ewg mailing list
[email protected]
http://lists.openfabrics.org/cgi-bin/mailman/listinfo/ewg

Reply via email to