]> git.proxmox.com Git - mirror_zfs.git/blobdiff - module/zfs/spa_errlog.c
Teach zpool scrub to scrub only blocks in error log
[mirror_zfs.git] / module / zfs / spa_errlog.c
index 5fe35278683a7cfe96d661e1290e06fd6050afd7..2e5c22c11490148430308bfc1a2ae0f1ef5e9380 100644 (file)
@@ -110,7 +110,7 @@ errphys_to_name(zbookmark_err_phys_t *zep, char *buf, size_t len)
 /*
  * Convert a string to a err_phys.
  */
-static void
+void
 name_to_errphys(char *buf, zbookmark_err_phys_t *zep)
 {
        zep->zb_object = zfs_strtonum(buf, &buf);
@@ -139,8 +139,7 @@ name_to_bookmark(char *buf, zbookmark_phys_t *zb)
        ASSERT(*buf == '\0');
 }
 
-#ifdef _KERNEL
-static void
+void
 zep_to_zb(uint64_t dataset, zbookmark_err_phys_t *zep, zbookmark_phys_t *zb)
 {
        zb->zb_objset = dataset;
@@ -148,7 +147,6 @@ zep_to_zb(uint64_t dataset, zbookmark_err_phys_t *zep, zbookmark_phys_t *zb)
        zb->zb_level = zep->zb_level;
        zb->zb_blkid = zep->zb_blkid;
 }
-#endif
 
 static void
 name_to_object(char *buf, uint64_t *obj)
@@ -238,8 +236,7 @@ spa_log_error(spa_t *spa, const zbookmark_phys_t *zb, const uint64_t *birth)
        mutex_exit(&spa->spa_errlist_lock);
 }
 
-#ifdef _KERNEL
-static int
+int
 find_birth_txg(dsl_dataset_t *ds, zbookmark_err_phys_t *zep,
     uint64_t *birth_txg)
 {
@@ -267,6 +264,34 @@ find_birth_txg(dsl_dataset_t *ds, zbookmark_err_phys_t *zep,
        return (error);
 }
 
+/*
+ * This function finds the oldest affected filesystem containing an error
+ * block.
+ */
+int
+find_top_affected_fs(spa_t *spa, uint64_t head_ds, zbookmark_err_phys_t *zep,
+    uint64_t *top_affected_fs)
+{
+       uint64_t oldest_dsobj;
+       int error = dsl_dataset_oldest_snapshot(spa, head_ds, zep->zb_birth,
+           &oldest_dsobj);
+       if (error != 0)
+               return (error);
+
+       dsl_dataset_t *ds;
+       error = dsl_dataset_hold_obj_flags(spa->spa_dsl_pool, oldest_dsobj,
+           DS_HOLD_FLAG_DECRYPT, FTAG, &ds);
+       if (error != 0)
+               return (error);
+
+       *top_affected_fs =
+           dsl_dir_phys(ds->ds_dir)->dd_head_dataset_obj;
+       dsl_dataset_rele_flags(ds, DS_HOLD_FLAG_DECRYPT, FTAG);
+       return (0);
+}
+
+
+#ifdef _KERNEL
 /*
  * Copy the bookmark to the end of the user-space buffer which starts at
  * uaddr and has *count unused entries, and decrement *count by 1.
@@ -288,7 +313,8 @@ copyout_entry(const zbookmark_phys_t *zb, void *uaddr, uint64_t *count)
  * Each time the error block is referenced by a snapshot or clone, add a
  * zbookmark_phys_t entry to the userspace array at uaddr. The array is
  * filled from the back and the in-out parameter *count is modified to be the
- * number of unused entries at the beginning of the array.
+ * number of unused entries at the beginning of the array. The function
+ * scrub_filesystem() is modelled after this one.
  */
 static int
 check_filesystem(spa_t *spa, uint64_t head_ds, zbookmark_err_phys_t *zep,
@@ -449,28 +475,6 @@ out:
        return (error);
 }
 
-static int
-find_top_affected_fs(spa_t *spa, uint64_t head_ds, zbookmark_err_phys_t *zep,
-    uint64_t *top_affected_fs)
-{
-       uint64_t oldest_dsobj;
-       int error = dsl_dataset_oldest_snapshot(spa, head_ds, zep->zb_birth,
-           &oldest_dsobj);
-       if (error != 0)
-               return (error);
-
-       dsl_dataset_t *ds;
-       error = dsl_dataset_hold_obj_flags(spa->spa_dsl_pool, oldest_dsobj,
-           DS_HOLD_FLAG_DECRYPT, FTAG, &ds);
-       if (error != 0)
-               return (error);
-
-       *top_affected_fs =
-           dsl_dir_phys(ds->ds_dir)->dd_head_dataset_obj;
-       dsl_dataset_rele_flags(ds, DS_HOLD_FLAG_DECRYPT, FTAG);
-       return (0);
-}
-
 static int
 process_error_block(spa_t *spa, uint64_t head_ds, zbookmark_err_phys_t *zep,
     void *uaddr, uint64_t *count)
@@ -536,6 +540,21 @@ process_error_block(spa_t *spa, uint64_t head_ds, zbookmark_err_phys_t *zep,
 }
 #endif
 
+/* Return the number of errors in the error log */
+uint64_t
+spa_get_last_errlog_size(spa_t *spa)
+{
+       uint64_t total = 0, count;
+       mutex_enter(&spa->spa_errlog_lock);
+
+       if (spa->spa_errlog_last != 0 &&
+           zap_count(spa->spa_meta_objset, spa->spa_errlog_last,
+           &count) == 0)
+               total += count;
+       mutex_exit(&spa->spa_errlog_lock);
+       return (total);
+}
+
 /*
  * If a healed bookmark matches an entry in the error log we stash it in a tree
  * so that we can later remove the related log entries in sync context.
@@ -1447,6 +1466,7 @@ spa_swap_errlog(spa_t *spa, uint64_t new_head_ds, uint64_t old_head_ds,
 /* error handling */
 EXPORT_SYMBOL(spa_log_error);
 EXPORT_SYMBOL(spa_approx_errlog_size);
+EXPORT_SYMBOL(spa_get_last_errlog_size);
 EXPORT_SYMBOL(spa_get_errlog);
 EXPORT_SYMBOL(spa_errlog_rotate);
 EXPORT_SYMBOL(spa_errlog_drain);
@@ -1456,6 +1476,10 @@ EXPORT_SYMBOL(spa_delete_dataset_errlog);
 EXPORT_SYMBOL(spa_swap_errlog);
 EXPORT_SYMBOL(sync_error_list);
 EXPORT_SYMBOL(spa_upgrade_errlog);
+EXPORT_SYMBOL(find_top_affected_fs);
+EXPORT_SYMBOL(find_birth_txg);
+EXPORT_SYMBOL(zep_to_zb);
+EXPORT_SYMBOL(name_to_errphys);
 #endif
 
 /* BEGIN CSTYLED */