aboutsummaryrefslogtreecommitdiff
path: root/libdiskfs/shutdown.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdiskfs/shutdown.c')
-rw-r--r--libdiskfs/shutdown.c104
1 files changed, 104 insertions, 0 deletions
diff --git a/libdiskfs/shutdown.c b/libdiskfs/shutdown.c
new file mode 100644
index 00000000..1a544f5b
--- /dev/null
+++ b/libdiskfs/shutdown.c
@@ -0,0 +1,104 @@
+/*
+ Copyright (C) 1993, 94, 95, 96, 98, 99 Free Software Foundation, Inc.
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Michael I. Bushnell. */
+
+#include "priv.h"
+#include <hurd/fsys.h>
+
+struct rwlock diskfs_fsys_lock = RWLOCK_INITIALIZER;
+
+/* Shutdown the filesystem; flags are as for fsys_goaway. */
+error_t
+diskfs_shutdown (int flags)
+{
+ int nports = -1;
+ int err;
+
+ error_t
+ helper (struct node *np)
+ {
+ error_t error;
+ mach_port_t control;
+
+ error = fshelp_fetch_control (&np->transbox, &control);
+ mutex_unlock (&np->lock);
+ if (!error && (control != MACH_PORT_NULL))
+ {
+ error = fsys_goaway (control, flags);
+ mach_port_deallocate (mach_task_self (), control);
+ }
+ else
+ error = 0;
+ mutex_lock (&np->lock);
+
+ if ((error == MIG_SERVER_DIED) || (error == MACH_SEND_INVALID_DEST))
+ error = 0;
+
+ return error;
+ }
+
+ if ((flags & FSYS_GOAWAY_UNLINK)
+ && S_ISDIR (diskfs_root_node->dn_stat.st_mode))
+ return EBUSY;
+
+ if (flags & FSYS_GOAWAY_RECURSE)
+ {
+ err = diskfs_node_iterate (helper);
+ if (err)
+ return err;
+ }
+
+ rwlock_writer_lock (&diskfs_fsys_lock);
+
+ /* Permit all the current RPC's to finish, and then
+ suspend new ones. */
+ err = ports_inhibit_class_rpcs (diskfs_protid_class);
+ if (err)
+ {
+ rwlock_writer_unlock (&diskfs_fsys_lock);
+ return err;
+ }
+
+ /* Write everything out and set "clean" state. Even if we don't in fact
+ shut down now, this has the nice effect that a disk that has not been
+ written for a long time will not need checking after a crash. */
+ diskfs_sync_everything (1);
+ diskfs_set_hypermetadata (1, 1);
+ _diskfs_diskdirty = 0;
+
+ /* First, see if there are outstanding user ports. */
+ nports = ports_count_class (diskfs_protid_class);
+ if (((flags & FSYS_GOAWAY_FORCE) == 0)
+ && (nports || diskfs_pager_users ()))
+ {
+ ports_enable_class (diskfs_protid_class);
+ ports_resume_class_rpcs (diskfs_protid_class);
+ rwlock_writer_unlock (&diskfs_fsys_lock);
+ return EBUSY;
+ }
+
+ if (!diskfs_readonly && (flags & FSYS_GOAWAY_NOSYNC) == 0)
+ {
+ diskfs_shutdown_pager ();
+ diskfs_set_hypermetadata (1, 1);
+ }
+
+ return 0;
+}