| File: | src/usr.sbin/rpc.lockd/lockd_lock.c |
| Warning: | line 726, column 2 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: lockd_lock.c,v 1.12 2023/03/08 04:43:15 guenther Exp $ */ | |||
| 2 | ||||
| 3 | /* | |||
| 4 | * Copyright (c) 2000 Manuel Bouyer. | |||
| 5 | * | |||
| 6 | * Redistribution and use in source and binary forms, with or without | |||
| 7 | * modification, are permitted provided that the following conditions | |||
| 8 | * are met: | |||
| 9 | * 1. Redistributions of source code must retain the above copyright | |||
| 10 | * notice, this list of conditions and the following disclaimer. | |||
| 11 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 12 | * notice, this list of conditions and the following disclaimer in the | |||
| 13 | * documentation and/or other materials provided with the distribution. | |||
| 14 | * | |||
| 15 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
| 16 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
| 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
| 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
| 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
| 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
| 21 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
| 22 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
| 23 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
| 24 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| 25 | * SUCH DAMAGE. | |||
| 26 | * | |||
| 27 | */ | |||
| 28 | ||||
| 29 | #include <sys/socket.h> | |||
| 30 | #include <sys/stat.h> | |||
| 31 | #include <sys/mount.h> | |||
| 32 | #include <sys/wait.h> | |||
| 33 | #include <stdio.h> | |||
| 34 | #include <stdlib.h> | |||
| 35 | #include <unistd.h> | |||
| 36 | #include <fcntl.h> | |||
| 37 | #include <inttypes.h> | |||
| 38 | #include <syslog.h> | |||
| 39 | #include <errno(*__errno()).h> | |||
| 40 | #include <string.h> | |||
| 41 | #include <signal.h> | |||
| 42 | #include <rpc/rpc.h> | |||
| 43 | #include <rpcsvc/sm_inter.h> | |||
| 44 | #include <rpcsvc/nlm_prot.h> | |||
| 45 | #include "lockd_lock.h" | |||
| 46 | #include "lockd.h" | |||
| 47 | ||||
| 48 | /* A set of utilities for managing file locking */ | |||
| 49 | LIST_HEAD(lcklst_head, file_lock)struct lcklst_head { struct file_lock *lh_first; }; | |||
| 50 | struct lcklst_head lcklst_head = LIST_HEAD_INITIALIZER(lcklst_head){ ((void *)0) }; | |||
| 51 | ||||
| 52 | #define FHANDLE_SIZE_MAX1024 1024 /* arbitrary big enough value */ | |||
| 53 | typedef struct { | |||
| 54 | size_t fhsize; | |||
| 55 | char *fhdata; | |||
| 56 | } nfs_fhandle_t; | |||
| 57 | ||||
| 58 | static int | |||
| 59 | fhcmp(const nfs_fhandle_t *fh1, const nfs_fhandle_t *fh2) | |||
| 60 | { | |||
| 61 | return memcmp(fh1->fhdata, fh2->fhdata, sizeof(fhandle_t)); | |||
| 62 | } | |||
| 63 | ||||
| 64 | static int | |||
| 65 | fhconv(nfs_fhandle_t *fh, const netobj *rfh) | |||
| 66 | { | |||
| 67 | size_t sz; | |||
| 68 | ||||
| 69 | sz = rfh->n_len; | |||
| 70 | if (sz > FHANDLE_SIZE_MAX1024) { | |||
| 71 | syslog(LOG_DEBUG7, | |||
| 72 | "received fhandle size %zd, max supported size %d", | |||
| 73 | sz, FHANDLE_SIZE_MAX1024); | |||
| 74 | errno(*__errno()) = EINVAL22; | |||
| 75 | return -1; | |||
| 76 | } | |||
| 77 | fh->fhdata = malloc(sz); | |||
| 78 | if (fh->fhdata == NULL((void *)0)) { | |||
| 79 | return -1; | |||
| 80 | } | |||
| 81 | fh->fhsize = sz; | |||
| 82 | memcpy(fh->fhdata, rfh->n_bytes, sz); | |||
| 83 | return 0; | |||
| 84 | } | |||
| 85 | ||||
| 86 | static void | |||
| 87 | fhfree(nfs_fhandle_t *fh) | |||
| 88 | { | |||
| 89 | ||||
| 90 | free(fh->fhdata); | |||
| 91 | } | |||
| 92 | ||||
| 93 | /* struct describing a lock */ | |||
| 94 | struct file_lock { | |||
| 95 | LIST_ENTRY(file_lock)struct { struct file_lock *le_next; struct file_lock **le_prev ; } lcklst; | |||
| 96 | nfs_fhandle_t filehandle; /* NFS filehandle */ | |||
| 97 | struct sockaddr_in *addr; | |||
| 98 | struct nlm4_holder client; /* lock holder */ | |||
| 99 | netobj client_cookie; /* cookie sent by the client */ | |||
| 100 | char client_name[128]; | |||
| 101 | int nsm_status; /* status from the remote lock manager */ | |||
| 102 | int status; /* lock status, see below */ | |||
| 103 | int flags; /* lock flags, see lockd_lock.h */ | |||
| 104 | pid_t locker; /* pid of the child process trying to get the lock */ | |||
| 105 | int fd; /* file descriptor for this lock */ | |||
| 106 | }; | |||
| 107 | ||||
| 108 | /* lock status */ | |||
| 109 | #define LKST_LOCKED1 1 /* lock is locked */ | |||
| 110 | #define LKST_WAITING2 2 /* file is already locked by another host */ | |||
| 111 | #define LKST_PROCESSING3 3 /* child is trying to acquire the lock */ | |||
| 112 | #define LKST_DYING4 4 /* must die when we get news from the child */ | |||
| 113 | ||||
| 114 | static struct file_lock *lalloc(void); | |||
| 115 | void lfree(struct file_lock *); | |||
| 116 | enum nlm_stats do_lock(struct file_lock *, int); | |||
| 117 | enum nlm_stats do_unlock(struct file_lock *); | |||
| 118 | void send_granted(struct file_lock *, int); | |||
| 119 | void siglock(void); | |||
| 120 | void sigunlock(void); | |||
| 121 | ||||
| 122 | /* list of hosts we monitor */ | |||
| 123 | LIST_HEAD(hostlst_head, host)struct hostlst_head { struct host *lh_first; }; | |||
| 124 | struct hostlst_head hostlst_head = LIST_HEAD_INITIALIZER(hostlst_head){ ((void *)0) }; | |||
| 125 | ||||
| 126 | /* struct describing a lock */ | |||
| 127 | struct host { | |||
| 128 | LIST_ENTRY(host)struct { struct host *le_next; struct host **le_prev; } hostlst; | |||
| 129 | char name[SM_MAXSTRLEN1024+1]; | |||
| 130 | int refcnt; | |||
| 131 | }; | |||
| 132 | ||||
| 133 | void do_mon(const char *); | |||
| 134 | ||||
| 135 | #define LL_FH0x01 0x01 | |||
| 136 | #define LL_NAME0x02 0x02 | |||
| 137 | #define LL_SVID0x04 0x04 | |||
| 138 | ||||
| 139 | static struct file_lock *lock_lookup(struct file_lock *, int); | |||
| 140 | ||||
| 141 | /* | |||
| 142 | * lock_lookup: lookup a matching lock. | |||
| 143 | * called with siglock held. | |||
| 144 | */ | |||
| 145 | static struct file_lock * | |||
| 146 | lock_lookup(struct file_lock *newfl, int flags) | |||
| 147 | { | |||
| 148 | struct file_lock *fl; | |||
| 149 | ||||
| 150 | LIST_FOREACH(fl, &lcklst_head, lcklst)for((fl) = ((&lcklst_head)->lh_first); (fl)!= ((void * )0); (fl) = ((fl)->lcklst.le_next)) { | |||
| 151 | if ((flags & LL_SVID0x04) != 0 && | |||
| 152 | newfl->client.svid != fl->client.svid) | |||
| 153 | continue; | |||
| 154 | if ((flags & LL_NAME0x02) != 0 && | |||
| 155 | strcmp(newfl->client_name, fl->client_name) != 0) | |||
| 156 | continue; | |||
| 157 | if ((flags & LL_FH0x01) != 0 && | |||
| 158 | fhcmp(&newfl->filehandle, &fl->filehandle) != 0) | |||
| 159 | continue; | |||
| 160 | /* found */ | |||
| 161 | break; | |||
| 162 | } | |||
| 163 | ||||
| 164 | return fl; | |||
| 165 | } | |||
| 166 | ||||
| 167 | /* | |||
| 168 | * testlock(): inform the caller if the requested lock would be granted or not | |||
| 169 | * returns NULL if lock would granted, or pointer to the current nlm4_holder | |||
| 170 | * otherwise. | |||
| 171 | */ | |||
| 172 | ||||
| 173 | struct nlm4_holder * | |||
| 174 | testlock(struct nlm4_lock *lock, int flags) | |||
| 175 | { | |||
| 176 | struct file_lock *fl; | |||
| 177 | nfs_fhandle_t filehandle; | |||
| 178 | ||||
| 179 | /* convert lock to a local filehandle */ | |||
| 180 | if (fhconv(&filehandle, &lock->fh)) { | |||
| 181 | syslog(LOG_NOTICE5, "fhconv failed (%m)"); | |||
| 182 | return NULL((void *)0); /* XXX */ | |||
| 183 | } | |||
| 184 | ||||
| 185 | siglock(); | |||
| 186 | /* search through the list for lock holder */ | |||
| 187 | LIST_FOREACH(fl, &lcklst_head, lcklst)for((fl) = ((&lcklst_head)->lh_first); (fl)!= ((void * )0); (fl) = ((fl)->lcklst.le_next)) { | |||
| 188 | if (fl->status != LKST_LOCKED1) | |||
| 189 | continue; | |||
| 190 | if (fhcmp(&fl->filehandle, &filehandle) != 0) | |||
| 191 | continue; | |||
| 192 | /* got it ! */ | |||
| 193 | syslog(LOG_DEBUG7, "test for %s: found lock held by %s", | |||
| 194 | lock->caller_name, fl->client_name); | |||
| 195 | sigunlock(); | |||
| 196 | fhfree(&filehandle); | |||
| 197 | return (&fl->client); | |||
| 198 | } | |||
| 199 | /* not found */ | |||
| 200 | sigunlock(); | |||
| 201 | fhfree(&filehandle); | |||
| 202 | syslog(LOG_DEBUG7, "test for %s: no lock found", lock->caller_name); | |||
| 203 | return NULL((void *)0); | |||
| 204 | } | |||
| 205 | ||||
| 206 | /* | |||
| 207 | * getlock: try to acquire the lock. | |||
| 208 | * If file is already locked and we can sleep, put the lock in the list with | |||
| 209 | * status LKST_WAITING; it'll be processed later. | |||
| 210 | * Otherwise try to lock. If we're allowed to block, fork a child which | |||
| 211 | * will do the blocking lock. | |||
| 212 | */ | |||
| 213 | enum nlm_stats | |||
| 214 | getlock(nlm4_lockargs * lckarg, struct svc_req *rqstp, int flags) | |||
| 215 | { | |||
| 216 | struct file_lock *fl, *newfl; | |||
| 217 | enum nlm_stats retval; | |||
| 218 | struct sockaddr_in *addr; | |||
| 219 | ||||
| 220 | if (grace_expired == 0 && lckarg->reclaim == 0) | |||
| 221 | return (flags & LOCK_V40x02) ? | |||
| 222 | nlm4_denied_grace_period : nlm_denied_grace_period; | |||
| 223 | ||||
| 224 | /* allocate new file_lock for this request */ | |||
| 225 | newfl = lalloc(); | |||
| 226 | if (newfl == NULL((void *)0)) { | |||
| 227 | syslog(LOG_NOTICE5, "malloc failed (%m)"); | |||
| 228 | /* failed */ | |||
| 229 | return (flags & LOCK_V40x02) ? | |||
| 230 | nlm4_denied_nolock : nlm_denied_nolocks; | |||
| 231 | } | |||
| 232 | if (fhconv(&newfl->filehandle, &lckarg->alock.fh)) { | |||
| 233 | syslog(LOG_NOTICE5, "fhconv failed (%m)"); | |||
| 234 | lfree(newfl); | |||
| 235 | /* failed */ | |||
| 236 | return (flags & LOCK_V40x02) ? | |||
| 237 | nlm4_denied_nolock : nlm_denied_nolocks; | |||
| 238 | } | |||
| 239 | addr = svc_getcaller(rqstp->rq_xprt)(&(rqstp->rq_xprt)->xp_raddr); | |||
| 240 | newfl->addr = malloc(addr->sin_len); | |||
| 241 | if (newfl->addr == NULL((void *)0)) { | |||
| 242 | syslog(LOG_NOTICE5, "malloc failed (%m)"); | |||
| 243 | lfree(newfl); | |||
| 244 | /* failed */ | |||
| 245 | return (flags & LOCK_V40x02) ? | |||
| 246 | nlm4_denied_nolock : nlm_denied_nolocks; | |||
| 247 | } | |||
| 248 | memcpy(newfl->addr, addr, addr->sin_len); | |||
| 249 | newfl->client.exclusive = lckarg->exclusive; | |||
| 250 | newfl->client.svid = lckarg->alock.svid; | |||
| 251 | newfl->client.oh.n_bytes = malloc(lckarg->alock.oh.n_len); | |||
| 252 | if (newfl->client.oh.n_bytes == NULL((void *)0)) { | |||
| 253 | syslog(LOG_NOTICE5, "malloc failed (%m)"); | |||
| 254 | lfree(newfl); | |||
| 255 | return (flags & LOCK_V40x02) ? | |||
| 256 | nlm4_denied_nolock : nlm_denied_nolocks; | |||
| 257 | } | |||
| 258 | newfl->client.oh.n_len = lckarg->alock.oh.n_len; | |||
| 259 | memcpy(newfl->client.oh.n_bytes, lckarg->alock.oh.n_bytes, | |||
| 260 | lckarg->alock.oh.n_len); | |||
| 261 | newfl->client.l_offset = lckarg->alock.l_offset; | |||
| 262 | newfl->client.l_len = lckarg->alock.l_len; | |||
| 263 | newfl->client_cookie.n_len = lckarg->cookie.n_len; | |||
| 264 | newfl->client_cookie.n_bytes = malloc(lckarg->cookie.n_len); | |||
| 265 | if (newfl->client_cookie.n_bytes == NULL((void *)0)) { | |||
| 266 | syslog(LOG_NOTICE5, "malloc failed (%m)"); | |||
| 267 | lfree(newfl); | |||
| 268 | return (flags & LOCK_V40x02) ? | |||
| 269 | nlm4_denied_nolock : nlm_denied_nolocks; | |||
| 270 | } | |||
| 271 | memcpy(newfl->client_cookie.n_bytes, lckarg->cookie.n_bytes, | |||
| 272 | lckarg->cookie.n_len); | |||
| 273 | strlcpy(newfl->client_name, lckarg->alock.caller_name, | |||
| 274 | sizeof(newfl->client_name)); | |||
| 275 | newfl->nsm_status = lckarg->state; | |||
| 276 | newfl->status = 0; | |||
| 277 | newfl->flags = flags; | |||
| 278 | siglock(); | |||
| 279 | /* look for a lock rq from this host for this fh */ | |||
| 280 | fl = lock_lookup(newfl, LL_FH0x01|LL_NAME0x02|LL_SVID0x04); | |||
| 281 | if (fl) { | |||
| 282 | /* already locked by this host ??? */ | |||
| 283 | sigunlock(); | |||
| 284 | syslog(LOG_NOTICE5, "duplicate lock from %s.%" | |||
| 285 | PRIu32"u", | |||
| 286 | newfl->client_name, newfl->client.svid); | |||
| 287 | lfree(newfl); | |||
| 288 | switch(fl->status) { | |||
| 289 | case LKST_LOCKED1: | |||
| 290 | return (flags & LOCK_V40x02) ? | |||
| 291 | nlm4_granted : nlm_granted; | |||
| 292 | case LKST_WAITING2: | |||
| 293 | case LKST_PROCESSING3: | |||
| 294 | return (flags & LOCK_V40x02) ? | |||
| 295 | nlm4_blocked : nlm_blocked; | |||
| 296 | case LKST_DYING4: | |||
| 297 | return (flags & LOCK_V40x02) ? | |||
| 298 | nlm4_denied : nlm_denied; | |||
| 299 | default: | |||
| 300 | syslog(LOG_NOTICE5, "bad status %d", | |||
| 301 | fl->status); | |||
| 302 | return (flags & LOCK_V40x02) ? | |||
| 303 | nlm4_failed : nlm_denied; | |||
| 304 | } | |||
| 305 | /* NOTREACHED */ | |||
| 306 | } | |||
| 307 | fl = lock_lookup(newfl, LL_FH0x01); | |||
| 308 | if (fl) { | |||
| 309 | /* | |||
| 310 | * We already have a lock for this file. | |||
| 311 | * Put this one in waiting state if allowed to block | |||
| 312 | */ | |||
| 313 | if (lckarg->block) { | |||
| 314 | syslog(LOG_DEBUG7, "lock from %s.%" PRIu32"u" ": " | |||
| 315 | "already locked, waiting", | |||
| 316 | lckarg->alock.caller_name, | |||
| 317 | lckarg->alock.svid); | |||
| 318 | newfl->status = LKST_WAITING2; | |||
| 319 | LIST_INSERT_HEAD(&lcklst_head, newfl, lcklst)do { if (((newfl)->lcklst.le_next = (&lcklst_head)-> lh_first) != ((void *)0)) (&lcklst_head)->lh_first-> lcklst.le_prev = &(newfl)->lcklst.le_next; (&lcklst_head )->lh_first = (newfl); (newfl)->lcklst.le_prev = &( &lcklst_head)->lh_first; } while (0); | |||
| 320 | do_mon(lckarg->alock.caller_name); | |||
| 321 | sigunlock(); | |||
| 322 | return (flags & LOCK_V40x02) ? | |||
| 323 | nlm4_blocked : nlm_blocked; | |||
| 324 | } else { | |||
| 325 | sigunlock(); | |||
| 326 | syslog(LOG_DEBUG7, "lock from %s.%" PRIu32"u" ": " | |||
| 327 | "already locked, failed", | |||
| 328 | lckarg->alock.caller_name, | |||
| 329 | lckarg->alock.svid); | |||
| 330 | lfree(newfl); | |||
| 331 | return (flags & LOCK_V40x02) ? | |||
| 332 | nlm4_denied : nlm_denied; | |||
| 333 | } | |||
| 334 | /* NOTREACHED */ | |||
| 335 | } | |||
| 336 | ||||
| 337 | /* no entry for this file yet; add to list */ | |||
| 338 | LIST_INSERT_HEAD(&lcklst_head, newfl, lcklst)do { if (((newfl)->lcklst.le_next = (&lcklst_head)-> lh_first) != ((void *)0)) (&lcklst_head)->lh_first-> lcklst.le_prev = &(newfl)->lcklst.le_next; (&lcklst_head )->lh_first = (newfl); (newfl)->lcklst.le_prev = &( &lcklst_head)->lh_first; } while (0); | |||
| 339 | /* do the lock */ | |||
| 340 | retval = do_lock(newfl, lckarg->block); | |||
| 341 | switch (retval) { | |||
| 342 | case nlm4_granted: | |||
| 343 | /* case nlm_granted: is the same as nlm4_granted */ | |||
| 344 | case nlm4_blocked: | |||
| 345 | /* case nlm_blocked: is the same as nlm4_blocked */ | |||
| 346 | do_mon(lckarg->alock.caller_name); | |||
| 347 | break; | |||
| 348 | default: | |||
| 349 | lfree(newfl); | |||
| 350 | break; | |||
| 351 | } | |||
| 352 | sigunlock(); | |||
| 353 | return retval; | |||
| 354 | } | |||
| 355 | ||||
| 356 | /* unlock a filehandle */ | |||
| 357 | enum nlm_stats | |||
| 358 | unlock(nlm4_lock *lck, int flags) | |||
| 359 | { | |||
| 360 | struct file_lock *fl; | |||
| 361 | nfs_fhandle_t filehandle; | |||
| 362 | int err = (flags & LOCK_V40x02) ? nlm4_granted : nlm_granted; | |||
| 363 | ||||
| 364 | if (fhconv(&filehandle, &lck->fh)) { | |||
| 365 | syslog(LOG_NOTICE5, "fhconv failed (%m)"); | |||
| 366 | return (flags & LOCK_V40x02) ? nlm4_denied : nlm_denied; | |||
| 367 | } | |||
| 368 | siglock(); | |||
| 369 | LIST_FOREACH(fl, &lcklst_head, lcklst)for((fl) = ((&lcklst_head)->lh_first); (fl)!= ((void * )0); (fl) = ((fl)->lcklst.le_next)) { | |||
| 370 | if (strcmp(fl->client_name, lck->caller_name) || | |||
| 371 | fhcmp(&filehandle, &fl->filehandle) != 0 || | |||
| 372 | fl->client.oh.n_len != lck->oh.n_len || | |||
| 373 | memcmp(fl->client.oh.n_bytes, lck->oh.n_bytes, | |||
| 374 | fl->client.oh.n_len) != 0 || | |||
| 375 | fl->client.svid != lck->svid) | |||
| 376 | continue; | |||
| 377 | /* Got it, unlock and remove from the queue */ | |||
| 378 | syslog(LOG_DEBUG7, "unlock from %s.%" PRIu32"u" ": found struct, " | |||
| 379 | "status %d", lck->caller_name, lck->svid, fl->status); | |||
| 380 | switch (fl->status) { | |||
| 381 | case LKST_LOCKED1: | |||
| 382 | err = do_unlock(fl); | |||
| 383 | break; | |||
| 384 | case LKST_WAITING2: | |||
| 385 | /* remove from the list */ | |||
| 386 | LIST_REMOVE(fl, lcklst)do { if ((fl)->lcklst.le_next != ((void *)0)) (fl)->lcklst .le_next->lcklst.le_prev = (fl)->lcklst.le_prev; *(fl)-> lcklst.le_prev = (fl)->lcklst.le_next; ; ; } while (0); | |||
| 387 | lfree(fl); | |||
| 388 | break; | |||
| 389 | case LKST_PROCESSING3: | |||
| 390 | /* | |||
| 391 | * being handled by a child; will clean up | |||
| 392 | * when the child exits | |||
| 393 | */ | |||
| 394 | fl->status = LKST_DYING4; | |||
| 395 | break; | |||
| 396 | case LKST_DYING4: | |||
| 397 | /* nothing to do */ | |||
| 398 | break; | |||
| 399 | default: | |||
| 400 | syslog(LOG_NOTICE5, "unknown status %d for %s", | |||
| 401 | fl->status, fl->client_name); | |||
| 402 | } | |||
| 403 | sigunlock(); | |||
| 404 | fhfree(&filehandle); | |||
| 405 | return err; | |||
| 406 | } | |||
| 407 | sigunlock(); | |||
| 408 | /* didn't find a matching entry; log anyway */ | |||
| 409 | syslog(LOG_NOTICE5, "no matching entry for %s", | |||
| 410 | lck->caller_name); | |||
| 411 | fhfree(&filehandle); | |||
| 412 | return (flags & LOCK_V40x02) ? nlm4_granted : nlm_granted; | |||
| 413 | } | |||
| 414 | ||||
| 415 | static struct file_lock * | |||
| 416 | lalloc(void) | |||
| 417 | { | |||
| 418 | return calloc(1, sizeof(struct file_lock)); | |||
| 419 | } | |||
| 420 | ||||
| 421 | void | |||
| 422 | lfree(struct file_lock *fl) | |||
| 423 | { | |||
| 424 | free(fl->addr); | |||
| 425 | free(fl->client.oh.n_bytes); | |||
| 426 | free(fl->client_cookie.n_bytes); | |||
| 427 | fhfree(&fl->filehandle); | |||
| 428 | free(fl); | |||
| 429 | } | |||
| 430 | ||||
| 431 | void | |||
| 432 | sigchild_handler(int sig) | |||
| 433 | { | |||
| 434 | int sstatus; | |||
| 435 | pid_t pid; | |||
| 436 | struct file_lock *fl; | |||
| 437 | ||||
| 438 | for (;;) { | |||
| 439 | pid = wait4(-1, &sstatus, WNOHANG0x01, NULL((void *)0)); | |||
| 440 | if (pid == -1) { | |||
| 441 | if (errno(*__errno()) != ECHILD10) | |||
| 442 | syslog(LOG_NOTICE5, "wait failed (%m)"); | |||
| 443 | else | |||
| 444 | syslog(LOG_DEBUG7, "wait failed (%m)"); | |||
| 445 | return; | |||
| 446 | } | |||
| 447 | if (pid == 0) { | |||
| 448 | /* no more child to handle yet */ | |||
| 449 | return; | |||
| 450 | } | |||
| 451 | /* | |||
| 452 | * if we're here we have a child that exited | |||
| 453 | * Find the associated file_lock. | |||
| 454 | */ | |||
| 455 | LIST_FOREACH(fl, &lcklst_head, lcklst)for((fl) = ((&lcklst_head)->lh_first); (fl)!= ((void * )0); (fl) = ((fl)->lcklst.le_next)) { | |||
| 456 | if (pid == fl->locker) | |||
| 457 | break; | |||
| 458 | } | |||
| 459 | if (fl == NULL((void *)0)) { | |||
| 460 | syslog(LOG_NOTICE5, "unknown child %d", pid); | |||
| 461 | } else { | |||
| 462 | /* protect from pid reusing. */ | |||
| 463 | fl->locker = 0; | |||
| 464 | if (!WIFEXITED(sstatus)(((sstatus) & 0177) == 0) || WEXITSTATUS(sstatus)(int)(((unsigned)(sstatus) >> 8) & 0xff) != 0) { | |||
| 465 | syslog(LOG_NOTICE5, "child %d failed", pid); | |||
| 466 | /* | |||
| 467 | * can't do much here; we can't reply | |||
| 468 | * anything but OK for blocked locks | |||
| 469 | * Eventually the client will time out | |||
| 470 | * and retry. | |||
| 471 | */ | |||
| 472 | do_unlock(fl); | |||
| 473 | return; | |||
| 474 | } | |||
| 475 | ||||
| 476 | /* check lock status */ | |||
| 477 | syslog(LOG_DEBUG7, "processing child %d, status %d", | |||
| 478 | pid, fl->status); | |||
| 479 | switch(fl->status) { | |||
| 480 | case LKST_PROCESSING3: | |||
| 481 | fl->status = LKST_LOCKED1; | |||
| 482 | send_granted(fl, (fl->flags & LOCK_V40x02) ? | |||
| 483 | nlm4_granted : nlm_granted); | |||
| 484 | break; | |||
| 485 | case LKST_DYING4: | |||
| 486 | do_unlock(fl); | |||
| 487 | break; | |||
| 488 | default: | |||
| 489 | syslog(LOG_NOTICE5, "bad lock status (%d) for" | |||
| 490 | " child %d", fl->status, pid); | |||
| 491 | } | |||
| 492 | } | |||
| 493 | } | |||
| 494 | } | |||
| 495 | ||||
| 496 | /* | |||
| 497 | * | |||
| 498 | * try to acquire the lock described by fl. Eventually fork a child to do a | |||
| 499 | * blocking lock if allowed and required. | |||
| 500 | */ | |||
| 501 | ||||
| 502 | enum nlm_stats | |||
| 503 | do_lock(struct file_lock *fl, int block) | |||
| 504 | { | |||
| 505 | int lflags, error; | |||
| 506 | struct stat st; | |||
| 507 | ||||
| 508 | fl->fd = fhopen((fhandle_t *)fl->filehandle.fhdata, O_RDWR0x0002); | |||
| 509 | if (fl->fd == -1) { | |||
| 510 | switch (errno(*__errno())) { | |||
| 511 | case ESTALE70: | |||
| 512 | error = nlm4_stale_fh; | |||
| 513 | break; | |||
| 514 | case EROFS30: | |||
| 515 | error = nlm4_rofs; | |||
| 516 | break; | |||
| 517 | default: | |||
| 518 | error = nlm4_failed; | |||
| 519 | } | |||
| 520 | if ((fl->flags & LOCK_V40x02) == 0) | |||
| 521 | error = nlm_denied; | |||
| 522 | syslog(LOG_NOTICE5, "fhopen failed (from %s) (%m)", | |||
| 523 | fl->client_name); | |||
| 524 | LIST_REMOVE(fl, lcklst)do { if ((fl)->lcklst.le_next != ((void *)0)) (fl)->lcklst .le_next->lcklst.le_prev = (fl)->lcklst.le_prev; *(fl)-> lcklst.le_prev = (fl)->lcklst.le_next; ; ; } while (0); | |||
| 525 | return error; | |||
| 526 | } | |||
| 527 | if (fstat(fl->fd, &st) == -1) { | |||
| 528 | syslog(LOG_NOTICE5, "fstat failed (from %s) (%m)", | |||
| 529 | fl->client_name); | |||
| 530 | } | |||
| 531 | syslog(LOG_DEBUG7, "lock from %s.%" PRIu32"u" " for file%s%s: " | |||
| 532 | "dev %u ino %llu (uid %d), flags %d", | |||
| 533 | fl->client_name, fl->client.svid, | |||
| 534 | fl->client.exclusive ? " (exclusive)":"", block ? " (block)":"", | |||
| 535 | st.st_dev, (unsigned long long)st.st_ino, st.st_uid, fl->flags); | |||
| 536 | lflags = LOCK_NB0x04; | |||
| 537 | if (fl->client.exclusive == 0) | |||
| 538 | lflags |= LOCK_SH0x01; | |||
| 539 | else | |||
| 540 | lflags |= LOCK_EX0x02; | |||
| 541 | error = flock(fl->fd, lflags); | |||
| 542 | if (error != 0 && errno(*__errno()) == EAGAIN35 && block) { | |||
| 543 | switch (fl->locker = fork()) { | |||
| 544 | case -1: /* fork failed */ | |||
| 545 | syslog(LOG_NOTICE5, "fork failed (%m)"); | |||
| 546 | LIST_REMOVE(fl, lcklst)do { if ((fl)->lcklst.le_next != ((void *)0)) (fl)->lcklst .le_next->lcklst.le_prev = (fl)->lcklst.le_prev; *(fl)-> lcklst.le_prev = (fl)->lcklst.le_next; ; ; } while (0); | |||
| 547 | close(fl->fd); | |||
| 548 | return (fl->flags & LOCK_V40x02) ? | |||
| 549 | nlm4_denied_nolock : nlm_denied_nolocks; | |||
| 550 | case 0: | |||
| 551 | /* | |||
| 552 | * Attempt a blocking lock. Will have to call | |||
| 553 | * NLM_GRANTED later. | |||
| 554 | */ | |||
| 555 | setproctitle("%s.%" PRIu32"u", | |||
| 556 | fl->client_name, fl->client.svid); | |||
| 557 | lflags &= ~LOCK_NB0x04; | |||
| 558 | if(flock(fl->fd, lflags) != 0) { | |||
| 559 | syslog(LOG_NOTICE5, "flock failed (%m)"); | |||
| 560 | _exit(1); | |||
| 561 | } | |||
| 562 | /* lock granted */ | |||
| 563 | _exit(0); | |||
| 564 | /*NOTREACHED*/ | |||
| 565 | default: | |||
| 566 | syslog(LOG_DEBUG7, "lock request from %s.%" PRIu32"u" ": " | |||
| 567 | "forked %d", | |||
| 568 | fl->client_name, fl->client.svid, fl->locker); | |||
| 569 | fl->status = LKST_PROCESSING3; | |||
| 570 | return (fl->flags & LOCK_V40x02) ? | |||
| 571 | nlm4_blocked : nlm_blocked; | |||
| 572 | } | |||
| 573 | } | |||
| 574 | /* non block case */ | |||
| 575 | if (error != 0) { | |||
| 576 | switch (errno(*__errno())) { | |||
| 577 | case EAGAIN35: | |||
| 578 | error = nlm4_denied; | |||
| 579 | break; | |||
| 580 | case ESTALE70: | |||
| 581 | error = nlm4_stale_fh; | |||
| 582 | break; | |||
| 583 | case EROFS30: | |||
| 584 | error = nlm4_rofs; | |||
| 585 | break; | |||
| 586 | default: | |||
| 587 | error = nlm4_failed; | |||
| 588 | } | |||
| 589 | if ((fl->flags & LOCK_V40x02) == 0) | |||
| 590 | error = nlm_denied; | |||
| 591 | if (errno(*__errno()) != EAGAIN35) | |||
| 592 | syslog(LOG_NOTICE5, "flock for %s failed (%m)", | |||
| 593 | fl->client_name); | |||
| 594 | else syslog(LOG_DEBUG7, "flock for %s failed (%m)", | |||
| 595 | fl->client_name); | |||
| 596 | LIST_REMOVE(fl, lcklst)do { if ((fl)->lcklst.le_next != ((void *)0)) (fl)->lcklst .le_next->lcklst.le_prev = (fl)->lcklst.le_prev; *(fl)-> lcklst.le_prev = (fl)->lcklst.le_next; ; ; } while (0); | |||
| 597 | close(fl->fd); | |||
| 598 | return error; | |||
| 599 | } | |||
| 600 | fl->status = LKST_LOCKED1; | |||
| 601 | return (fl->flags & LOCK_V40x02) ? nlm4_granted : nlm_granted; | |||
| 602 | } | |||
| 603 | ||||
| 604 | void | |||
| 605 | send_granted(struct file_lock *fl, int opcode) | |||
| 606 | { | |||
| 607 | CLIENT *cli; | |||
| 608 | static char dummy; | |||
| 609 | struct timeval timeo; | |||
| 610 | int success; | |||
| 611 | static struct nlm_res retval; | |||
| 612 | static struct nlm4_res retval4; | |||
| 613 | ||||
| 614 | cli = get_client(fl->addr, | |||
| 615 | (fl->flags & LOCK_V40x02) ? NLM_VERS4((u_long)4) : NLM_VERS((u_long)1)); | |||
| 616 | if (cli == NULL((void *)0)) { | |||
| 617 | syslog(LOG_NOTICE5, "failed to get CLIENT for %s.%" PRIu32"u", | |||
| 618 | fl->client_name, fl->client.svid); | |||
| 619 | /* | |||
| 620 | * We fail to notify remote that the lock has been granted. | |||
| 621 | * The client will timeout and retry, the lock will be | |||
| 622 | * granted at this time. | |||
| 623 | */ | |||
| 624 | return; | |||
| 625 | } | |||
| 626 | timeo.tv_sec = 0; | |||
| 627 | timeo.tv_usec = (fl->flags & LOCK_ASYNC0x01) ? 0 : 500000; /* 0.5s */ | |||
| 628 | ||||
| 629 | if (fl->flags & LOCK_V40x02) { | |||
| 630 | static nlm4_testargs result; | |||
| 631 | result.cookie = fl->client_cookie; | |||
| 632 | result.exclusive = fl->client.exclusive; | |||
| 633 | result.alock.caller_name = fl->client_name; | |||
| 634 | result.alock.fh.n_len = fl->filehandle.fhsize; | |||
| 635 | result.alock.fh.n_bytes = fl->filehandle.fhdata; | |||
| 636 | result.alock.oh = fl->client.oh; | |||
| 637 | result.alock.svid = fl->client.svid; | |||
| 638 | result.alock.l_offset = fl->client.l_offset; | |||
| 639 | result.alock.l_len = fl->client.l_len; | |||
| 640 | syslog(LOG_DEBUG7, "sending v4 reply%s", | |||
| 641 | (fl->flags & LOCK_ASYNC0x01) ? " (async)":""); | |||
| 642 | if (fl->flags & LOCK_ASYNC0x01) { | |||
| 643 | success = clnt_call(cli, NLM4_GRANTED_MSG,((*(cli)->cl_ops->cl_call)(cli, ((u_long)10), xdr_nlm4_testargs , (caddr_t)&result, xdr_void, (caddr_t)&dummy, timeo) ) | |||
| 644 | xdr_nlm4_testargs, &result, xdr_void, &dummy, timeo)((*(cli)->cl_ops->cl_call)(cli, ((u_long)10), xdr_nlm4_testargs , (caddr_t)&result, xdr_void, (caddr_t)&dummy, timeo) ); | |||
| 645 | } else { | |||
| 646 | success = clnt_call(cli, NLM4_GRANTED,((*(cli)->cl_ops->cl_call)(cli, ((u_long)5), xdr_nlm4_testargs , (caddr_t)&result, xdr_nlm4_res, (caddr_t)&retval4, timeo )) | |||
| 647 | xdr_nlm4_testargs, &result, xdr_nlm4_res,((*(cli)->cl_ops->cl_call)(cli, ((u_long)5), xdr_nlm4_testargs , (caddr_t)&result, xdr_nlm4_res, (caddr_t)&retval4, timeo )) | |||
| 648 | &retval4, timeo)((*(cli)->cl_ops->cl_call)(cli, ((u_long)5), xdr_nlm4_testargs , (caddr_t)&result, xdr_nlm4_res, (caddr_t)&retval4, timeo )); | |||
| 649 | } | |||
| 650 | } else { | |||
| 651 | static nlm_testargs result; | |||
| 652 | ||||
| 653 | result.cookie = fl->client_cookie; | |||
| 654 | result.exclusive = fl->client.exclusive; | |||
| 655 | result.alock.caller_name = fl->client_name; | |||
| 656 | result.alock.fh.n_len = fl->filehandle.fhsize; | |||
| 657 | result.alock.fh.n_bytes = fl->filehandle.fhdata; | |||
| 658 | result.alock.oh = fl->client.oh; | |||
| 659 | result.alock.svid = fl->client.svid; | |||
| 660 | result.alock.l_offset = | |||
| 661 | (unsigned int)fl->client.l_offset; | |||
| 662 | result.alock.l_len = | |||
| 663 | (unsigned int)fl->client.l_len; | |||
| 664 | syslog(LOG_DEBUG7, "sending v1 reply%s", | |||
| 665 | (fl->flags & LOCK_ASYNC0x01) ? " (async)":""); | |||
| 666 | if (fl->flags & LOCK_ASYNC0x01) { | |||
| 667 | success = clnt_call(cli, NLM_GRANTED_MSG,((*(cli)->cl_ops->cl_call)(cli, ((u_long)10), xdr_nlm_testargs , (caddr_t)&result, xdr_void, (caddr_t)&dummy, timeo) ) | |||
| 668 | xdr_nlm_testargs, &result, xdr_void, &dummy, timeo)((*(cli)->cl_ops->cl_call)(cli, ((u_long)10), xdr_nlm_testargs , (caddr_t)&result, xdr_void, (caddr_t)&dummy, timeo) ); | |||
| 669 | } else { | |||
| 670 | success = clnt_call(cli, NLM_GRANTED,((*(cli)->cl_ops->cl_call)(cli, ((u_long)5), xdr_nlm_testargs , (caddr_t)&result, xdr_nlm_res, (caddr_t)&retval, timeo )) | |||
| 671 | xdr_nlm_testargs, &result, xdr_nlm_res,((*(cli)->cl_ops->cl_call)(cli, ((u_long)5), xdr_nlm_testargs , (caddr_t)&result, xdr_nlm_res, (caddr_t)&retval, timeo )) | |||
| 672 | &retval, timeo)((*(cli)->cl_ops->cl_call)(cli, ((u_long)5), xdr_nlm_testargs , (caddr_t)&result, xdr_nlm_res, (caddr_t)&retval, timeo )); | |||
| 673 | } | |||
| 674 | } | |||
| 675 | if (debug_level > 2) | |||
| 676 | syslog(LOG_DEBUG7, "clnt_call returns %d(%s) for granted", | |||
| 677 | success, clnt_sperrno(success)); | |||
| 678 | ||||
| 679 | } | |||
| 680 | ||||
| 681 | enum nlm_stats | |||
| 682 | do_unlock(struct file_lock *rfl) | |||
| 683 | { | |||
| 684 | struct file_lock *fl; | |||
| 685 | int error; | |||
| 686 | int lockst; | |||
| 687 | ||||
| 688 | /* unlock the file: closing is enough ! */ | |||
| 689 | if (close(rfl->fd) == -1) { | |||
| 690 | if (errno(*__errno()) == ESTALE70) | |||
| 691 | error = nlm4_stale_fh; | |||
| 692 | else | |||
| 693 | error = nlm4_failed; | |||
| 694 | if ((rfl->flags & LOCK_V40x02) == 0) | |||
| 695 | error = nlm_denied; | |||
| 696 | syslog(LOG_NOTICE5, "close failed (from %s) (%m)", | |||
| 697 | rfl->client_name); | |||
| 698 | } else { | |||
| 699 | error = (rfl->flags & LOCK_V40x02) ? | |||
| 700 | nlm4_granted : nlm_granted; | |||
| 701 | } | |||
| 702 | LIST_REMOVE(rfl, lcklst)do { if ((rfl)->lcklst.le_next != ((void *)0)) (rfl)->lcklst .le_next->lcklst.le_prev = (rfl)->lcklst.le_prev; *(rfl )->lcklst.le_prev = (rfl)->lcklst.le_next; ; ; } while ( 0); | |||
| 703 | ||||
| 704 | /* process the next LKST_WAITING lock request for this fh */ | |||
| 705 | LIST_FOREACH(fl, &lcklst_head, lcklst)for((fl) = ((&lcklst_head)->lh_first); (fl)!= ((void * )0); (fl) = ((fl)->lcklst.le_next)) { | |||
| 706 | if (fl->status != LKST_WAITING2 || | |||
| 707 | fhcmp(&rfl->filehandle, &fl->filehandle) != 0) | |||
| 708 | continue; | |||
| 709 | ||||
| 710 | lockst = do_lock(fl, 1); /* If it's LKST_WAITING we can block */ | |||
| 711 | switch (lockst) { | |||
| 712 | case nlm4_granted: | |||
| 713 | /* case nlm_granted: same as nlm4_granted */ | |||
| 714 | send_granted(fl, (fl->flags & LOCK_V40x02) ? | |||
| 715 | nlm4_granted : nlm_granted); | |||
| 716 | break; | |||
| 717 | case nlm4_blocked: | |||
| 718 | /* case nlm_blocked: same as nlm4_blocked */ | |||
| 719 | break; | |||
| 720 | default: | |||
| 721 | lfree(fl); | |||
| 722 | break; | |||
| 723 | } | |||
| 724 | break; | |||
| 725 | } | |||
| 726 | lfree(rfl); | |||
| ||||
| 727 | return error; | |||
| 728 | } | |||
| 729 | ||||
| 730 | void | |||
| 731 | siglock(void) | |||
| 732 | { | |||
| 733 | sigset_t block; | |||
| 734 | ||||
| 735 | sigemptyset(&block); | |||
| 736 | sigaddset(&block, SIGCHLD20); | |||
| 737 | ||||
| 738 | if (sigprocmask(SIG_BLOCK1, &block, NULL((void *)0)) == -1) { | |||
| 739 | syslog(LOG_WARNING4, "siglock failed (%m)"); | |||
| 740 | } | |||
| 741 | } | |||
| 742 | ||||
| 743 | void | |||
| 744 | sigunlock(void) | |||
| 745 | { | |||
| 746 | sigset_t block; | |||
| 747 | ||||
| 748 | sigemptyset(&block); | |||
| 749 | sigaddset(&block, SIGCHLD20); | |||
| 750 | ||||
| 751 | if (sigprocmask(SIG_UNBLOCK2, &block, NULL((void *)0)) == -1) { | |||
| 752 | syslog(LOG_WARNING4, "sigunlock failed (%m)"); | |||
| 753 | } | |||
| 754 | } | |||
| 755 | ||||
| 756 | /* monitor a host through rpc.statd, and keep a ref count */ | |||
| 757 | void | |||
| 758 | do_mon(const char *hostname) | |||
| 759 | { | |||
| 760 | static char localhost[] = "localhost"; | |||
| 761 | struct host *hp; | |||
| 762 | struct mon my_mon; | |||
| 763 | struct sm_stat_res result; | |||
| 764 | int retval; | |||
| 765 | ||||
| 766 | LIST_FOREACH(hp, &hostlst_head, hostlst)for((hp) = ((&hostlst_head)->lh_first); (hp)!= ((void * )0); (hp) = ((hp)->hostlst.le_next)) { | |||
| 767 | if (strcmp(hostname, hp->name) == 0) { | |||
| 768 | /* already monitored, just bump refcnt */ | |||
| 769 | hp->refcnt++; | |||
| 770 | return; | |||
| 771 | } | |||
| 772 | } | |||
| 773 | /* not found, have to create an entry for it */ | |||
| 774 | hp = malloc(sizeof(struct host)); | |||
| 775 | if (hp == NULL((void *)0)) { | |||
| 776 | syslog(LOG_WARNING4, "can't monitor host %s (%m)", hostname); | |||
| 777 | return; | |||
| 778 | } | |||
| 779 | strlcpy(hp->name, hostname, sizeof(hp->name)); | |||
| 780 | hp->refcnt = 1; | |||
| 781 | syslog(LOG_DEBUG7, "monitoring host %s", hostname); | |||
| 782 | memset(&my_mon, 0, sizeof(my_mon)); | |||
| 783 | my_mon.mon_id.mon_name = hp->name; | |||
| 784 | my_mon.mon_id.my_id.my_name = localhost; | |||
| 785 | my_mon.mon_id.my_id.my_prog = NLM_PROG((u_long)100021); | |||
| 786 | my_mon.mon_id.my_id.my_vers = NLM_SM((u_long)0); | |||
| 787 | my_mon.mon_id.my_id.my_proc = NLM_SM_NOTIFY((u_long)1); | |||
| 788 | if ((retval = callrpc(localhost, SM_PROG((u_long)100024), SM_VERS((u_long)1), SM_MON((u_long)2), xdr_mon, | |||
| 789 | (void *)&my_mon, xdr_sm_stat_res, (void *)&result)) != 0) { | |||
| 790 | syslog(LOG_WARNING4, "rpc to statd failed (%s)", | |||
| 791 | clnt_sperrno((enum clnt_stat)retval)); | |||
| 792 | free(hp); | |||
| 793 | return; | |||
| 794 | } | |||
| 795 | if (result.res_stat == stat_fail) { | |||
| 796 | syslog(LOG_WARNING4, "statd failed"); | |||
| 797 | free(hp); | |||
| 798 | return; | |||
| 799 | } | |||
| 800 | LIST_INSERT_HEAD(&hostlst_head, hp, hostlst)do { if (((hp)->hostlst.le_next = (&hostlst_head)-> lh_first) != ((void *)0)) (&hostlst_head)->lh_first-> hostlst.le_prev = &(hp)->hostlst.le_next; (&hostlst_head )->lh_first = (hp); (hp)->hostlst.le_prev = &(& hostlst_head)->lh_first; } while (0); | |||
| 801 | } | |||
| 802 | ||||
| 803 | void | |||
| 804 | notify(const char *hostname, int state) | |||
| 805 | { | |||
| 806 | struct file_lock *fl, *next_fl; | |||
| 807 | int err; | |||
| 808 | syslog(LOG_DEBUG7, "notify from %s, new state %d", hostname, state); | |||
| 809 | /* search all lock for this host; if status changed, release the lock */ | |||
| 810 | siglock(); | |||
| 811 | for (fl = LIST_FIRST(&lcklst_head)((&lcklst_head)->lh_first); fl != NULL((void *)0); fl = next_fl) { | |||
| ||||
| 812 | next_fl = LIST_NEXT(fl, lcklst)((fl)->lcklst.le_next); | |||
| 813 | if (strcmp(hostname, fl->client_name) == 0 && | |||
| 814 | fl->nsm_status != state) { | |||
| 815 | syslog(LOG_DEBUG7, "state %d, nsm_state %d, unlocking", | |||
| 816 | fl->status, fl->nsm_status); | |||
| 817 | switch(fl->status) { | |||
| 818 | case LKST_LOCKED1: | |||
| 819 | err = do_unlock(fl); | |||
| 820 | if (err != nlm_granted) | |||
| 821 | syslog(LOG_DEBUG7, | |||
| 822 | "notify: unlock failed for %s (%d)", | |||
| 823 | hostname, err); | |||
| 824 | break; | |||
| 825 | case LKST_WAITING2: | |||
| 826 | LIST_REMOVE(fl, lcklst)do { if ((fl)->lcklst.le_next != ((void *)0)) (fl)->lcklst .le_next->lcklst.le_prev = (fl)->lcklst.le_prev; *(fl)-> lcklst.le_prev = (fl)->lcklst.le_next; ; ; } while (0); | |||
| 827 | lfree(fl); | |||
| 828 | break; | |||
| 829 | case LKST_PROCESSING3: | |||
| 830 | fl->status = LKST_DYING4; | |||
| 831 | break; | |||
| 832 | case LKST_DYING4: | |||
| 833 | break; | |||
| 834 | default: | |||
| 835 | syslog(LOG_NOTICE5, "unknown status %d for %s", | |||
| 836 | fl->status, fl->client_name); | |||
| 837 | } | |||
| 838 | } | |||
| 839 | } | |||
| 840 | sigunlock(); | |||
| 841 | } |