Properly decrement inode refcounts when finishing a request.
authorMichael Vrable <mvrable@cs.ucsd.edu>
Mon, 25 Jan 2010 01:35:14 +0000 (17:35 -0800)
committerMichael Vrable <mvrable@cs.ucsd.edu>
Mon, 25 Jan 2010 01:35:14 +0000 (17:35 -0800)
Track each refcount increase made, and when the request is finally replied
to, drop those references.  In a few cases we manually drop references, but
this should be less error-prone if there are multiple possible return
paths.

bluesky/bluesky.h
nfs3/nfs3.c
nfs3/nfs3_prot.h
nfs3/nfsd.c
nfs3/rpc.c

index 41618b5..201cc17 100644 (file)
@@ -211,6 +211,8 @@ uint64_t bluesky_fs_alloc_inode(BlueSkyFS *fs);
 BlueSkyInode *bluesky_new_inode(uint64_t inum, BlueSkyFS *fs, BlueSkyFileType type);
 
 BlueSkyInode *bluesky_get_inode(BlueSkyFS *fs, uint64_t inum);
+void bluesky_inode_ref(BlueSkyInode *inode);
+void bluesky_inode_unref(BlueSkyInode *inode);
 void bluesky_insert_inode(BlueSkyFS *fs, BlueSkyInode *inode);
 
 void bluesky_dirent_destroy(gpointer dirent);
index 3f858ac..8be68bd 100644 (file)
@@ -27,14 +27,27 @@ gboolean validate_filename(const char *filename)
     return TRUE;
 }
 
+/* Arrange for a reference to an inode to be dropped when the RPC request
+ * completes. */
+void schedule_inode_unref(RPCRequest *req, BlueSkyInode *inode)
+{
+    struct cleanup_list *c = g_new(struct cleanup_list, 1);
+    c->func = (void (*)(void *))bluesky_inode_unref;
+    c->arg = inode;
+    c->next = req->cleanup;
+    req->cleanup = c;
+}
+
 /* Look up a BlueSkyInode given an NFS filehandle.  Returns NULL if the
  * filehandle is invalid. */
-BlueSkyInode *lookup_fh(nfs_fh3 *fh)
+BlueSkyInode *lookup_fh(RPCRequest *req, nfs_fh3 *fh)
 {
     BlueSkyInode *inode = NULL;
     if (fh->data.data_len == 8) {
         uint64_t inum = GUINT64_FROM_BE(*(uint64_t *)(fh->data.data_val));
         inode = bluesky_get_inode(fs, inum);
+        if (inode != NULL)
+            schedule_inode_unref(req, inode);
     }
     return inode;
 }
@@ -146,7 +159,7 @@ void nfsproc3_getattr_3_svc(nfs_fh3 *argp, RPCRequest *req)
     getattr3res result;
     memset(&result, 0, sizeof(result));
 
-    BlueSkyInode *inode = lookup_fh(argp);
+    BlueSkyInode *inode = lookup_fh(req, argp);
     if (inode != NULL) {
         result.status = NFS3_OK;
         encode_fattr3(&result.getattr3res_u.attributes, inode);
@@ -164,7 +177,7 @@ void nfsproc3_setattr_3_svc(setattr3args *argp, RPCRequest *req)
 
     result.wccstat3_u.wcc.before.present = FALSE;
     result.wccstat3_u.wcc.after.present = FALSE;
-    BlueSkyInode *inode = lookup_fh(&argp->object);
+    BlueSkyInode *inode = lookup_fh(req, &argp->object);
     if (inode == NULL) {
         result.status = NFS3ERR_STALE;
         async_rpc_send_reply(req, &result);
@@ -197,7 +210,7 @@ void nfsproc3_lookup_3_svc(diropargs3 *argp, RPCRequest *req)
     lookup3res result;
     memset(&result, 0, sizeof(result));
 
-    BlueSkyInode *dir = lookup_fh(&argp->dir);
+    BlueSkyInode *dir = lookup_fh(req, &argp->dir);
     if (dir == NULL) {
         result.status = NFS3ERR_STALE;
         result.lookup3res_u.resfail.present = FALSE;
@@ -229,6 +242,7 @@ void nfsproc3_lookup_3_svc(diropargs3 *argp, RPCRequest *req)
         async_rpc_send_reply(req, &result);
         return;
     }
+    schedule_inode_unref(req, inode);
 
     result.status = NFS3_OK;
     result.lookup3res_u.resok.dir_attributes.present = TRUE;
@@ -249,7 +263,7 @@ void nfsproc3_access_3_svc(access3args *argp, RPCRequest *req)
     access3res result;
     memset(&result, 0, sizeof(result));
 
-    BlueSkyInode *inode = lookup_fh(&argp->object);
+    BlueSkyInode *inode = lookup_fh(req, &argp->object);
     if (inode == NULL) {
         result.status = NFS3ERR_STALE;
         result.access3res_u.resfail.present = FALSE;
@@ -270,7 +284,7 @@ void nfsproc3_readlink_3_svc(nfs_fh3 *argp, RPCRequest *req)
     readlink3res result;
     memset(&result, 0, sizeof(result));
 
-    BlueSkyInode *inode = lookup_fh(argp);
+    BlueSkyInode *inode = lookup_fh(req, argp);
     if (inode != NULL) {
         if (inode->type == BLUESKY_SYMLINK) {
             result.status = NFS3_OK;
@@ -295,7 +309,7 @@ void nfsproc3_read_3_svc(read3args *argp, RPCRequest *req)
     memset(&result, 0, sizeof(result));
     char buf[32768];
 
-    BlueSkyInode *inode = lookup_fh(&argp->file);
+    BlueSkyInode *inode = lookup_fh(req, &argp->file);
     if (inode == NULL) {
         result.status = NFS3ERR_STALE;
         result.read3res_u.resfail.present = FALSE;
@@ -334,7 +348,7 @@ void nfsproc3_write_3_svc(write3args *argp, RPCRequest *req)
     struct wcc_data wcc;
     memset(&wcc, 0, sizeof(wcc));
 
-    BlueSkyInode *inode = lookup_fh(&argp->file);
+    BlueSkyInode *inode = lookup_fh(req, &argp->file);
     if (inode == NULL) {
         result.status = NFS3ERR_STALE;
         result.write3res_u.resfail = wcc;
@@ -378,7 +392,7 @@ void nfsproc3_create_3_svc(create3args *argp, RPCRequest *req)
     struct wcc_data wcc;
     memset(&wcc, 0, sizeof(wcc));
 
-    BlueSkyInode *dir = lookup_fh(&argp->where.dir);
+    BlueSkyInode *dir = lookup_fh(req, &argp->where.dir);
     if (dir == NULL) {
         result.status = NFS3ERR_STALE;
         result.diropres3_u.resfail = wcc;
@@ -442,7 +456,7 @@ void nfsproc3_mkdir_3_svc(mkdir3args *argp, RPCRequest *req)
     struct wcc_data wcc;
     memset(&wcc, 0, sizeof(wcc));
 
-    BlueSkyInode *dir = lookup_fh(&argp->where.dir);
+    BlueSkyInode *dir = lookup_fh(req, &argp->where.dir);
     if (dir == NULL) {
         result.status = NFS3ERR_STALE;
         result.diropres3_u.resfail = wcc;
@@ -506,7 +520,7 @@ void nfsproc3_symlink_3_svc(symlink3args *argp, RPCRequest *req)
     struct wcc_data wcc;
     memset(&wcc, 0, sizeof(wcc));
 
-    BlueSkyInode *dir = lookup_fh(&argp->where.dir);
+    BlueSkyInode *dir = lookup_fh(req, &argp->where.dir);
     if (dir == NULL) {
         result.status = NFS3ERR_STALE;
         result.diropres3_u.resfail = wcc;
@@ -578,7 +592,7 @@ void nfsproc3_remove_3_svc(diropargs3 *argp, RPCRequest *req)
     wccstat3 result;
     memset(&result, 0, sizeof(result));
 
-    BlueSkyInode *dir = lookup_fh(&argp->dir);
+    BlueSkyInode *dir = lookup_fh(req, &argp->dir);
     if (dir == NULL) {
         result.status = NFS3ERR_STALE;
         async_rpc_send_reply(req, &result);
@@ -613,7 +627,7 @@ void nfsproc3_rmdir_3_svc(diropargs3 *argp, RPCRequest *req)
     wccstat3 result;
     memset(&result, 0, sizeof(result));
 
-    BlueSkyInode *dir = lookup_fh(&argp->dir);
+    BlueSkyInode *dir = lookup_fh(req, &argp->dir);
     if (dir == NULL) {
         result.status = NFS3ERR_STALE;
         async_rpc_send_reply(req, &result);
@@ -638,6 +652,7 @@ void nfsproc3_rmdir_3_svc(diropargs3 *argp, RPCRequest *req)
         async_rpc_send_reply(req, &result);
         return;
     }
+    schedule_inode_unref(req, inode);
 
     if (inode->type != BLUESKY_DIRECTORY) {
         result.status = NFS3ERR_NOTDIR;
@@ -671,7 +686,7 @@ void nfsproc3_rename_3_svc(rename3args *argp, RPCRequest *req)
     wcc_data *wcc1 = &result.rename3res_u.res.fromdir_wcc;
     wcc_data *wcc2 = &result.rename3res_u.res.todir_wcc;
 
-    BlueSkyInode *dir1 = lookup_fh(&argp->from.dir);
+    BlueSkyInode *dir1 = lookup_fh(req, &argp->from.dir);
     if (dir1 == NULL) {
         result.status = NFS3ERR_STALE;
         async_rpc_send_reply(req, &result);
@@ -679,7 +694,7 @@ void nfsproc3_rename_3_svc(rename3args *argp, RPCRequest *req)
     }
     encode_pre_wcc(wcc1, dir1);
 
-    BlueSkyInode *dir2 = lookup_fh(&argp->to.dir);
+    BlueSkyInode *dir2 = lookup_fh(req, &argp->to.dir);
     if (dir2 == NULL) {
         result.status = NFS3ERR_STALE;
         async_rpc_send_reply(req, &result);
@@ -710,7 +725,7 @@ void nfsproc3_link_3_svc(link3args *argp, RPCRequest *req)
     struct wcc_data wcc;
     memset(&wcc, 0, sizeof(wcc));
 
-    BlueSkyInode *inode = lookup_fh(&argp->file);
+    BlueSkyInode *inode = lookup_fh(req, &argp->file);
     if (inode == NULL) {
         result.status = NFS3ERR_STALE;
         result.link3res_u.res.linkdir_wcc = wcc;
@@ -718,7 +733,7 @@ void nfsproc3_link_3_svc(link3args *argp, RPCRequest *req)
         return;
     }
 
-    BlueSkyInode *dir = lookup_fh(&argp->link.dir);
+    BlueSkyInode *dir = lookup_fh(req, &argp->link.dir);
     if (dir == NULL) {
         result.status = NFS3ERR_STALE;
         result.link3res_u.res.linkdir_wcc = wcc;
@@ -773,7 +788,7 @@ void nfsproc3_readdir_3_svc(readdir3args *argp, RPCRequest *req)
     readdir3res result;
     memset(&result, 0, sizeof(result));
 
-    BlueSkyInode *dir = lookup_fh(&argp->dir);
+    BlueSkyInode *dir = lookup_fh(req, &argp->dir);
     if (dir == NULL) {
         result.status = NFS3ERR_STALE;
         result.readdir3res_u.resfail.present = FALSE;
@@ -827,7 +842,7 @@ void nfsproc3_readdirplus_3_svc(readdirplus3args *argp, RPCRequest *req)
     readdirplus3res result;
     memset(&result, 0, sizeof(result));
 
-    BlueSkyInode *dir = lookup_fh(&argp->dir);
+    BlueSkyInode *dir = lookup_fh(req, &argp->dir);
     if (dir == NULL) {
         result.status = NFS3ERR_STALE;
         result.readdirplus3res_u.resfail.present = FALSE;
@@ -874,6 +889,7 @@ void nfsproc3_readdirplus_3_svc(readdirplus3args *argp, RPCRequest *req)
             if (count > 0)
                 dirents[count - 1].nextentry = &dirents[count];
             count++;
+            bluesky_inode_unref(inode);
         }
         i = g_sequence_iter_next(i);
     }
@@ -892,7 +908,7 @@ void nfsproc3_fsstat_3_svc(nfs_fh3 *argp, RPCRequest *req)
     fsstat3res result;
     memset(&result, 0, sizeof(result));
 
-    BlueSkyInode *inode = lookup_fh(argp);
+    BlueSkyInode *inode = lookup_fh(req, argp);
     if (inode == NULL) {
         result.status = NFS3ERR_STALE;
         result.fsstat3res_u.resfail.present = FALSE;
@@ -936,6 +952,7 @@ void nfsproc3_fsinfo_3_svc(nfs_fh3 *argp, RPCRequest *req)
     result.fsinfo3res_u.resok.time_delta.nseconds = 1000;
     result.fsinfo3res_u.resok.properties
         = FSF3_LINK | FSF3_SYMLINK | FSF3_HOMOGENEOUS | FSF3_CANSETTIME;
+    bluesky_inode_unref(inode);
 
     async_rpc_send_reply(req, &result);
 }
@@ -955,6 +972,7 @@ void nfsproc3_pathconf_3_svc(nfs_fh3 *argp, RPCRequest *req)
     result.pathconf3res_u.resok.chown_restricted = TRUE;
     result.pathconf3res_u.resok.case_insensitive = FALSE;
     result.pathconf3res_u.resok.case_preserving = TRUE;
+    bluesky_inode_unref(inode);
 
     async_rpc_send_reply(req, &result);
 }
index 6a3e316..01ed7b5 100644 (file)
@@ -655,6 +655,13 @@ typedef struct {
     int frag_hdr_bytes;
 } RPCConnection;
 
+/* Linked list of cleanup functions to call when a request is completed. */
+struct cleanup_list {
+    void (*func)(void *arg);
+    void *arg;
+    struct cleanup_list *next;
+};
+
 /* Used to track a single outstanding RPC request.  Not all of the fields are
  * initially filled in, but more are filled in as the request is processed. */
 typedef struct {
@@ -684,6 +691,10 @@ typedef struct {
 
     /* Procedure to be used for encoding the eventual return value into XDR. */
     xdrproc_t xdr_result;
+
+    /* Functions to be called when the response is sent to clean up any
+     * resources. */
+    struct cleanup_list *cleanup;
 } RPCRequest;
 
 extern void async_rpc_send_reply(RPCRequest *req, void *result);
index 16011f4..55819e0 100644 (file)
@@ -34,7 +34,7 @@ int main(int argc, char *argv[])
 
     bluesky_options.synchronous_stores = 1;
 
-    store = bluesky_store_new("file");
+    store = bluesky_store_new("s3");
     fs = bluesky_init_fs("export", store);
 
     BlueSkyInode *root;
@@ -47,6 +47,8 @@ int main(int argc, char *argv[])
         bluesky_insert_inode(fs, root);
     }
 
+    bluesky_debug_dump(fs);
+
     svc_run();
     fprintf(stderr, "%s", "svc_run returned");
     exit(1);
index ae39154..7b73840 100644 (file)
@@ -212,6 +212,13 @@ async_rpc_send_failure(RPCRequest *req, enum accept_stat stat)
     if (req->raw_args != NULL)
         g_string_free(req->raw_args, TRUE);
 
+    while (req->cleanup != NULL) {
+        struct cleanup_list *c = req->cleanup;
+        req->cleanup = c->next;
+        c->func(c->arg);
+        g_free(c);
+    }
+
     g_free(req);
 }
 
@@ -264,6 +271,13 @@ async_rpc_send_reply(RPCRequest *req, void *result)
     if (req->raw_args != NULL)
         g_string_free(req->raw_args, TRUE);
 
+    while (req->cleanup != NULL) {
+        struct cleanup_list *c = req->cleanup;
+        req->cleanup = c->next;
+        c->func(c->arg);
+        g_free(c);
+    }
+
     g_free(req);
 }