Merge tag 'nfs-for-3.9-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 3 Mar 2013 00:46:07 +0000 (16:46 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 3 Mar 2013 00:46:07 +0000 (16:46 -0800)
Pull NFS client bugfixes from Trond Myklebust:
 "We've just concluded another Connectathon interoperability testing
  week, and so here are the fixes for the bugs that were discovered:

   - Don't allow NFS silly-renamed files to be deleted
   - Don't start the retransmission timer when out of socket space
   - Fix a couple of pnfs-related Oopses.
   - Fix one more NFSv4 state recovery deadlock
   - Don't loop forever when LAYOUTGET returns NFS4ERR_LAYOUTTRYLATER"

* tag 'nfs-for-3.9-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  SUNRPC: One line comment fix
  NFSv4.1: LAYOUTGET EDELAY loops timeout to the MDS
  SUNRPC: add call to get configured timeout
  PNFS: set the default DS timeout to 60 seconds
  NFSv4: Fix another open/open_recovery deadlock
  nfs: don't allow nfs_find_actor to match inodes of the wrong type
  NFSv4.1: Hold reference to layout hdr in layoutget
  pnfs: fix resend_to_mds for directio
  SUNRPC: Don't start the retransmission timer when out of socket space
  NFS: Don't allow NFS silly-renamed files to be deleted, no signal

1  2 
fs/nfs/inode.c
include/linux/nfs_xdr.h
include/linux/sunrpc/clnt.h
net/sunrpc/clnt.c

diff --combined fs/nfs/inode.c
@@@ -237,6 -237,8 +237,8 @@@ nfs_find_actor(struct inode *inode, voi
  
        if (NFS_FILEID(inode) != fattr->fileid)
                return 0;
+       if ((S_IFMT & inode->i_mode) != (S_IFMT & fattr->mode))
+               return 0;
        if (nfs_compare_fh(NFS_FH(inode), fh))
                return 0;
        if (is_bad_inode(inode) || NFS_STALE(inode))
@@@ -332,8 -334,8 +334,8 @@@ nfs_fhget(struct super_block *sb, struc
                inode->i_version = 0;
                inode->i_size = 0;
                clear_nlink(inode);
 -              inode->i_uid = -2;
 -              inode->i_gid = -2;
 +              inode->i_uid = make_kuid(&init_user_ns, -2);
 +              inode->i_gid = make_kgid(&init_user_ns, -2);
                inode->i_blocks = 0;
                memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
                nfsi->write_io = 0;
@@@ -711,7 -713,7 +713,7 @@@ EXPORT_SYMBOL_GPL(put_nfs_open_context)
   */
  void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx)
  {
 -      struct inode *inode = filp->f_path.dentry->d_inode;
 +      struct inode *inode = file_inode(filp);
        struct nfs_inode *nfsi = NFS_I(inode);
  
        filp->private_data = get_nfs_open_context(ctx);
@@@ -744,7 -746,7 +746,7 @@@ struct nfs_open_context *nfs_find_open_
  
  static void nfs_file_clear_open_context(struct file *filp)
  {
 -      struct inode *inode = filp->f_path.dentry->d_inode;
 +      struct inode *inode = file_inode(filp);
        struct nfs_open_context *ctx = nfs_file_open_context(filp);
  
        if (ctx) {
@@@ -1006,9 -1008,9 +1008,9 @@@ static int nfs_check_inode_attributes(s
        /* Have any file permissions changed? */
        if ((fattr->valid & NFS_ATTR_FATTR_MODE) && (inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO))
                invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
 -      if ((fattr->valid & NFS_ATTR_FATTR_OWNER) && inode->i_uid != fattr->uid)
 +      if ((fattr->valid & NFS_ATTR_FATTR_OWNER) && !uid_eq(inode->i_uid, fattr->uid))
                invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
 -      if ((fattr->valid & NFS_ATTR_FATTR_GROUP) && inode->i_gid != fattr->gid)
 +      if ((fattr->valid & NFS_ATTR_FATTR_GROUP) && !gid_eq(inode->i_gid, fattr->gid))
                invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL;
  
        /* Has the link count changed? */
@@@ -1437,7 -1439,7 +1439,7 @@@ static int nfs_update_inode(struct inod
                                | NFS_INO_REVAL_FORCED);
  
        if (fattr->valid & NFS_ATTR_FATTR_OWNER) {
 -              if (inode->i_uid != fattr->uid) {
 +              if (!uid_eq(inode->i_uid, fattr->uid)) {
                        invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
                        inode->i_uid = fattr->uid;
                }
                                | NFS_INO_REVAL_FORCED);
  
        if (fattr->valid & NFS_ATTR_FATTR_GROUP) {
 -              if (inode->i_gid != fattr->gid) {
 +              if (!gid_eq(inode->i_gid, fattr->gid)) {
                        invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL;
                        inode->i_gid = fattr->gid;
                }
diff --combined include/linux/nfs_xdr.h
@@@ -48,8 -48,8 +48,8 @@@ struct nfs_fattr 
        unsigned int            valid;          /* which fields are valid */
        umode_t                 mode;
        __u32                   nlink;
 -      __u32                   uid;
 -      __u32                   gid;
 +      kuid_t                  uid;
 +      kgid_t                  gid;
        dev_t                   rdev;
        __u64                   size;
        union {
@@@ -233,6 -233,7 +233,7 @@@ struct nfs4_layoutget_args 
        struct inode *inode;
        struct nfs_open_context *ctx;
        nfs4_stateid stateid;
+       unsigned long timestamp;
        struct nfs4_layoutdriver_data layout;
  };
  
@@@ -160,10 -160,163 +160,11 @@@ void           rpc_setbufsize(struct rpc_clnt *
  int           rpc_protocol(struct rpc_clnt *);
  struct net *  rpc_net_ns(struct rpc_clnt *);
  size_t                rpc_max_payload(struct rpc_clnt *);
+ unsigned long rpc_get_timeout(struct rpc_clnt *clnt);
  void          rpc_force_rebind(struct rpc_clnt *);
  size_t                rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t);
  const char    *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t);
  int           rpc_localaddr(struct rpc_clnt *, struct sockaddr *, size_t);
  
 -size_t                rpc_ntop(const struct sockaddr *, char *, const size_t);
 -size_t                rpc_pton(struct net *, const char *, const size_t,
 -                       struct sockaddr *, const size_t);
 -char *                rpc_sockaddr2uaddr(const struct sockaddr *, gfp_t);
 -size_t                rpc_uaddr2sockaddr(struct net *, const char *, const size_t,
 -                                 struct sockaddr *, const size_t);
 -
 -static inline unsigned short rpc_get_port(const struct sockaddr *sap)
 -{
 -      switch (sap->sa_family) {
 -      case AF_INET:
 -              return ntohs(((struct sockaddr_in *)sap)->sin_port);
 -      case AF_INET6:
 -              return ntohs(((struct sockaddr_in6 *)sap)->sin6_port);
 -      }
 -      return 0;
 -}
 -
 -static inline void rpc_set_port(struct sockaddr *sap,
 -                              const unsigned short port)
 -{
 -      switch (sap->sa_family) {
 -      case AF_INET:
 -              ((struct sockaddr_in *)sap)->sin_port = htons(port);
 -              break;
 -      case AF_INET6:
 -              ((struct sockaddr_in6 *)sap)->sin6_port = htons(port);
 -              break;
 -      }
 -}
 -
 -#define IPV6_SCOPE_DELIMITER          '%'
 -#define IPV6_SCOPE_ID_LEN             sizeof("%nnnnnnnnnn")
 -
 -static inline bool __rpc_cmp_addr4(const struct sockaddr *sap1,
 -                                 const struct sockaddr *sap2)
 -{
 -      const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sap1;
 -      const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sap2;
 -
 -      return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
 -}
 -
 -static inline bool __rpc_copy_addr4(struct sockaddr *dst,
 -                                  const struct sockaddr *src)
 -{
 -      const struct sockaddr_in *ssin = (struct sockaddr_in *) src;
 -      struct sockaddr_in *dsin = (struct sockaddr_in *) dst;
 -
 -      dsin->sin_family = ssin->sin_family;
 -      dsin->sin_addr.s_addr = ssin->sin_addr.s_addr;
 -      return true;
 -}
 -
 -#if IS_ENABLED(CONFIG_IPV6)
 -static inline bool __rpc_cmp_addr6(const struct sockaddr *sap1,
 -                                 const struct sockaddr *sap2)
 -{
 -      const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sap1;
 -      const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sap2;
 -
 -      if (!ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr))
 -              return false;
 -      else if (ipv6_addr_type(&sin1->sin6_addr) & IPV6_ADDR_LINKLOCAL)
 -              return sin1->sin6_scope_id == sin2->sin6_scope_id;
 -
 -      return true;
 -}
 -
 -static inline bool __rpc_copy_addr6(struct sockaddr *dst,
 -                                  const struct sockaddr *src)
 -{
 -      const struct sockaddr_in6 *ssin6 = (const struct sockaddr_in6 *) src;
 -      struct sockaddr_in6 *dsin6 = (struct sockaddr_in6 *) dst;
 -
 -      dsin6->sin6_family = ssin6->sin6_family;
 -      dsin6->sin6_addr = ssin6->sin6_addr;
 -      return true;
 -}
 -#else /* !(IS_ENABLED(CONFIG_IPV6) */
 -static inline bool __rpc_cmp_addr6(const struct sockaddr *sap1,
 -                                 const struct sockaddr *sap2)
 -{
 -      return false;
 -}
 -
 -static inline bool __rpc_copy_addr6(struct sockaddr *dst,
 -                                  const struct sockaddr *src)
 -{
 -      return false;
 -}
 -#endif        /* !(IS_ENABLED(CONFIG_IPV6) */
 -
 -/**
 - * rpc_cmp_addr - compare the address portion of two sockaddrs.
 - * @sap1: first sockaddr
 - * @sap2: second sockaddr
 - *
 - * Just compares the family and address portion. Ignores port, scope, etc.
 - * Returns true if the addrs are equal, false if they aren't.
 - */
 -static inline bool rpc_cmp_addr(const struct sockaddr *sap1,
 -                              const struct sockaddr *sap2)
 -{
 -      if (sap1->sa_family == sap2->sa_family) {
 -              switch (sap1->sa_family) {
 -              case AF_INET:
 -                      return __rpc_cmp_addr4(sap1, sap2);
 -              case AF_INET6:
 -                      return __rpc_cmp_addr6(sap1, sap2);
 -              }
 -      }
 -      return false;
 -}
 -
 -/**
 - * rpc_copy_addr - copy the address portion of one sockaddr to another
 - * @dst: destination sockaddr
 - * @src: source sockaddr
 - *
 - * Just copies the address portion and family. Ignores port, scope, etc.
 - * Caller is responsible for making certain that dst is large enough to hold
 - * the address in src. Returns true if address family is supported. Returns
 - * false otherwise.
 - */
 -static inline bool rpc_copy_addr(struct sockaddr *dst,
 -                               const struct sockaddr *src)
 -{
 -      switch (src->sa_family) {
 -      case AF_INET:
 -              return __rpc_copy_addr4(dst, src);
 -      case AF_INET6:
 -              return __rpc_copy_addr6(dst, src);
 -      }
 -      return false;
 -}
 -
 -/**
 - * rpc_get_scope_id - return scopeid for a given sockaddr
 - * @sa: sockaddr to get scopeid from
 - *
 - * Returns the value of the sin6_scope_id for AF_INET6 addrs, or 0 if
 - * not an AF_INET6 address.
 - */
 -static inline u32 rpc_get_scope_id(const struct sockaddr *sa)
 -{
 -      if (sa->sa_family != AF_INET6)
 -              return 0;
 -
 -      return ((struct sockaddr_in6 *) sa)->sin6_scope_id;
 -}
 -
  #endif /* __KERNEL__ */
  #endif /* _LINUX_SUNRPC_CLNT_H */
diff --combined net/sunrpc/clnt.c
@@@ -33,7 -33,6 +33,7 @@@
  #include <linux/rcupdate.h>
  
  #include <linux/sunrpc/clnt.h>
 +#include <linux/sunrpc/addr.h>
  #include <linux/sunrpc/rpc_pipe_fs.h>
  #include <linux/sunrpc/metrics.h>
  #include <linux/sunrpc/bc_xprt.h>
@@@ -1196,6 -1195,21 +1196,21 @@@ size_t rpc_max_payload(struct rpc_clnt 
  }
  EXPORT_SYMBOL_GPL(rpc_max_payload);
  
+ /**
+  * rpc_get_timeout - Get timeout for transport in units of HZ
+  * @clnt: RPC client to query
+  */
+ unsigned long rpc_get_timeout(struct rpc_clnt *clnt)
+ {
+       unsigned long ret;
+       rcu_read_lock();
+       ret = rcu_dereference(clnt->cl_xprt)->timeout->to_initval;
+       rcu_read_unlock();
+       return ret;
+ }
+ EXPORT_SYMBOL_GPL(rpc_get_timeout);
  /**
   * rpc_force_rebind - force transport to check that remote port is unchanged
   * @clnt: client to rebind