From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Tue, 19 May 2020 12:08:45 -0500 Subject: [PATCH] libmultipath: use atomic linkat() in mark_failed_wwid() This keeps (almost) the simplicity of the previous patch, while making sure that the return value of mark_failed_wwid() (WWID_FAILED_CHANGED vs. WWID_FAILED_UNCHANGED) is correct, even if several processes access this WWID at the same time. Signed-off-by: Martin Wilck Signed-off-by: Benjamin Marzinski --- libmultipath/wwids.c | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/libmultipath/wwids.c b/libmultipath/wwids.c index aab5da8a..61d9c39e 100644 --- a/libmultipath/wwids.c +++ b/libmultipath/wwids.c @@ -374,7 +374,7 @@ int is_failed_wwid(const char *wwid) if (safe_sprintf(path, "%s/%s", shm_dir, wwid)) { condlog(1, "%s: path name overflow", __func__); - return -1; + return WWID_FAILED_ERROR; } if (lstat(path, &st) == 0) @@ -390,27 +390,43 @@ int is_failed_wwid(const char *wwid) int mark_failed_wwid(const char *wwid) { - char path[PATH_MAX]; - int r, fd; + char tmpfile[WWID_SIZE + 2 * sizeof(long) + 1]; + int r = WWID_FAILED_ERROR, fd, dfd; - if (safe_sprintf(path, "%s/%s", shm_dir, wwid)) { - condlog(1, "%s: path name overflow", __func__); - return -1; + dfd = open(shm_dir, O_RDONLY|O_DIRECTORY); + if (dfd == -1 && errno == ENOENT) { + char path[sizeof(shm_dir) + 2]; + + /* arg for ensure_directories_exist() must not end with "/" */ + safe_sprintf(path, "%s/_", shm_dir); + ensure_directories_exist(path, 0700); + dfd = open(shm_dir, O_RDONLY|O_DIRECTORY); } - if (ensure_directories_exist(path, 0700) < 0) { - condlog(1, "%s: can't setup directories", __func__); - return -1; + if (dfd == -1) { + condlog(1, "%s: can't setup %s: %m", __func__, shm_dir); + return WWID_FAILED_ERROR; } - fd = open(path, O_RDONLY | O_CREAT | O_EXCL, S_IRUSR); - if (fd >= 0) { + safe_sprintf(tmpfile, "%s.%lx", wwid, (long)getpid()); + fd = openat(dfd, tmpfile, O_RDONLY | O_CREAT | O_EXCL, S_IRUSR); + if (fd >= 0) close(fd); + else + goto out_closedir; + + if (linkat(dfd, tmpfile, dfd, wwid, 0) == 0) r = WWID_FAILED_CHANGED; - } else if (errno == EEXIST) + else if (errno == EEXIST) r = WWID_FAILED_UNCHANGED; else r = WWID_FAILED_ERROR; + if (unlinkat(dfd, tmpfile, 0) == -1) + condlog(2, "%s: failed to unlink %s/%s: %m", + __func__, shm_dir, tmpfile); + +out_closedir: + close(dfd); print_failed_wwid_result("mark_failed", wwid, r); return r; } @@ -422,7 +438,7 @@ int unmark_failed_wwid(const char *wwid) if (safe_sprintf(path, "%s/%s", shm_dir, wwid)) { condlog(1, "%s: path name overflow", __func__); - return -1; + return WWID_FAILED_ERROR; } if (unlink(path) == 0) -- 2.17.2