Print this page
OS-20 share_nfs(1m) charset handling is unreliable
OS-22 Page fault at nfscmd_dropped_entrysize+0x1e()
OS-23 NFSv2/3/4: READDIR responses are inconsistent when charset conversion fails
OS-24 rfs3_readdir(): Issues related to nfscmd_convdirent()
Reviewed by: Jan Kryl <jan.kryl@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>

@@ -26,10 +26,11 @@
 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
 /* All Rights Reserved */
 
 /*
  * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
  */
 
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/systm.h>

@@ -2008,101 +2009,33 @@
         if (!xdr_u_longlong_t(xdrs, &objp->cookieverf))
                 return (FALSE);
         return (xdr_u_int(xdrs, &objp->count));
 }
 
-#ifdef  nextdp
-#undef  nextdp
-#endif
-#define nextdp(dp)      ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
-#ifdef  roundup
-#undef  roundup
-#endif
-#define roundup(x, y)   ((((x) + ((y) - 1)) / (y)) * (y))
-
 /*
  * ENCODE ONLY
  */
 static bool_t
 xdr_putdirlist(XDR *xdrs, READDIR3resok *objp)
 {
-        struct dirent64 *dp;
-        char *name;
-        int size;
-        int bufsize;
-        uint_t namlen;
         bool_t true = TRUE;
         bool_t false = FALSE;
-        int entrysz;
-        int tofit;
-        fileid3 fileid;
-        cookie3 cookie;
+        entry3 *entry;
 
         if (xdrs->x_op != XDR_ENCODE)
                 return (FALSE);
 
-        /*
-         * bufsize is used to keep track of the size of the response.
-         * It is primed with:
-         *      1 for the status +
-         *      1 for the dir_attributes.attributes boolean +
-         *      2 for the cookie verifier
-         * all times BYTES_PER_XDR_UNIT to convert from XDR units
-         * to bytes.  If there are directory attributes to be
-         * returned, then:
-         *      NFS3_SIZEOF_FATTR3 for the dir_attributes.attr fattr3
-         * time BYTES_PER_XDR_UNIT is added to account for them.
-         */
-        bufsize = (1 + 1 + 2) * BYTES_PER_XDR_UNIT;
-        if (objp->dir_attributes.attributes)
-                bufsize += NFS3_SIZEOF_FATTR3 * BYTES_PER_XDR_UNIT;
-        for (size = objp->size, dp = (struct dirent64 *)objp->reply.entries;
-            size > 0;
-            size -= dp->d_reclen, dp = nextdp(dp)) {
-                if (dp->d_reclen == 0)
-                        return (FALSE);
-                if (dp->d_ino == 0)
-                        continue;
-                name = dp->d_name;
-                namlen = (uint_t)strlen(dp->d_name);
-                /*
-                 * An entry is composed of:
-                 *      1 for the true/false list indicator +
-                 *      2 for the fileid +
-                 *      1 for the length of the name +
-                 *      2 for the cookie +
-                 * all times BYTES_PER_XDR_UNIT to convert from
-                 * XDR units to bytes, plus the length of the name
-                 * rounded up to the nearest BYTES_PER_XDR_UNIT.
-                 */
-                entrysz = (1 + 2 + 1 + 2) * BYTES_PER_XDR_UNIT +
-                    roundup(namlen, BYTES_PER_XDR_UNIT);
-                /*
-                 * We need to check to see if the number of bytes left
-                 * to go into the buffer will actually fit into the
-                 * buffer.  This is calculated as the size of this
-                 * entry plus:
-                 *      1 for the true/false list indicator +
-                 *      1 for the eof indicator
-                 * times BYTES_PER_XDR_UNIT to convert from from
-                 * XDR units to bytes.
-                 */
-                tofit = entrysz + (1 + 1) * BYTES_PER_XDR_UNIT;
-                if (bufsize + tofit > objp->count) {
-                        objp->reply.eof = FALSE;
-                        break;
-                }
-                fileid = (fileid3)(dp->d_ino);
-                cookie = (cookie3)(dp->d_off);
+        for (entry = objp->reply.entries; entry != NULL;
+            entry = entry->nextentry) {
                 if (!xdr_bool(xdrs, &true) ||
-                    !xdr_u_longlong_t(xdrs, &fileid) ||
-                    !xdr_bytes(xdrs, &name, &namlen, ~0) ||
-                    !xdr_u_longlong_t(xdrs, &cookie)) {
+                    !xdr_u_longlong_t(xdrs, &entry->fileid) ||
+                    !xdr_string(xdrs, &entry->name, MAXPATHLEN) ||
+                    !xdr_u_longlong_t(xdrs, &entry->cookie)) {
                         return (FALSE);
                 }
-                bufsize += entrysz;
         }
+
         if (!xdr_bool(xdrs, &false))
                 return (FALSE);
         if (!xdr_bool(xdrs, &objp->reply.eof))
                 return (FALSE);
         return (TRUE);

@@ -2285,46 +2218,28 @@
  * ENCODE ONLY
  */
 static bool_t
 xdr_putdirpluslist(XDR *xdrs, READDIRPLUS3resok *objp)
 {
-        struct dirent64 *dp;
-        char *name;
-        int nents;
         bool_t true = TRUE;
         bool_t false = FALSE;
-        fileid3 fileid;
-        cookie3 cookie;
-        entryplus3_info *infop;
+        entryplus3 *entry;
 
         if (xdrs->x_op != XDR_ENCODE)
                 return (FALSE);
 
-        dp = (struct dirent64 *)objp->reply.entries;
-        nents = objp->size;
-        infop = objp->infop;
-
-        while (nents > 0) {
-                if (dp->d_reclen == 0)
-                        return (FALSE);
-                if (dp->d_ino != 0) {
-                        name = dp->d_name;
-                        fileid = (fileid3)(dp->d_ino);
-                        cookie = (cookie3)(dp->d_off);
+        for (entry = objp->reply.entries; entry != NULL;
+            entry = entry->nextentry) {
                         if (!xdr_bool(xdrs, &true) ||
-                            !xdr_u_longlong_t(xdrs, &fileid) ||
-                            !xdr_bytes(xdrs, &name, &infop->namelen, ~0) ||
-                            !xdr_u_longlong_t(xdrs, &cookie) ||
-                            !xdr_post_op_attr(xdrs, &infop->attr) ||
-                            !xdr_post_op_fh3(xdrs, &infop->fh)) {
+                    !xdr_u_longlong_t(xdrs, &entry->fileid) ||
+                    !xdr_string(xdrs, &entry->name, MAXPATHLEN) ||
+                    !xdr_u_longlong_t(xdrs, &entry->cookie) ||
+                    !xdr_post_op_attr(xdrs, &entry->name_attributes) ||
+                    !xdr_post_op_fh3(xdrs, &entry->name_handle)) {
                                 return (FALSE);
                         }
                 }
-                dp = nextdp(dp);
-                infop++;
-                nents--;
-        }
 
         if (!xdr_bool(xdrs, &false))
                 return (FALSE);
         if (!xdr_bool(xdrs, &objp->reply.eof))
                 return (FALSE);