]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
sysfs: add function for writing to sysfs fd
authorMariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Tue, 24 Sep 2024 13:53:18 +0000 (15:53 +0200)
committerMariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Fri, 27 Sep 2024 09:08:49 +0000 (11:08 +0200)
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 <mariusz.tkaczyk@linux.intel.com>
Manage.c
managemon.c
mdadm.h
monitor.c
sysfs.c
util.c

index aba97df8e122588fa631192696570997c4e93ec5..0f232a579d9ecf28f3ca360dc4b5d4a38e4c8bd5 100644 (file)
--- 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");
index add6a79e43b6391f5d0ac6bc41efc1f4f3ed6f30..877e8605bcb0b530118990f3014ae32aeb96d8c0 100644 (file)
@@ -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 d4f5702c88b15708cd839960e137cd784bd2e139..ce8155b51077cc59dfcd2c1c5132b141ce349001 100644 (file)
--- 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,
index be0bec785080351412f4a1fcd07e031e1d356b68..a4f707ccb8f0cbf7dfce1a73d89fc7ae8906d915 100644 (file)
--- 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 b3c8b10d97089a8929da824a4dfe46b7f31c14e2..7a81cc5b4ffd65073d322b88aaea63d7606c8e19 100644 (file)
--- 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 cc162278cfac1217e8d42a7fcb2fee2914a54d0b..2b6607252402668be786ddc087124ef43664f3d3 100644 (file)
--- 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)