Whamcloud - gitweb
LU-12515 ofd: allow setting a target to readonly 04/56304/10
authorRonnie Sahlberg <rsahlberg@whamcloud.com>
Fri, 6 Sep 2024 04:29:30 +0000 (00:29 -0400)
committerOleg Drokin <green@whamcloud.com>
Mon, 2 Dec 2024 05:49:29 +0000 (05:49 +0000)
Add a control to toggle read-only mode for an OFD
to have it reject all mutating commands with -EROFS

This can be used to temporarily set a device to readonly mode
while identifying and correcting a misbehaving client.
As this prevents clients from destaging data it should not
be kept in readonly mode for too long else clients will
eventually run out of kernel memory.

Example:
   lctl set_param obdfilter.lustre-OST0000.readonly=1

Test-Parameters: trivial
Signed-off-by: Ronnie Sahlberg <rsahlberg@whamcloud.com>
Change-Id: Ia6658fb58aea17624d5c2ef2528696c4355e7b05
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/56304
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Alex Zhuravlev <bzzz@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/ofd/lproc_ofd.c
lustre/ofd/ofd_internal.h
lustre/ofd/ofd_trans.c
lustre/tests/sanity.sh

index 91e7094..15b4934 100644 (file)
@@ -347,6 +347,56 @@ LUSTRE_RW_ATTR(no_precreate);
 #endif
 
 /**
+ * Show if the OFD is in read-only mode.
+ *
+ * This means OFD has been adminstratively disabled at the OST to prevent
+ * writing to the OFD.
+ *
+ * \retval             number of bytes written
+ */
+static ssize_t readonly_show(struct kobject *kobj, struct attribute *attr,
+                            char *buf)
+{
+       struct obd_device *obd = container_of(kobj, struct obd_device,
+                                             obd_kset.kobj);
+       struct ofd_device *ofd = ofd_dev(obd->obd_lu_dev);
+
+       return scnprintf(buf, PAGE_SIZE, "%u\n", ofd->ofd_readonly);
+}
+
+/**
+ * Set OFD to readonly mode.
+ *
+ * This is used to interface to userspace administrative tools to
+ * set the OST read-only.
+ *
+ * \param[in] count    \a buffer length
+ *
+ * \retval             \a count on success
+ * \retval             negative number on error
+ */
+static ssize_t readonly_store(struct kobject *kobj, struct attribute *attr,
+                             const char *buffer, size_t count)
+{
+       struct obd_device *obd = container_of(kobj, struct obd_device,
+                                             obd_kset.kobj);
+       struct ofd_device *ofd = ofd_dev(obd->obd_lu_dev);
+       bool val;
+       int rc;
+
+       rc = kstrtobool(buffer, &val);
+       if (rc)
+               return rc;
+
+       spin_lock(&ofd->ofd_flags_lock);
+       ofd->ofd_readonly = val;
+       spin_unlock(&ofd->ofd_flags_lock);
+
+       return count;
+}
+LUSTRE_RW_ATTR(readonly);
+
+/**
  * Show OFD filesystem type.
  *
  * \param[in] m                seq_file handle
@@ -1023,6 +1073,7 @@ static struct attribute *ofd_attrs[] = {
        &lustre_attr_job_cleanup_interval.attr,
        &lustre_attr_lfsck_speed_limit.attr,
        &lustre_attr_no_create.attr,
+       &lustre_attr_readonly.attr,
 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 20, 53, 0)
        &lustre_attr_no_precreate.attr,
 #endif
index 8670136..730d86f 100644 (file)
@@ -142,7 +142,8 @@ struct ofd_device {
                                 ofd_lastid_rebuilding:1,
                                 ofd_record_fid_accessed:1,
                                 ofd_lfsck_verify_pfid:1,
-                                ofd_skip_lfsck:1;
+                                ofd_skip_lfsck:1,
+                                ofd_readonly:1;
        struct seq_server_site   ofd_seq_site;
        /* the limit of SOFT_SYNC RPCs that will trigger a soft sync */
        unsigned int             ofd_soft_sync_limit;
index 367ca24..963de2e 100644 (file)
@@ -61,6 +61,12 @@ struct thandle *ofd_trans_create(const struct lu_env *env,
 
        LASSERT(info);
 
+       if (unlikely(ofd->ofd_readonly)) {
+               CERROR("%s: Deny transaction for read-only OFD device\n",
+                      ofd_name(ofd));
+               return ERR_PTR(-EROFS);
+       }
+
        th = dt_trans_create(env, ofd->ofd_osd);
        if (IS_ERR(th))
                return th;
index 945a0fb..0350bed 100755 (executable)
@@ -32645,6 +32645,33 @@ test_802b() {
 }
 run_test 802b "be able to set MDTs to readonly"
 
+test_802c() {
+       [ $PARALLEL == "yes" ] && skip "skip parallel run"
+
+       do_facet ost1 $LCTL get_param obdfilter.*.readonly ||
+               skip "readonly option not available"
+
+       $LFS mkdir -i 0 -c 1 $DIR/$tdir || error "(1) fail to mkdir"
+
+       cp $LUSTRE/tests/test-framework.sh $DIR/$tdir/ ||
+               error "(2) Fail to copy"
+
+       # write back all cached data before setting OFD to readonly
+       cancel_lru_locks
+       sync_all_data
+
+       do_facet ost1 $LCTL set_param obdfilter.*.readonly=1
+       stack_trap "do_facet ost1 $LCTL set_param obdfilter.*.readonly=0" EXIT
+
+       echo "Modify should be refused"
+       touch $DIR/$tdir/guard && error "(6) Touch should fail under ro mode"
+
+       echo "Read should be allowed"
+       diff $LUSTRE/tests/test-framework.sh $DIR/$tdir/test-framework.sh ||
+               error "(7) Read should succeed under ro mode"
+}
+run_test 802c "be able to set OFDs to readonly"
+
 test_803a() {
        [[ $MDSCOUNT -lt 2 ]] && skip_env "needs >= 2 MDTs"
        [ $MDS1_VERSION -lt $(version_code 2.10.54) ] &&