Merge tag 'nfs-for-3.14-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 28 Jan 2014 16:46:44 +0000 (08:46 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 28 Jan 2014 16:46:44 +0000 (08:46 -0800)
Pull NFS client updates from Trond Myklebust:
 "Highlights include:

   - stable fix for an infinite loop in RPC state machine
   - stable fix for a use after free situation in the NFSv4 trunking discovery
   - stable fix for error handling in the NFSv4 trunking discovery
   - stable fix for the page write update code
   - stable fix for the NFSv4.1 mount time security negotiation
   - stable fix for the NFSv4 open code.
   - O_DIRECT locking fixes
   - fix an Oops in the pnfs file commit code
   - RPC layer needs finer grained handling of connection errors
   - more RPC GSS upcall fixes"

* tag 'nfs-for-3.14-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (30 commits)
  pnfs: Proper delay for NFS4ERR_RECALLCONFLICT in layout_get_done
  pnfs: fix BUG in filelayout_recover_commit_reqs
  nfs4: fix discover_server_trunking use after free
  NFSv4.1: Handle errors correctly in nfs41_walk_client_list
  nfs: always make sure page is up-to-date before extending a write to cover the entire page
  nfs: page cache invalidation for dio
  nfs: take i_mutex during direct I/O reads
  nfs: merge nfs_direct_write into nfs_file_direct_write
  nfs: merge nfs_direct_read into nfs_file_direct_read
  nfs: increment i_dio_count for reads, too
  nfs: defer inode_dio_done call until size update is done
  nfs: fix size updates for aio writes
  nfs4.1: properly handle ENOTSUP in SECINFO_NO_NAME
  NFSv4.1: Fix a race in nfs4_write_inode
  NFSv4.1: Don't trust attributes if a pNFS LAYOUTCOMMIT is outstanding
  point to the right include file in a comment (left over from a9004abc3)
  NFS: dprintk() should not print negative fileids and inode numbers
  nfs: fix dead code of ipv6_addr_scope
  sunrpc: Fix infinite loop in RPC state machine
  SUNRPC: Add tracepoint for socket errors
  ...

1  2 
fs/nfs/inode.c
net/sunrpc/xprt.c
net/sunrpc/xprtsock.c

diff --combined fs/nfs/inode.c
index ecd11ba7f960f1b8c75743b6379ea6f27425462b,c63e152244665990ce20603c8658ec87119f74a1..ea00b34ff0712d6374908a08832cef0acdef82eb
@@@ -458,9 -458,9 +458,9 @@@ nfs_fhget(struct super_block *sb, struc
                unlock_new_inode(inode);
        } else
                nfs_refresh_inode(inode, fattr);
-       dprintk("NFS: nfs_fhget(%s/%Ld fh_crc=0x%08x ct=%d)\n",
+       dprintk("NFS: nfs_fhget(%s/%Lu fh_crc=0x%08x ct=%d)\n",
                inode->i_sb->s_id,
-               (long long)NFS_FILEID(inode),
+               (unsigned long long)NFS_FILEID(inode),
                nfs_display_fhandle_hash(fh),
                atomic_read(&inode->i_count));
  
@@@ -870,8 -870,8 +870,8 @@@ __nfs_revalidate_inode(struct nfs_serve
        struct nfs_fattr *fattr = NULL;
        struct nfs_inode *nfsi = NFS_I(inode);
  
-       dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n",
-               inode->i_sb->s_id, (long long)NFS_FILEID(inode));
+       dfprintk(PAGECACHE, "NFS: revalidating (%s/%Lu)\n",
+               inode->i_sb->s_id, (unsigned long long)NFS_FILEID(inode));
  
        trace_nfs_revalidate_inode_enter(inode);
  
  
        status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr, label);
        if (status != 0) {
-               dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n",
+               dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Lu) getattr failed, error=%d\n",
                         inode->i_sb->s_id,
-                        (long long)NFS_FILEID(inode), status);
+                        (unsigned long long)NFS_FILEID(inode), status);
                if (status == -ESTALE) {
                        nfs_zap_caches(inode);
                        if (!S_ISDIR(inode->i_mode))
  
        status = nfs_refresh_inode(inode, fattr);
        if (status) {
-               dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n",
+               dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Lu) refresh failed, error=%d\n",
                         inode->i_sb->s_id,
-                        (long long)NFS_FILEID(inode), status);
+                        (unsigned long long)NFS_FILEID(inode), status);
                goto err_out;
        }
  
  
        nfs_setsecurity(inode, fattr, label);
  
-       dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n",
+       dfprintk(PAGECACHE, "NFS: (%s/%Lu) revalidation complete\n",
                inode->i_sb->s_id,
-               (long long)NFS_FILEID(inode));
+               (unsigned long long)NFS_FILEID(inode));
  
  err_out:
        nfs4_label_free(label);
@@@ -985,8 -985,9 +985,9 @@@ static int nfs_invalidate_mapping(struc
        nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
        nfs_fscache_wait_on_invalidate(inode);
  
-       dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n",
-                       inode->i_sb->s_id, (long long)NFS_FILEID(inode));
+       dfprintk(PAGECACHE, "NFS: (%s/%Lu) data cache invalidated\n",
+                       inode->i_sb->s_id,
+                       (unsigned long long)NFS_FILEID(inode));
        return 0;
  }
  
@@@ -1282,12 -1283,28 +1283,28 @@@ static int nfs_inode_attrs_need_update(
                ((long)nfsi->attr_gencount - (long)nfs_read_attr_generation_counter() > 0);
  }
  
+ /*
+  * Don't trust the change_attribute, mtime, ctime or size if
+  * a pnfs LAYOUTCOMMIT is outstanding
+  */
+ static void nfs_inode_attrs_handle_layoutcommit(struct inode *inode,
+               struct nfs_fattr *fattr)
+ {
+       if (pnfs_layoutcommit_outstanding(inode))
+               fattr->valid &= ~(NFS_ATTR_FATTR_CHANGE |
+                               NFS_ATTR_FATTR_MTIME |
+                               NFS_ATTR_FATTR_CTIME |
+                               NFS_ATTR_FATTR_SIZE);
+ }
  static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
  {
        int ret;
  
        trace_nfs_refresh_inode_enter(inode);
  
+       nfs_inode_attrs_handle_layoutcommit(inode, fattr);
        if (nfs_inode_attrs_need_update(inode, fattr))
                ret = nfs_update_inode(inode, fattr);
        else
@@@ -1434,7 -1451,7 +1451,7 @@@ static int nfs_update_inode(struct inod
        unsigned long now = jiffies;
        unsigned long save_cache_validity;
  
-       dfprintk(VFS, "NFS: %s(%s/%ld fh_crc=0x%08x ct=%d info=0x%x)\n",
+       dfprintk(VFS, "NFS: %s(%s/%lu fh_crc=0x%08x ct=%d info=0x%x)\n",
                        __func__, inode->i_sb->s_id, inode->i_ino,
                        nfs_display_fhandle_hash(NFS_FH(inode)),
                        atomic_read(&inode->i_count), fattr->valid);
                /*
                * Big trouble! The inode has become a different object.
                */
-               printk(KERN_DEBUG "NFS: %s: inode %ld mode changed, %07o to %07o\n",
+               printk(KERN_DEBUG "NFS: %s: inode %lu mode changed, %07o to %07o\n",
                                __func__, inode->i_ino, inode->i_mode, fattr->mode);
                goto out_err;
        }
                if (new_isize != cur_isize) {
                        /* Do we perhaps have any outstanding writes, or has
                         * the file grown beyond our last write? */
-                       if ((nfsi->npages == 0 && !test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) ||
-                            new_isize > cur_isize) {
+                       if ((nfsi->npages == 0) || new_isize > cur_isize) {
                                i_size_write(inode, new_isize);
                                invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
                        }
@@@ -1641,6 -1657,10 +1657,6 @@@ struct inode *nfs_alloc_inode(struct su
                return NULL;
        nfsi->flags = 0UL;
        nfsi->cache_validity = 0UL;
 -#ifdef CONFIG_NFS_V3_ACL
 -      nfsi->acl_access = ERR_PTR(-EAGAIN);
 -      nfsi->acl_default = ERR_PTR(-EAGAIN);
 -#endif
  #if IS_ENABLED(CONFIG_NFS_V4)
        nfsi->nfs4_acl = NULL;
  #endif /* CONFIG_NFS_V4 */
diff --combined net/sunrpc/xprt.c
index 1750048130a7c0d305a51c87c38d539ee3001fd7,ddd198e90292ddc9ffa5fb893057e5bed0aa1ff3..7d4df99f761faa27de43af1b27640e412a3dc8a0
@@@ -749,6 -749,11 +749,11 @@@ static void xprt_connect_status(struct 
        }
  
        switch (task->tk_status) {
+       case -ECONNREFUSED:
+       case -ECONNRESET:
+       case -ECONNABORTED:
+       case -ENETUNREACH:
+       case -EHOSTUNREACH:
        case -EAGAIN:
                dprintk("RPC: %5u xprt_connect_status: retrying\n", task->tk_pid);
                break;
@@@ -1188,7 -1193,7 +1193,7 @@@ static inline __be32 xprt_alloc_xid(str
  
  static inline void xprt_init_xid(struct rpc_xprt *xprt)
  {
 -      xprt->xid = net_random();
 +      xprt->xid = prandom_u32();
  }
  
  static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
diff --combined net/sunrpc/xprtsock.c
index 75b045e1cd50b00096a3a2ec938c2f82423dffce,25dbfa9719482acef0e9d859c1172a04493f8869..2a7ca8ffe83a9ad47576959b30f9664cc3996b0a
@@@ -257,6 -257,7 +257,7 @@@ struct sock_xprt 
        void                    (*old_data_ready)(struct sock *, int);
        void                    (*old_state_change)(struct sock *);
        void                    (*old_write_space)(struct sock *);
+       void                    (*old_error_report)(struct sock *);
  };
  
  /*
   */
  #define TCP_RPC_REPLY         (1UL << 6)
  
+ static inline struct rpc_xprt *xprt_from_sock(struct sock *sk)
+ {
+       return (struct rpc_xprt *) sk->sk_user_data;
+ }
  static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt)
  {
        return (struct sockaddr *) &xprt->addr;
@@@ -799,6 -805,7 +805,7 @@@ static void xs_save_old_callbacks(struc
        transport->old_data_ready = sk->sk_data_ready;
        transport->old_state_change = sk->sk_state_change;
        transport->old_write_space = sk->sk_write_space;
+       transport->old_error_report = sk->sk_error_report;
  }
  
  static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *sk)
        sk->sk_data_ready = transport->old_data_ready;
        sk->sk_state_change = transport->old_state_change;
        sk->sk_write_space = transport->old_write_space;
+       sk->sk_error_report = transport->old_error_report;
+ }
+ /**
+  * xs_error_report - callback to handle TCP socket state errors
+  * @sk: socket
+  *
+  * Note: we don't call sock_error() since there may be a rpc_task
+  * using the socket, and so we don't want to clear sk->sk_err.
+  */
+ static void xs_error_report(struct sock *sk)
+ {
+       struct rpc_xprt *xprt;
+       int err;
+       read_lock_bh(&sk->sk_callback_lock);
+       if (!(xprt = xprt_from_sock(sk)))
+               goto out;
+       err = -sk->sk_err;
+       if (err == 0)
+               goto out;
+       dprintk("RPC:       xs_error_report client %p, error=%d...\n",
+                       xprt, -err);
+       trace_rpc_socket_error(xprt, sk->sk_socket, err);
+       xprt_wake_pending_tasks(xprt, err);
+  out:
+       read_unlock_bh(&sk->sk_callback_lock);
  }
  
  static void xs_reset_transport(struct sock_xprt *transport)
@@@ -885,11 -920,6 +920,6 @@@ static void xs_destroy(struct rpc_xprt 
        module_put(THIS_MODULE);
  }
  
- static inline struct rpc_xprt *xprt_from_sock(struct sock *sk)
- {
-       return (struct rpc_xprt *) sk->sk_user_data;
- }
  static int xs_local_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb)
  {
        struct xdr_skb_reader desc = {
@@@ -1674,7 -1704,7 +1704,7 @@@ static void xs_udp_timer(struct rpc_xpr
  static unsigned short xs_get_random_port(void)
  {
        unsigned short range = xprt_max_resvport - xprt_min_resvport;
 -      unsigned short rand = (unsigned short) net_random() % range;
 +      unsigned short rand = (unsigned short) prandom_u32() % range;
        return rand + xprt_min_resvport;
  }
  
@@@ -1869,6 -1899,7 +1899,7 @@@ static int xs_local_finish_connecting(s
                sk->sk_user_data = xprt;
                sk->sk_data_ready = xs_local_data_ready;
                sk->sk_write_space = xs_udp_write_space;
+               sk->sk_error_report = xs_error_report;
                sk->sk_allocation = GFP_ATOMIC;
  
                xprt_clear_connected(xprt);
@@@ -2146,6 -2177,7 +2177,7 @@@ static int xs_tcp_finish_connecting(str
                sk->sk_data_ready = xs_tcp_data_ready;
                sk->sk_state_change = xs_tcp_state_change;
                sk->sk_write_space = xs_tcp_write_space;
+               sk->sk_error_report = xs_error_report;
                sk->sk_allocation = GFP_ATOMIC;
  
                /* socket options */