While looking into some of the races that seem possible in the new auth-cache and netgroup/export features for Gluster/NFS, I noticed that we do not really have a common way to do reference counting. I could really use that, so I've put something together and would like to request some comments on it.
Patch: http://review.gluster.org/11022 I'll add an example below, but the functions in the header are commented too. My plan is to use it to track and release auth-cache entries when the exports/netgroups get refreshed (auth-cache invalidated). Because other threads can still have a reference to the auth-cache entry, refcounting (and appropriate locking of the main structure) is needed. A first shot at the implementation is available too: http://review.gluster.org/11023 More datails about the actual issue have been sent to this list before: http://thread.gmane.org/gmane.comp.file-systems.gluster.devel/11052/focus=11109 Comments are much appreciated. Thanks, Niels It can be used to automatically recylce a twig when all the grapes attached to the twig have been plucked. For the record, we keep a reference to all grapes in our 'growing_grapes' list too. Lets assume our record keeping is *so* good, that we only need to go by the list to know which grapes are ripe enough to pluck. You might notice that I'm not a grape farmer ;-) #include "refcount.h" /* we track all the grapes of the plant, but only pluck the ripe ones */ list_head growing_grapes; /* ripe grapes are removed from growing_grapes, and put in the basket */ list_head grape_basket; /* a twig with grapes */ struct twig { struct gf_ref *ref; /* for refcounting */ struct plant *plant; /* plant attached to this twig */ } /* a grape that is/was attached to a twig */ struct grape { struct twig *twig; /* twig when still growing */ unsigned int tasty; /* mark from 1-10 on tastiness */ }; /* called by gf_ref_put() when all grapes have been plucked */ void recycle_twig (void *to_free) { struct twig *twig = (struct twig *) to_free; cut_from_plant (twig->plant); GF_FREE (twig); } /* you'll execute this whenever you pass the grapes plant */ void check_grapes () { struct grape *grape = NULL; foreach_grape (grape, growing_grapes) { if (is_ripe (grape)) { list_del (grape, growing_grapes); /* the grape has been removed from the twig */ twig = grape->twig; grape->twig = NULL; gf_ref_put (&twig->ref); /* the last gf_ref_put() will call recyle_twig() */ /* put the grape in the basket */ list_add (grape_basket, grape); } } } void grow_new_grape (struct twig *twig) { struct grape *grape = GF_MALLOC (sizeof (struct grape), gf_mt_grapes); if (gf_ref_get (&twig->ref) == 0) { /* oops, something went wrong! no locking implemented yet? */ GF_FREE (grape); return; } grape->twig = twig; /* the grape has just started to grow */ list_add (growing_grapes, grape); } /* there are many twigs with grapes on this plant */ struct twig * grow_twig_with_grapes (struct plant *plant, int grape_count) { int i = 0; struct twig *twig = GF_MALLOC (sizeof (struct twig), gf_mt_grapes); gf_ref_init (&twig->ref, recycle_twig, twig); /* recount has been set to 1 */ grape->plant = plant; for (i = 0; i < grape_count; i++) { /* each grape increments the refcount on the twig */ grow_grape (twig); } /* all grapes have been added and will start to grow */ gf_ref_put (&twig->ref); } /* at one point you want to share your grapes with your colleagues */ void eat_grapes() { struct grape *grape = NULL; if (list_empty (grape_basket)) /* sorry, no more grapes :-( */ return; grape = list_remove_last (grape_backet); hmmm (grape); } _______________________________________________ Gluster-devel mailing list Gluster-devel@gluster.org http://www.gluster.org/mailman/listinfo/gluster-devel