2525#include <netinet/in.h>
2626#include <stdlib.h>
2727#include <string.h>
28- #include <sys/stat.h>
29- #include <unistd.h>
3028#include "coverage.h"
3129#include "dynamic-string.h"
30+ #include "lockfile.h"
3231#include "ofpbuf.h"
3332#include "packets.h"
3433#include "svec.h"
@@ -52,8 +51,7 @@ static char *cfg_name;
5251static char * tmp_name ;
5352
5453/* Lock information. */
55- static char * lock_name ;
56- static int lock_fd = -1 ;
54+ static struct lockfile * lockfile ;
5755
5856/* Flag to indicate whether local modifications have been made. */
5957static bool dirty ;
@@ -106,15 +104,14 @@ cfg_init(void)
106104int
107105cfg_set_file (const char * file_name )
108106{
109- const char * slash ;
107+ char * lock_name ;
110108 int fd ;
111109
112110 if (cfg_name ) {
113- assert (lock_fd < 0 );
111+ assert (! lockfile );
114112 free (cfg_name );
115- free (lock_name );
116113 free (tmp_name );
117- cfg_name = lock_name = tmp_name = NULL ;
114+ cfg_name = tmp_name = NULL ;
118115 }
119116
120117 /* Make sure that we can open this file for reading. */
@@ -131,18 +128,11 @@ cfg_set_file(const char *file_name)
131128 * rename(tmp_name, cfg_name) will work. */
132129 tmp_name = xasprintf ("%s.~tmp~" , file_name );
133130
134- /* Put the lock file in the same directory as cfg_name, but prefixed by
135- * a dot so as not to garner administrator interest. */
136- slash = strrchr (file_name , '/' );
137- if (slash ) {
138- lock_name = xasprintf ("%.*s/.%s.~lock~" ,
139- slash - file_name , file_name , slash + 1 );
140- } else {
141- lock_name = xasprintf (".%s.~lock~" , file_name );
142- }
143-
131+ lock_name = lockfile_name (file_name );
144132 VLOG_INFO ("using \"%s\" as configuration file, \"%s\" as lock file" ,
145133 file_name , lock_name );
134+ free (lock_name );
135+
146136 return 0 ;
147137}
148138
@@ -280,61 +270,12 @@ cfg_get_cookie(uint8_t *cookie)
280270void
281271cfg_unlock (void )
282272{
283- if (lock_fd != -1 ) {
284- COVERAGE_INC (cfg_unlock );
285- close (lock_fd );
286- lock_fd = -1 ;
287- }
288- }
289-
290- static int
291- open_lockfile (const char * name )
292- {
293- for (;;) {
294- /* Try to open an existing lock file. */
295- int fd = open (name , O_RDWR );
296- if (fd >= 0 ) {
297- return fd ;
298- } else if (errno != ENOENT ) {
299- VLOG_WARN ("%s: failed to open lock file: %s" ,
300- name , strerror (errno ));
301- return - errno ;
302- }
303-
304- /* Try to create a new lock file. */
305- VLOG_INFO ("%s: lock file does not exist, creating" , name );
306- fd = open (name , O_RDWR | O_CREAT | O_EXCL , 0600 );
307- if (fd >= 0 ) {
308- return fd ;
309- } else if (errno != EEXIST ) {
310- VLOG_WARN ("%s: failed to create lock file: %s" ,
311- name , strerror (errno ));
312- return - errno ;
313- }
314-
315- /* Someone else created the lock file. Try again. */
273+ if (lockfile ) {
274+ lockfile_unlock (lockfile );
275+ lockfile = NULL ;
316276 }
317277}
318278
319- static int
320- try_lock (int fd , bool block )
321- {
322- struct flock l ;
323- int error ;
324-
325- memset (& l , 0 , sizeof l );
326- l .l_type = F_WRLCK ;
327- l .l_whence = SEEK_SET ;
328- l .l_start = 0 ;
329- l .l_len = 0 ;
330-
331- time_disable_restart ();
332- error = fcntl (fd , block ? F_SETLKW : F_SETLK , & l ) == -1 ? errno : 0 ;
333- time_enable_restart ();
334-
335- return error ;
336- }
337-
338279/* Locks the configuration file against modification by other processes and
339280 * re-reads it from disk.
340281 *
@@ -346,65 +287,18 @@ try_lock(int fd, bool block)
346287int
347288cfg_lock (uint8_t * cookie , int timeout )
348289{
349- long long int start ;
350- long long int elapsed = 0 ;
351- int fd ;
352- uint8_t curr_cookie [CFG_COOKIE_LEN ];
353-
354- assert (lock_fd < 0 );
355- COVERAGE_INC (cfg_lock );
356-
357- time_refresh ();
358- start = time_msec ();
359- for (;;) {
360- int error ;
361-
362- /* Open lock file. */
363- fd = open_lockfile (lock_name );
364- if (fd < 0 ) {
365- return - fd ;
366- }
367-
368- /* Try to lock it. This will block (if 'timeout' > 0). */
369- error = try_lock (fd , timeout > 0 );
370- time_refresh ();
371- elapsed = time_msec () - start ;
372- if (!error ) {
373- /* Success! */
374- break ;
375- }
376-
377- /* Lock failed. Close the lock file and reopen it on the next
378- * iteration, just in case someone deletes it underneath us (even
379- * though that should not happen). */
380- close (fd );
381- if (error != EINTR ) {
382- /* Hard error, give up. */
383- COVERAGE_INC (cfg_lock_error );
384- VLOG_WARN ("%s: failed to lock file "
385- "(after %lld ms, with %d-ms timeout): %s" ,
386- lock_name , elapsed , timeout , strerror (error ));
387- return error ;
388- }
290+ int error ;
389291
390- /* Probably, the periodic timer set up by time_init() woke up us. Just
391- * check whether it's time to give up. */
392- if (timeout != INT_MAX && elapsed >= timeout ) {
393- COVERAGE_INC (cfg_lock_timeout );
394- VLOG_WARN ("%s: giving up on lock file after %lld ms" ,
395- lock_name , elapsed );
396- return ETIMEDOUT ;
397- }
398- COVERAGE_INC (cfg_lock_retry );
399- }
400- if (elapsed ) {
401- VLOG_WARN ("%s: waited %lld ms for lock file" , lock_name , elapsed );
292+ assert (!lockfile );
293+ error = lockfile_lock (cfg_name , timeout , & lockfile );
294+ if (error ) {
295+ return error ;
402296 }
403- lock_fd = fd ;
404297
405298 cfg_read ();
406299
407300 if (cookie ) {
301+ uint8_t curr_cookie [CFG_COOKIE_LEN ];
408302 cfg_get_cookie (curr_cookie );
409303
410304 if (memcmp (curr_cookie , cookie , sizeof * curr_cookie )) {
0 commit comments