When h_TossStuff_r h_NBLock_r's a host, it is not only possible for
someone else to grab a hold on the host, but in theory it's also
possible for someone to hold a host, release it, and for the host to be
deleted again (assuming some callers hold HOSTDELETED hosts, which they
should not be doing).
To make this safety check a bit more robust, hold the host in
h_TossStuff_r before h_NBLock_r'ing, to ensure that it does not go away
while we're waiting for H_LOCK.
Change-Id: I018a611143d6dccba79cc627803cce74aa830c77
Reviewed-on: http://gerrit.openafs.org/1330
Tested-by: Andrew Deason <adeason@sinenomine.net>
Reviewed-by: Derrick Brashear <shadow@dementia.org>
h_TossStuff_r(register struct host *host)
{
register struct client **cp, *client;
+ int code;
+
+ /* make sure host doesn't go away over h_NBLock_r */
+ h_Hold_r(host);
+
+ code = h_NBLock_r(host);
+
+ /* don't use h_Release_r, since that may call h_TossStuff_r again */
+ h_Decrement_r(host);
/* if somebody still has this host locked */
- if (h_NBLock_r(host) != 0) {
+ if (code != 0) {
char hoststr[16];
ViceLog(0,
("Warning: h_TossStuff_r failed; Host %" AFS_PTR_FMT " (%s:%d) was locked.\n",
++((x)->refCount); \
} while(0)
-#define h_Release_r(x) \
+#define h_Decrement_r(x) \
do { \
--((x)->refCount); \
+} while (0)
+
+#define h_Release_r(x) \
+do { \
+ h_Decrement_r(x); \
if (((x)->refCount < 1) && \
(((x)->hostFlags & HOSTDELETED) || \
((x)->hostFlags & CLIENTDELETED))) h_TossStuff_r((x)); \