Hello, I recently installed freeradius and have it forwarding accounting information. I noticed that there were a lot of failed locks in the logs, so I began to investigate. In rlm_detail, I found this loop for locking: do { if (inst->locking) { lseek(outfd, 0L, SEEK_SET); if (rad_lockfd_nonblock(outfd, 0) < 0) { close(outfd); tv.tv_sec = 0; tv.tv_usec = 25000; select(0, NULL, NULL, NULL, &tv); lock_count++; } else { DEBUG("rlm_detail: Acquired filelock, tried %d time(s)", lock_count + 1); locked = 1; } } } while (!locked && inst->locking && lock_count < 80); This loop, if it fails on the first lock, might as well not try again. Why? Because it closes the file descriptor when it fails. All of the following calls just come back with 'bad file descriptor'. The oddest part about this is that I had found this thread: http://osdir.com/ml/freeradius.devel/2005-03/msg00112.html It looks like the locking should work perfectly! But it seems these changes never found their way into the 1.x series, despite having occurred two years ago. I poked around in CVS and found revision 1.43 which is when the corrected locking was added. I took a diff of revision 1.42 and 1.43, and applied it by hand to 1.1.7. I haven't had any complaints from freeradius about locking issues since. I have attached the patch. Is there any reason this never found its way into the 1.x series? I see it's in the CVS head. --- src/modules/rlm_detail/rlm_detail.c.orig 2007-11-21 14:53:45.000000000 -0800 +++ src/modules/rlm_detail/rlm_detail.c 2007-11-26 11:41:58.000000000 -0800 @@ -271,25 +271,24 @@ *p = '/'; } /* else there was no directory delimiter. */ - /* - * Open & create the file, with the given permissions. - */ - if ((outfd = open(buffer, O_WRONLY | O_APPEND | O_CREAT, - inst->detailperm)) < 0) { - radlog(L_ERR, "rlm_detail: Couldn't open file %s: %s", - buffer, strerror(errno)); - return RLM_MODULE_FAIL; - } - - /* - * If we're not using locking, we'll just pass straight though - * the while loop. - * If we fail to aquire the filelock in 80 tries (approximately - * two seconds) we bail out. - */ locked = 0; lock_count = 0; do { + /* + * Open & create the file, with the given + * permissions. + */ + if ((outfd = open(buffer, O_WRONLY | O_APPEND | O_CREAT, + inst->detailperm)) < 0) { + radlog(L_ERR, "rlm_detail: Couldn't open file %s: %s", + buffer, strerror(errno)); + return RLM_MODULE_FAIL; + } + + /* + * If we fail to aquire the filelock in 80 tries + * (approximately two seconds) we bail out. + */ if (inst->locking) { lseek(outfd, 0L, SEEK_SET); if (rad_lockfd_nonblock(outfd, 0) < 0) { @@ -298,15 +297,36 @@ tv.tv_usec = 25000; select(0, NULL, NULL, NULL, &tv); lock_count++; - } else { - DEBUG("rlm_detail: Acquired filelock, tried %d time(s)", - lock_count + 1); - locked = 1; + continue; + } + + /* + * The file might have been deleted by + * radrelay while we tried to acquire + * the lock (race condition) + */ + if (fstat(outfd, &st) != 0) { + radlog(L_ERR, "rlm_detail: Couldn't stat file %s: %s", + buffer, strerror(errno)); + close(outfd); + return RLM_MODULE_FAIL; } + if (st.st_nlink == 0) { + DEBUG("rlm_detail: File %s removed by another program, retrying", + buffer); + close(outfd); + lock_count = 0; + continue; + } + + DEBUG("rlm_detail: Acquired filelock, tried %d time(s)", + lock_count + 1); + locked = 1; } - } while (!locked && inst->locking && lock_count < 80); + } while (inst->locking && !locked && lock_count < 80); - if (!locked && inst->locking && lock_count >= 80) { + if (inst->locking && !locked) { + close(outfd); radlog(L_ERR, "rlm_detail: Failed to aquire filelock for %s, giving up", buffer); return RLM_MODULE_FAIL;