diff options
author | dormando <dormando@rydia.net> | 2020-11-10 22:20:10 -0800 |
---|---|---|
committer | dormando <dormando@rydia.net> | 2020-11-11 21:23:35 -0800 |
commit | 2251d98cd7ecb7dd4b2f58fe9b97f5799eb39edc (patch) | |
tree | 089383cc7b09fdf7b98e778b354ce612200cf8bd | |
parent | 19aac5aeca5aaf588dc58d5c04264c6be14ff7c0 (diff) | |
download | memcached-2251d98cd7ecb7dd4b2f58fe9b97f5799eb39edc.tar.gz |
extstore: use fcntl locking on disk file
if you accidentally start memcached with the same options twice,
extstore is initiated before the listener sockets and will happily
truncate its own file.
So this avoids that. Keep in mind any other process can still wipe the
file clean!
-rw-r--r-- | extstore.c | 21 | ||||
-rw-r--r-- | t/extstore.t | 5 |
2 files changed, 24 insertions, 2 deletions
@@ -253,15 +253,32 @@ void *extstore_init(struct extstore_conf_file *fh, struct extstore_conf *cf, e->page_size = cf->page_size; uint64_t temp_page_count = 0; for (f = fh; f != NULL; f = f->next) { - f->fd = open(f->file, O_RDWR | O_CREAT | O_TRUNC, 0644); + f->fd = open(f->file, O_RDWR | O_CREAT, 0644); if (f->fd < 0) { *res = EXTSTORE_INIT_OPEN_FAIL; #ifdef EXTSTORE_DEBUG - perror("open"); + perror("extstore open"); #endif free(e); return NULL; } + // use an fcntl lock to help avoid double starting. + struct flock lock; + lock.l_type = F_WRLCK; + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + if (fcntl(f->fd, F_SETLK, &lock) < 0) { + *res = EXTSTORE_INIT_OPEN_FAIL; + free(e); + return NULL; + } + if (ftruncate(f->fd, 0) < 0) { + *res = EXTSTORE_INIT_OPEN_FAIL; + free(e); + return NULL; + } + temp_page_count += f->page_count; f->offset = 0; } diff --git a/t/extstore.t b/t/extstore.t index 1790a54..116a7f4 100644 --- a/t/extstore.t +++ b/t/extstore.t @@ -20,6 +20,11 @@ $ext_path = "/tmp/extstore.$$"; my $server = new_memcached("-m 64 -U 0 -o ext_page_size=8,ext_wbuf_size=2,ext_threads=1,ext_io_depth=2,ext_item_size=512,ext_item_age=2,ext_recache_rate=10000,ext_max_frag=0.9,ext_path=$ext_path:64m,slab_automove=0,ext_compact_under=1"); my $sock = $server->sock; +eval { + my $server = new_memcached("-o ext_path=$ext_path:64m"); +}; +ok($@, "failed to start a second server with the same file path"); + # Wait until all items have flushed sub wait_for_ext { my $target = shift || 0; |