summaryrefslogtreecommitdiff
path: root/fatfs
diff options
context:
space:
mode:
authorJames Clarke <jrtc27@jrtc27.com>2015-08-27 17:22:11 +0100
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2015-09-06 21:40:20 +0200
commit7a2c17fcbb789997421725d726340301ef35d84c (patch)
treeea51083985eaf4c5aad3d21716a77863dd241e0a /fatfs
parent918a8c2ce462cea65e3e7a614f19b4f5ae4ff1e1 (diff)
Fix race condition in ext2fs when remounting
On some systems, ext2fs.static would regularly hang at startup, as a race condition meant it would process paging requests while remounting. To fix this, libpager has been altered to allow inhibiting and resuming its worker threads, and ext2fs uses this to inhibit paging while remounting. * console/pager.c (pager_requests): New variable. (user_pager_init): Updated call to pager_start_workers to use new pager_requests variable. * daemons/runsystem.sh: Removed artificial delay working around the race condition. * ext2fs/ext2fs.c (diskfs_reload_global_state): Call new inhibit_ext2_pager and resume_ext2_pager functions, and leave sblock as non-NULL so it will be munmapped. * ext2fs/ext2fs.h (inhibit_ext2_pager,resume_ext2_pager): New functions. * ext2fs/pager.c (file_pager_requests): New variable. (create_disk_pager): Updated call to pager_start_workers to use new file_pager_requests variable. (inhibit_ext2_pager,resume_ext2_pager): New functions. * fatfs/fatfs.h (inhibit_fat_pager,resume_fat_pager): New functions. * fatfs/pager.c (file_pager_requests): New variable. (create_fat_pager): Updated call to pager_start_workers to use new file_pager_requests variable. (inhibit_fat_pager,resume_fat_pager): New functions. * libdiskfs/disk-pager.c (diskfs_disk_pager_requests): New variable. (diskfs_start_disk_pager): Updated call to pager_start_workers to use new diskfs_disk_pager_requests variable. * libdiskfs/diskfs-pager.h (diskfs_disk_pager_requests): New variable. * libpager/demuxer.c (struct pager_requests): Renamed struct requests to struct pager_requests. Replaced queue with queue_in and queue_out pointers. Added inhibit_wakeup field. (pager_demuxer): Updated to use new queue_in/queue_out pointers. Only wake up workers if not inhibited. (worker_func): Updated to use new queue_in/queue_out pointers. Final worker thread to sleep notifies the inhibit_wakeup condition variable. (pager_start_workers): Added out parameter for the requests instance. Allocate heap space shared by both queues. Initialise new inhibit_wakeup condition. (pager_inhibit_workers,pager_resume_workers): New functions. * libpager/pager.h (struct pager_requests): Public forward definition. (pager_start_workers): Added out parameter for the requests instance. (pager_inhibit_workers,pager_resume_workers): New functions. * libpager/queue.h (queue_empty): New function. * storeio/pager.c (pager_requests): New variable. (init_dev_paging): Updated call to pager_start_workers to use new pager_requests variable.
Diffstat (limited to 'fatfs')
-rw-r--r--fatfs/fatfs.h2
-rw-r--r--fatfs/pager.c33
2 files changed, 34 insertions, 1 deletions
diff --git a/fatfs/fatfs.h b/fatfs/fatfs.h
index 3c3d8366..54c3426a 100644
--- a/fatfs/fatfs.h
+++ b/fatfs/fatfs.h
@@ -121,6 +121,8 @@ extern struct dirrect dr_root_node;
void drop_pager_softrefs (struct node *);
void allow_pager_softrefs (struct node *);
void create_fat_pager (void);
+error_t inhibit_fat_pager (void);
+void resume_fat_pager (void);
void flush_node_pager (struct node *node);
diff --git a/fatfs/pager.c b/fatfs/pager.c
index 10d1fc96..d255f290 100644
--- a/fatfs/pager.c
+++ b/fatfs/pager.c
@@ -29,6 +29,10 @@ struct port_bucket *disk_pager_bucket;
/* A ports bucket to hold file pager ports. */
struct port_bucket *file_pager_bucket;
+/* Stores a reference to the requests instance used by the file pager so its
+ worker threads can be inhibited and resumed. */
+struct pager_requests *file_pager_requests;
+
/* Mapped image of the FAT. */
void *fat_image;
@@ -776,11 +780,38 @@ create_fat_pager (void)
file_pager_bucket = ports_create_bucket ();
/* Start libpagers worker threads. */
- err = pager_start_workers (file_pager_bucket);
+ err = pager_start_workers (file_pager_bucket, &file_pager_requests);
if (err)
error (2, err, "can't create libpager worker threads");
}
+error_t
+inhibit_fat_pager (void)
+{
+ error_t err;
+
+ /* The file pager can rely on the disk pager, so inhibit the file
+ pager first. */
+
+ err = pager_inhibit_workers (file_pager_requests);
+ if (err)
+ return err;
+
+ err = pager_inhibit_workers (diskfs_disk_pager_requests);
+ /* We don't want only one pager disabled. */
+ if (err)
+ pager_resume_workers (file_pager_requests);
+
+ return err;
+}
+
+void
+resume_fat_pager (void)
+{
+ pager_resume_workers (diskfs_disk_pager_requests);
+ pager_resume_workers (file_pager_requests);
+}
+
/* Call this to create a FILE_DATA pager and return a send right.
NODE must be locked. */
mach_port_t