Patchwork [BUG:942,1/6] nfs3: Funge . and .. ino/gen in readdir of root

login
register
Submitter Shehjar Tikoo
Date 2010-06-01 04:13:52
Message ID <1275365637-30417-1-git-send-email-shehjart@gluster.com>
Download mbox | patch
Permalink /patch/3354/
State Accepted
Delegated to: Anand Avati
Headers show

Comments

Shehjar Tikoo - 2010-06-01 04:13:52
From: Shehjar Tikoo <shehjart@gluster.com>

In the readdir reply for the root of the export, replace the ino
and gen number for the . and .. entries with 1 and 0 respectively.
On clients which inspect this field, the client will error out due
to the change in inode number of the root directory when see for "."

.. also needs to be replaced because we do not have a concept of
the parent directory of root. The return of 1 and 0 is the same as
the behaviour of: stat /.. command.

Signed-off-by: Shehjar Tikoo <shehjart@gluster.com>
---
 xlators/nfs/server/src/nfs3-helpers.c |   82 ++++++++++++++++++++++++++++++---
 xlators/nfs/server/src/nfs3-helpers.h |    9 ++-
 xlators/nfs/server/src/nfs3.c         |   44 ++++++------------
 3 files changed, 96 insertions(+), 39 deletions(-)

Patch

diff --git a/xlators/nfs/server/src/nfs3-helpers.c b/xlators/nfs/server/src/nfs3-helpers.c
index feab7b5..95e8601 100644
--- a/xlators/nfs/server/src/nfs3-helpers.c
+++ b/xlators/nfs/server/src/nfs3-helpers.c
@@ -702,11 +702,64 @@  nfs3_prep_readdir3args (readdir3args *ra, struct nfs3_fh *fh)
 }
 
 
+int
+nfs3_is_dot_entry (char *entry)
+{
+        int     ret = 0;
+
+        if (!entry)
+                return 0;
+
+        if (strcmp (entry, ".") == 0)
+                ret = 1;
+
+        return ret;
+}
+
+
+int
+nfs3_is_parentdir_entry (char *entry)
+{
+        int     ret = 0;
+
+        if (!entry)
+                return 0;
+
+        if (strcmp (entry, "..") == 0)
+                ret = 1;
+
+        return ret;
+}
+
+
+void
+nfs3_funge_root_dotdot_dirent (gf_dirent_t *ent, struct nfs3_fh *dfh)
+{
+        if ((!ent) || (!dfh))
+                return;
+
+        if (nfs3_fh_is_root_fh (dfh) &&
+            nfs3_is_parentdir_entry (ent->d_name)) {
+                ent->d_ino = 1;
+                ent->d_stat.ia_ino = 1;
+                ent->d_stat.ia_gen = 0;
+        }
+
+        if (nfs3_fh_is_root_fh (dfh) &&
+            nfs3_is_dot_entry (ent->d_name)) {
+                ent->d_ino = 1;
+                ent->d_stat.ia_ino = 1;
+                ent->d_stat.ia_gen = 0;
+        }
+
+}
+
+
 entry3 *
-nfs3_fill_entry3 (gf_dirent_t *entry)
+nfs3_fill_entry3 (gf_dirent_t *entry, struct nfs3_fh *dfh)
 {
         entry3          *ent = NULL;
-        if (!entry)
+        if ((!entry) || (!dfh))
                 return NULL;
 
         ent = GF_CALLOC (1, sizeof (*ent), gf_nfs_mt_entry3);
@@ -714,6 +767,14 @@  nfs3_fill_entry3 (gf_dirent_t *entry)
                 return NULL;
 
         gf_log (GF_NFS3, GF_LOG_TRACE, "Entry: %s", entry->d_name);
+
+        /* If the entry is . or .., we need to replace the physical ino and gen
+         * with 1 and 0 respectively if the directory is root. This funging is
+         * needed because there is no parent directory of the root. In that
+         * sense the behavious we provide is similar to the output of the
+         * command: "stat /.."
+         */
+        nfs3_funge_root_dotdot_dirent (entry, dfh);
         ent->fileid = entry->d_ino;
         ent->cookie = entry->d_off;
         ent->name = GF_CALLOC ((strlen (entry->d_name) + 1), sizeof (char),
@@ -775,6 +836,13 @@  nfs3_fill_entryp3 (gf_dirent_t *entry, struct nfs3_fh *dirfh)
         if ((!entry) || (!dirfh))
                 return NULL;
 
+        /* If the entry is . or .., we need to replace the physical ino and gen
+         * with 1 and 0 respectively if the directory is root. This funging is
+         * needed because there is no parent directory of the root. In that
+         * sense the behavious we provide is similar to the output of the
+         * command: "stat /.."
+         */
+        nfs3_funge_root_dotdot_dirent (entry, dirfh);
         gf_log (GF_NFS3, GF_LOG_TRACE, "Entry: %s, ino: %"PRIu64,
                 entry->d_name, entry->d_ino);
         ent = GF_CALLOC (1, sizeof (*ent), gf_nfs_mt_entryp3);
@@ -802,9 +870,9 @@  err:
 
 
 void
-nfs3_fill_readdir3res (readdir3res *res, nfsstat3 stat, uint64_t cverf,
-                       struct iatt *dirstat, gf_dirent_t *entries, count3 count,
-                       int is_eof, uint16_t xlid)
+nfs3_fill_readdir3res (readdir3res *res, nfsstat3 stat, struct nfs3_fh *dirfh,
+                       uint64_t cverf, struct iatt *dirstat,
+                       gf_dirent_t *entries, count3 count, int is_eof)
 {
         post_op_attr    dirattr;
         entry3          *ent = NULL;
@@ -818,7 +886,7 @@  nfs3_fill_readdir3res (readdir3res *res, nfsstat3 stat, uint64_t cverf,
         if (stat != NFS3_OK)
                 return;
 
-        nfs3_map_xlid_to_statdev (dirstat, xlid);
+        nfs3_map_xlid_to_statdev (dirstat, dirfh->xlatorid);
         dirattr = nfs3_stat_to_post_op_attr (dirstat);
         res->readdir3res_u.resok.dir_attributes = dirattr;
         res->readdir3res_u.resok.reply.eof = (bool_t)is_eof;
@@ -834,7 +902,7 @@  nfs3_fill_readdir3res (readdir3res *res, nfsstat3 stat, uint64_t cverf,
                     (strcmp (entries->d_name, "..") == 0))
                         goto nextentry;
                         */
-                ent = nfs3_fill_entry3 (entries);
+                ent = nfs3_fill_entry3 (entries, dirfh);
                 if (!ent)
                         break;
 
diff --git a/xlators/nfs/server/src/nfs3-helpers.h b/xlators/nfs/server/src/nfs3-helpers.h
index 26bc11f..db76b5c 100644
--- a/xlators/nfs/server/src/nfs3-helpers.h
+++ b/xlators/nfs/server/src/nfs3-helpers.h
@@ -111,9 +111,9 @@  extern void
 nfs3_prep_readdir3args (readdir3args *ra, struct nfs3_fh *fh);
 
 extern void
-nfs3_fill_readdir3res (readdir3res *res, nfsstat3 stat, uint64_t cverf,
-                       struct iatt *dirstat, gf_dirent_t *entries,count3 count,
-                       int is_eof, uint16_t xlid);
+nfs3_fill_readdir3res (readdir3res *res, nfsstat3 stat, struct nfs3_fh *dfh,
+                       uint64_t cverf, struct iatt *dirstat,
+                       gf_dirent_t *entries, count3 count, int is_eof);
 
 extern void
 nfs3_prep_readdirp3args (readdirp3args *ra, struct nfs3_fh *fh);
@@ -339,4 +339,7 @@  nfs3_verify_dircookie (struct nfs3_state *nfs3, fd_t *dirfd, cookie3 cookie,
 
 extern int
 nfs3_fdcache_remove (struct nfs3_state *nfs3, fd_t *fd);
+
+extern int
+nfs3_is_parentdir_entry (char *entry);
 #endif
diff --git a/xlators/nfs/server/src/nfs3.c b/xlators/nfs/server/src/nfs3.c
index 385a4a3..f09ed95 100644
--- a/xlators/nfs/server/src/nfs3.c
+++ b/xlators/nfs/server/src/nfs3.c
@@ -993,21 +993,6 @@  nfs3err:
 
 
 int
-nfs3_is_parentdir_entry (char *entry)
-{
-        int     ret = 0;
-
-        if (!entry)
-                return 0;
-
-        if (strcmp (entry, "..") == 0)
-                ret = 1;
-
-        return ret;
-}
-
-
-int
 nfs3_lookup (rpcsvc_request_t *req, struct nfs3_fh *fh, int fhlen, char *name)
 {
         xlator_t                        *vol = NULL;
@@ -3627,16 +3612,14 @@  nfs3_readdirp_reply (rpcsvc_request_t *req, nfsstat3 stat,struct nfs3_fh *dirfh,
 
 
 int
-nfs3_readdir_reply (rpcsvc_request_t *req, nfsstat3 stat, uint64_t cverf,
-                    struct iatt *dirstat, gf_dirent_t *entries, count3 count,
-                    int is_eof)
+nfs3_readdir_reply (rpcsvc_request_t *req, nfsstat3 stat, struct nfs3_fh *dirfh,
+                    uint64_t cverf, struct iatt *dirstat, gf_dirent_t *entries,
+                    count3 count, int is_eof)
 {
         readdir3res     res = {0, };
-        uint16_t        xlid = 0;
 
-        xlid = nfs3_request_xlator_id (req);
-        nfs3_fill_readdir3res (&res, stat, cverf, dirstat, entries, count,
-                               is_eof, xlid);
+        nfs3_fill_readdir3res (&res, stat, dirfh, cverf, dirstat, entries, count
+                               , is_eof);
         nfs3svc_submit_reply (req, (void *)&res,
                               (nfs3_serializer) xdr_serialize_readdir3res);
         nfs3_free_readdir3res (&res);
@@ -3673,9 +3656,9 @@  nfs3err:
                 nfs3_log_readdir_res (rpcsvc_request_xid (cs->req), stat,
                                       op_errno, (uintptr_t)cs->fd,
                                       cs->dircount, is_eof);
-                nfs3_readdir_reply (cs->req, stat, (uintptr_t)cs->fd,
-                                    buf, &cs->entries, cs->dircount,
-                                    is_eof);
+                nfs3_readdir_reply (cs->req, stat, &cs->parent,
+                                    (uintptr_t)cs->fd, buf, &cs->entries,
+                                    cs->dircount, is_eof);
         } else {
                 nfs3_log_readdirp_res (rpcsvc_request_xid (cs->req), stat,
                                        op_errno, (uintptr_t)cs->fd,
@@ -3730,7 +3713,7 @@  err:
         if (cs->maxcount == 0) {
                 nfs3_log_common_res (rpcsvc_request_xid (cs->req), "READDIR",
                                      stat, op_errno);
-                nfs3_readdir_reply (cs->req, stat, 0, NULL, NULL, 0, 0);
+                nfs3_readdir_reply (cs->req, stat, NULL, 0, NULL, NULL, 0, 0);
         } else {
                 nfs3_log_common_res (rpcsvc_request_xid (cs->req), "READDIRP"
                                      , stat, op_errno);
@@ -3791,7 +3774,8 @@  nfs3err:
                 if (cs->maxcount == 0) {
                         nfs3_log_common_res (rpcsvc_request_xid (cs->req),
                                              "READDIR", stat, -ret);
-                        nfs3_readdir_reply (cs->req, stat, 0, NULL, NULL, 0, 0);
+                        nfs3_readdir_reply (cs->req, stat, NULL, 0, NULL, NULL,
+                                            0, 0);
                 } else {
                         nfs3_log_common_res (rpcsvc_request_xid (cs->req),
                                              "READDIRP", stat, -ret);
@@ -3826,7 +3810,8 @@  nfs3err:
                 if (cs->maxcount == 0) {
                         nfs3_log_common_res (rpcsvc_request_xid (cs->req),
                                              "READDIR", stat, -ret);
-                        nfs3_readdir_reply (cs->req, stat, 0, NULL, NULL, 0, 0);
+                        nfs3_readdir_reply (cs->req, stat, NULL, 0, NULL, NULL,
+                                            0, 0);
                 } else {
                         nfs3_log_common_res (rpcsvc_request_xid (cs->req),
                                              "READDIRP", stat, -ret);
@@ -3877,7 +3862,8 @@  nfs3err:
                 if (maxcount == 0) {
                         nfs3_log_common_res (rpcsvc_request_xid (req), "READDIR"
                                              , stat, -ret);
-                        nfs3_readdir_reply (req, stat, 0, NULL, NULL, 0, 0);
+                        nfs3_readdir_reply (req, stat, NULL, 0, NULL, NULL, 0,
+                                            0);
                 } else {
                         nfs3_log_common_res (rpcsvc_request_xid (req),"READDIRP"
                                              , stat, -ret);