Skip to content

Commit e6cfd63

Browse files
Will Andrewsbehlendorf
authored andcommitted
Illumos 3749 - zfs event processing should work on R/O root filesystems
3749 zfs event processing should work on R/O root filesystems Reviewed by: Matthew Ahrens <mahrens@delphix.com> Reviewed by: Eric Schrock <eric.schrock@delphix.com> Approved by: Christopher Siden <christopher.siden@delphix.com> References: https://www.illumos.org/issues/3749 illumos/illumos-gate@3cb69f7 Porting notes: - [include/sys/spa_impl.h] - ffe9d38 Add generic errata infrastructure - 1421c89 Add visibility in to arc_read - [include/sys/fm/fs/zfs.h] - 2668527 Add linux events - 6283f55 Support custom build directories and move includes - [module/zfs/spa_config.c] - Updated spa_config_sync() to match illumos with the exception of a Linux specific block. Ported-by: kernelOfTruth kerneloftruth@gmail.com Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
1 parent 7ea4f88 commit e6cfd63

File tree

4 files changed

+77
-20
lines changed

4 files changed

+77
-20
lines changed

include/sys/fm/fs/zfs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ extern "C" {
5656
#define FM_EREPORT_ZFS_IO_FAILURE "io_failure"
5757
#define FM_EREPORT_ZFS_PROBE_FAILURE "probe_failure"
5858
#define FM_EREPORT_ZFS_LOG_REPLAY "log_replay"
59+
#define FM_EREPORT_ZFS_CONFIG_CACHE_WRITE "config_cache_write"
5960
#define FM_EREPORT_ZFS_RESILVER_START "resilver.start"
6061
#define FM_EREPORT_ZFS_RESILVER_FINISH "resilver.finish"
6162
#define FM_EREPORT_ZFS_SCRUB_START "scrub.start"

include/sys/spa_impl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ struct spa {
252252
uint64_t spa_deadman_synctime; /* deadman expiration timer */
253253
uint64_t spa_errata; /* errata issues detected */
254254
spa_stats_t spa_stats; /* assorted spa statistics */
255+
hrtime_t spa_ccw_fail_time; /* Conf cache write fail time */
255256

256257
/*
257258
* spa_refcount & spa_config_lock must be the last elements

module/zfs/spa.c

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@
8282
#include "zfs_prop.h"
8383
#include "zfs_comutil.h"
8484

85+
/*
86+
* The interval, in seconds, at which failed configuration cache file writes
87+
* should be retried.
88+
*/
89+
static int zfs_ccw_retry_interval = 300;
90+
8591
typedef enum zti_modes {
8692
ZTI_MODE_FIXED, /* value is # of threads (min 1) */
8793
ZTI_MODE_BATCH, /* cpu-intensive; value is ignored */
@@ -5912,13 +5918,34 @@ spa_async_resume(spa_t *spa)
59125918
mutex_exit(&spa->spa_async_lock);
59135919
}
59145920

5921+
static boolean_t
5922+
spa_async_tasks_pending(spa_t *spa)
5923+
{
5924+
uint_t non_config_tasks;
5925+
uint_t config_task;
5926+
boolean_t config_task_suspended;
5927+
5928+
non_config_tasks = spa->spa_async_tasks & ~SPA_ASYNC_CONFIG_UPDATE;
5929+
config_task = spa->spa_async_tasks & SPA_ASYNC_CONFIG_UPDATE;
5930+
if (spa->spa_ccw_fail_time == 0) {
5931+
config_task_suspended = B_FALSE;
5932+
} else {
5933+
config_task_suspended =
5934+
(gethrtime() - spa->spa_ccw_fail_time) <
5935+
(zfs_ccw_retry_interval * NANOSEC);
5936+
}
5937+
5938+
return (non_config_tasks || (config_task && !config_task_suspended));
5939+
}
5940+
59155941
static void
59165942
spa_async_dispatch(spa_t *spa)
59175943
{
59185944
mutex_enter(&spa->spa_async_lock);
5919-
if (spa->spa_async_tasks && !spa->spa_async_suspended &&
5945+
if (spa_async_tasks_pending(spa) &&
5946+
!spa->spa_async_suspended &&
59205947
spa->spa_async_thread == NULL &&
5921-
rootdir != NULL && !vn_is_readonly(rootdir))
5948+
rootdir != NULL)
59225949
spa->spa_async_thread = thread_create(NULL, 0,
59235950
spa_async_thread, spa, 0, &p0, TS_RUN, maxclsyspri);
59245951
mutex_exit(&spa->spa_async_lock);

module/zfs/spa_config.c

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
*/
2727

2828
#include <sys/spa.h>
29+
#include <sys/fm/fs/zfs.h>
2930
#include <sys/spa_impl.h>
3031
#include <sys/nvpair.h>
3132
#include <sys/uio.h>
@@ -145,22 +146,22 @@ spa_config_load(void)
145146
kobj_close_file(file);
146147
}
147148

148-
static void
149+
static int
149150
spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl)
150151
{
151152
size_t buflen;
152153
char *buf;
153154
vnode_t *vp;
154155
int oflags = FWRITE | FTRUNC | FCREAT | FOFFMAX;
155-
int error;
156156
char *temp;
157+
int err;
157158

158159
/*
159160
* If the nvlist is empty (NULL), then remove the old cachefile.
160161
*/
161162
if (nvl == NULL) {
162-
(void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE);
163-
return;
163+
err = vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE);
164+
return (err);
164165
}
165166

166167
/*
@@ -181,16 +182,16 @@ spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl)
181182
* and overwritten in place. In the event of an error the file is
182183
* unlinked to make sure we always have a consistent view of the data.
183184
*/
184-
error = vn_open(dp->scd_path, UIO_SYSSPACE, oflags, 0644, &vp, 0, 0);
185-
if (error == 0) {
186-
error = vn_rdwr(UIO_WRITE, vp, buf, buflen, 0,
185+
err = vn_open(dp->scd_path, UIO_SYSSPACE, oflags, 0644, &vp, 0, 0);
186+
if (err == 0) {
187+
err = vn_rdwr(UIO_WRITE, vp, buf, buflen, 0,
187188
UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, NULL);
188-
if (error == 0)
189-
error = VOP_FSYNC(vp, FSYNC, kcred, NULL);
189+
if (err == 0)
190+
err = VOP_FSYNC(vp, FSYNC, kcred, NULL);
190191

191192
(void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL);
192193

193-
if (error)
194+
if (err)
194195
(void) vn_remove(dp->scd_path, UIO_SYSSPACE, RMFILE);
195196
}
196197
#else
@@ -201,13 +202,14 @@ spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl)
201202
*/
202203
(void) snprintf(temp, MAXPATHLEN, "%s.tmp", dp->scd_path);
203204

204-
error = vn_open(temp, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0);
205-
if (error == 0) {
206-
if (vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE,
207-
0, RLIM64_INFINITY, kcred, NULL) == 0 &&
208-
VOP_FSYNC(vp, FSYNC, kcred, NULL) == 0) {
209-
(void) vn_rename(temp, dp->scd_path, UIO_SYSSPACE);
210-
}
205+
err = vn_open(temp, UIO_SYSSPACE, oflags, 0644, &vp, CRCREAT, 0);
206+
if (err == 0) {
207+
err = vn_rdwr(UIO_WRITE, vp, buf, buflen, 0, UIO_SYSSPACE,
208+
0, RLIM64_INFINITY, kcred, NULL);
209+
if (err == 0)
210+
err = VOP_FSYNC(vp, FSYNC, kcred, NULL);
211+
if (err == 0)
212+
err = vn_rename(temp, dp->scd_path, UIO_SYSSPACE);
211213
(void) VOP_CLOSE(vp, oflags, 1, 0, kcred, NULL);
212214
}
213215

@@ -216,6 +218,7 @@ spa_config_write(spa_config_dirent_t *dp, nvlist_t *nvl)
216218

217219
vmem_free(buf, buflen);
218220
kmem_free(temp, MAXPATHLEN);
221+
return (err);
219222
}
220223

221224
/*
@@ -233,6 +236,8 @@ spa_config_sync(spa_t *target, boolean_t removing, boolean_t postsysevent)
233236
spa_config_dirent_t *dp, *tdp;
234237
nvlist_t *nvl;
235238
char *pool_name;
239+
boolean_t ccw_failure;
240+
int error = 0;
236241

237242
ASSERT(MUTEX_HELD(&spa_namespace_lock));
238243

@@ -244,6 +249,7 @@ spa_config_sync(spa_t *target, boolean_t removing, boolean_t postsysevent)
244249
* cachefile is changed, the new one is pushed onto this list, allowing
245250
* us to update previous cachefiles that no longer contain this pool.
246251
*/
252+
ccw_failure = B_FALSE;
247253
for (dp = list_head(&target->spa_config_list); dp != NULL;
248254
dp = list_next(&target->spa_config_list, dp)) {
249255
spa_t *spa = NULL;
@@ -290,10 +296,32 @@ spa_config_sync(spa_t *target, boolean_t removing, boolean_t postsysevent)
290296
mutex_exit(&spa->spa_props_lock);
291297
}
292298

293-
spa_config_write(dp, nvl);
299+
error = spa_config_write(dp, nvl);
300+
if (error != 0)
301+
ccw_failure = B_TRUE;
294302
nvlist_free(nvl);
295303
}
296304

305+
if (ccw_failure) {
306+
/*
307+
* Keep trying so that configuration data is
308+
* written if/when any temporary filesystem
309+
* resource issues are resolved.
310+
*/
311+
if (target->spa_ccw_fail_time == 0) {
312+
zfs_ereport_post(FM_EREPORT_ZFS_CONFIG_CACHE_WRITE,
313+
target, NULL, NULL, 0, 0);
314+
}
315+
target->spa_ccw_fail_time = gethrtime();
316+
spa_async_request(target, SPA_ASYNC_CONFIG_UPDATE);
317+
} else {
318+
/*
319+
* Do not rate limit future attempts to update
320+
* the config cache.
321+
*/
322+
target->spa_ccw_fail_time = 0;
323+
}
324+
297325
/*
298326
* Remove any config entries older than the current one.
299327
*/

0 commit comments

Comments
 (0)