From d95edceb362a6b647ec454c2a83add11c4ed4e64 Mon Sep 17 00:00:00 2001 From: Mariusz Tkaczyk Date: Tue, 24 Sep 2024 15:53:18 +0200 Subject: sysfs: add function for writing to sysfs fd Proposed function sysfs_wrte_descriptor() unifies error handling for write() done to sysfs files. Main purpose is to use it with MD sysfs file but it can be used elsewhere. No functional changes. Signed-off-by: Mariusz Tkaczyk --- Manage.c | 45 ++++++++++++++++++++++++------------------ managemon.c | 13 +++---------- mdadm.h | 3 +++ monitor.c | 12 ++---------- sysfs.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++------------ util.c | 19 +++++++++++++----- 6 files changed, 101 insertions(+), 56 deletions(-) diff --git a/Manage.c b/Manage.c index aba97df8..0f232a57 100644 --- a/Manage.c +++ b/Manage.c @@ -1439,7 +1439,7 @@ int Manage_subdevs(char *devname, int fd, for (dv = devlist; dv; dv = dv->next) { dev_t rdev = 0; /* device to add/remove etc */ - int rv; + int rv, err = 0; int mj,mn; raid_slot = -1; @@ -1670,9 +1670,8 @@ int Manage_subdevs(char *devname, int fd, rv = Manage_remove(tst, fd, dv, sysfd, rdev, verbose, force, devname); - if (sysfd >= 0) - close_fd(&sysfd); - sysfd = -1; + close_fd(&sysfd); + if (rv < 0) goto abort; if (rv > 0) @@ -1686,23 +1685,31 @@ int Manage_subdevs(char *devname, int fd, close_fd(&sysfd); goto abort; } - case 'I': /* incremental fail */ - if ((sysfd >= 0 && write(sysfd, "faulty", 6) != 6) || - (sysfd < 0 && ioctl(fd, SET_DISK_FAULTY, - rdev))) { - if (errno == EBUSY) - busy = 1; - pr_err("set device faulty failed for %s: %s\n", - dv->devname, strerror(errno)); - close_fd(&sysfd); - goto abort; + case 'I': + if (is_fd_valid(sysfd)) { + static const char val[] = "faulty"; + + rv = sysfs_write_descriptor(sysfd, val, strlen(val), &err); + } else { + rv = ioctl(fd, SET_DISK_FAULTY, rdev); + if (rv) + err = errno; } + close_fd(&sysfd); - count++; - if (verbose >= 0) - pr_err("set %s faulty in %s\n", - dv->devname, devname); - break; + + if (rv == MDADM_STATUS_SUCCESS) { + count++; + + pr_vrb("set %s faulty in %s\n", dv->devname, devname); + break; + } + + if (err == EBUSY) + busy = 1; + + pr_err("set device faulty failed for %s: %s\n", dv->devname, strerror(err)); + goto abort; case 'R': /* Mark as replaceable */ if (subarray) { pr_err("Cannot replace disks in a \'member\' array, perform this operation on the parent container\n"); diff --git a/managemon.c b/managemon.c index add6a79e..877e8605 100644 --- a/managemon.c +++ b/managemon.c @@ -512,16 +512,9 @@ static void manage_member(struct mdstat_ent *mdstat, if (a->container == NULL) return; - if (sigterm && a->info.safe_mode_delay != 1 && - a->safe_mode_delay_fd >= 0) { - long int new_delay = 1; - char delay[10]; - ssize_t len; - - len = snprintf(delay, sizeof(delay), "0.%03ld\n", new_delay); - if (write(a->safe_mode_delay_fd, delay, len) == len) - a->info.safe_mode_delay = new_delay; - } + if (sigterm && a->info.safe_mode_delay != 1 && a->safe_mode_delay_fd >= 0) + if (write_attr("0.001", a->safe_mode_delay_fd) == MDADM_STATUS_SUCCESS) + a->info.safe_mode_delay = 1; /* We don't check the array while any update is pending, as it * might container a change (such as a spare assignment) which diff --git a/mdadm.h b/mdadm.h index d4f5702c..ce8155b5 100644 --- a/mdadm.h +++ b/mdadm.h @@ -803,6 +803,9 @@ enum sysfs_read_flags { #define SYSFS_MAX_BUF_SIZE 64 +extern mdadm_status_t sysfs_write_descriptor(const int fd, const char *value, + const ssize_t len, int *errno_p); +extern mdadm_status_t write_attr(const char *value, const int fd); extern void sysfs_get_container_devnm(struct mdinfo *mdi, char *buf); /* If fd >= 0, get the array it is open on, diff --git a/monitor.c b/monitor.c index be0bec78..a4f707cc 100644 --- a/monitor.c +++ b/monitor.c @@ -35,11 +35,6 @@ enum bb_action { COMPARE_BB, }; -static int write_attr(char *attr, int fd) -{ - return write(fd, attr, strlen(attr)); -} - static void add_fd(fd_set *fds, int *maxfd, int fd) { struct stat st; @@ -173,7 +168,7 @@ int process_ubb(struct active_array *a, struct mdinfo *mdi, const unsigned long * via sysfs file */ if ((ss->record_bad_block(a, mdi->disk.raid_disk, sector, length)) && - (write(mdi->bb_fd, buf, buf_len) == buf_len)) + (sysfs_write_descriptor(mdi->bb_fd, buf, buf_len, NULL) == MDADM_STATUS_SUCCESS)) return 1; /* @@ -622,14 +617,11 @@ static int read_and_act(struct active_array *a, fd_set *fds) } if ((mdi->next_state & DS_REMOVE) && mdi->state_fd >= 0) { - int remove_result; - /* The kernel may not be able to immediately remove the * disk. In that case we wait a little while and * try again. */ - remove_result = write_attr("remove", mdi->state_fd); - if (remove_result > 0) { + if (write_attr("remove", mdi->state_fd) == MDADM_STATUS_SUCCESS) { dprintf_cont(" %d:removed", mdi->disk.raid_disk); close(mdi->state_fd); close(mdi->recovery_fd); diff --git a/sysfs.c b/sysfs.c index b3c8b10d..7a81cc5b 100644 --- a/sysfs.c +++ b/sysfs.c @@ -73,6 +73,47 @@ void sysfs_free(struct mdinfo *sra) sra = sra2; } } +/** + * write_attr() - write value to fd, don't check errno. + * @attr: value to write. + * @fd: file descriptor write to. + * + * Size to write is calculated by strlen(). + */ +mdadm_status_t write_attr(const char *value, const int fd) +{ + return sysfs_write_descriptor(fd, value, strlen(value), NULL); +} + +/** + * sysfs_write_descriptor()- wrapper for write(), projected to be used with sysfs. + * @fd: file descriptor. + * @value: value to set. + * @len: length of the value. + * @errno_p: On write() failure, buffer to copy errno value, might be NULL. + * + * Errors are differentiated, because (at least theoretically) kernel may not process whole string + * and it may or may not be a problem (it depends on implementation in kernel). Decision belongs to + * caller then. + * Generally, it should be safe to check if @errno_p changed to determine if error occurred. + */ +mdadm_status_t sysfs_write_descriptor(const int fd, const char *value, const ssize_t len, + int *errno_p) +{ + ssize_t ret; + + ret = write(fd, value, len); + if (ret == -1) { + if (errno_p) + *errno_p = errno; + return MDADM_STATUS_ERROR; + } + + if (ret != len) + return MDADM_STATUS_UNDEF; + + return MDADM_STATUS_SUCCESS; +} /** * sysfs_get_container_devnm() - extract container device name. @@ -486,7 +527,6 @@ int sysfs_set_str(struct mdinfo *sra, struct mdinfo *dev, char *name, char *val) { char fname[MAX_SYSFS_PATH_LEN]; - unsigned int n; int fd; snprintf(fname, MAX_SYSFS_PATH_LEN, "/sys/block/%s/md/%s/%s", @@ -494,13 +534,14 @@ int sysfs_set_str(struct mdinfo *sra, struct mdinfo *dev, fd = open(fname, O_WRONLY); if (fd < 0) return -1; - n = write(fd, val, strlen(val)); - close(fd); - if (n != strlen(val)) { - dprintf("failed to write '%s' to '%s' (%s)\n", - val, fname, strerror(errno)); + + if (write_attr(val, fd)) { + pr_err("failed to write '%s' to '%s' (%s)\n", val, fname, strerror(errno)); + close(fd); return -1; } + + close(fd); return 0; } @@ -523,7 +564,6 @@ int sysfs_set_num_signed(struct mdinfo *sra, struct mdinfo *dev, int sysfs_uevent(struct mdinfo *sra, char *event) { char fname[MAX_SYSFS_PATH_LEN]; - int n; int fd; snprintf(fname, MAX_SYSFS_PATH_LEN, "/sys/block/%s/uevent", @@ -531,13 +571,14 @@ int sysfs_uevent(struct mdinfo *sra, char *event) fd = open(fname, O_WRONLY); if (fd < 0) return -1; - n = write(fd, event, strlen(event)); - close(fd); - if (n != (int)strlen(event)) { - dprintf("failed to write '%s' to '%s' (%s)\n", - event, fname, strerror(errno)); + + if (write_attr(event, fd)) { + pr_err("failed to write '%s' to '%s' (%s)\n", event, fname, strerror(errno)); + close(fd); return -1; } + + close(fd); return 0; } diff --git a/util.c b/util.c index cc162278..2b660725 100644 --- a/util.c +++ b/util.c @@ -1854,13 +1854,22 @@ int hot_remove_disk(int mdfd, unsigned long dev, int force) int sys_hot_remove_disk(int statefd, int force) { int cnt = force ? 500 : 5; - int ret; + static const char val[] = "faulty"; + + while (cnt--) { + int err = 0; + int ret = sysfs_write_descriptor(statefd, val, strlen(val), &err); + + if (ret == MDADM_STATUS_SUCCESS) + return 0; + + if (err != EBUSY) + break; - while ((ret = write(statefd, "remove", 6)) == -1 && - errno == EBUSY && - cnt-- > 0) sleep_for(0, MSEC_TO_NSEC(10), true); - return ret == 6 ? 0 : -1; + } + + return -1; } int set_array_info(int mdfd, struct supertype *st, struct mdinfo *info) -- cgit v1.2.3