Read all directory entries before we start invoking the callbacks
authorRonnie Sahlberg <ronniesahlberg@gmail.com>
Tue, 3 Jul 2012 01:19:37 +0000 (11:19 +1000)
committerRonnie Sahlberg <ronniesahlberg@gmail.com>
Tue, 3 Jul 2012 01:19:37 +0000 (11:19 +1000)
Most nfs servers return READDIRPLUS entry cookies as the offset into the directory where the dirent starts.
This means that reading the directory is not impacted by changes to the directory and that BAD_COOKIE errors will never arise.
Think loops like
 opendir()
 while(readdir()){
     unlink()
 }
 closedir()

Some nfs servers can not easily produce semantics similar to the above in which case the cleanup funciton that does a recursive delete using a loop semantically similar to the above.
Change how we traverse directories to instead work something like
 opendir()
 while(readdir()){
    store dirent in list
 }
 closedir()
 walk whole list {
   unlink()
 }

libnfs.c
nfsio.c

index d83d33c1a90718c9e206ee88680b71a09c9ed040..1f60ef0b5af1a7de101d47d77448cda90a67b93d 100644 (file)
--- a/libnfs.c
+++ b/libnfs.c
@@ -1376,6 +1376,8 @@ nfsstat3 nfsio_readdirplus(struct nfsio *nfsio, const char *name, nfs3_dirent_cb
        int ret = NFS3_OK;
        data_t *fh;
        entryplus3 *e, *last_e = NULL;
+       entryplus3 *entries = NULL;
+       entryplus3 *new_entry;
        char *dir = NULL;
 
        dir = strdup(name);
@@ -1439,9 +1441,11 @@ again:
                );
                free(new_name);
 
-               if (cb) {
-                       cb(e, private_data);
-               }
+               new_entry = malloc(sizeof(entryplus3));
+               new_entry->name = strdup(e->name);
+               new_entry->name_attributes.post_op_attr_u.attributes.type = e->name_attributes.post_op_attr_u.attributes.type;
+               new_entry->nextentry = entries;
+               entries = new_entry;
        }       
 
        if (READDIRPLUS3res->READDIRPLUS3res_u.resok.reply.eof == 0) {
@@ -1456,6 +1460,18 @@ again:
                goto again;
        }
 
+       /* we have read all entries, now invoke the callback for all of them */
+       while (entries != NULL) {
+               e = entries;
+               entries = entries->nextentry;
+
+               if (cb) {
+                       cb(e, private_data);
+               }
+       
+               free(e->name);
+               free(e);
+       }
 
 finished:
        if (dir) {
diff --git a/nfsio.c b/nfsio.c
index c9ed44b84c5926b90aafb160060a6d41a1086912..75831106635d89c55f37bdf9fc7e5d20a765b4c8 100644 (file)
--- a/nfsio.c
+++ b/nfsio.c
@@ -135,7 +135,7 @@ static void nfs3_deltree(struct dbench_op *op)
 {
        struct cb_data *cbd;
        nfsstat3 res;
-       
+
        cbd = malloc(sizeof(struct cb_data));
 
        cbd->nfsio = op->child->private;