summaryrefslogtreecommitdiff
path: root/minix/lib/libfsdriver/fsdriver.c
blob: 1443e9ff70b8b44d56402fa64f11bbd244c00bb4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97

#include "fsdriver.h"

/* Library-local variables. */
dev_t fsdriver_device;
ino_t fsdriver_root;
int fsdriver_mounted = FALSE;

static int fsdriver_running;

/*
 * Process an incoming VFS request, and send a reply.  If the message is not
 * a file system request from VFS, pass it on to the generic message handler.
 * Multithreaded file systems should indicate that the reply is to be sent to
 * VFS asynchronously.
 */
void
fsdriver_process(const struct fsdriver * __restrict fdp,
	const message * __restrict m_ptr, int ipc_status, int asyn_reply)
{
	message m_out;
	unsigned int call_nr;
	int r, transid;

	/* Is this a file system request at all? */
	if (is_ipc_notify(ipc_status) || m_ptr->m_source != VFS_PROC_NR) {
		if (fdp->fdr_other != NULL)
			fdp->fdr_other(m_ptr, ipc_status);

		return; /* do not send a reply */
	}

	/* Call the appropriate function. */
	transid = TRNS_GET_ID(m_ptr->m_type);
	call_nr = TRNS_DEL_ID(m_ptr->m_type);

	memset(&m_out, 0, sizeof(m_out));

	if (fsdriver_mounted || call_nr == REQ_READSUPER) {
		call_nr -= FS_BASE;	/* unsigned; wrapping is intended */

		if (call_nr < NREQS && fsdriver_callvec[call_nr] != NULL)
			r = (fsdriver_callvec[call_nr])(fdp, m_ptr, &m_out);
		else
			r = ENOSYS;
	} else
		r = EINVAL;

	/* Send a reply. */
	m_out.m_type = TRNS_ADD_ID(r, transid);

	if (asyn_reply)
		r = asynsend(m_ptr->m_source, &m_out);
	else
		r = ipc_send(m_ptr->m_source, &m_out);

	if (r != OK)
		printf("fsdriver: sending reply failed (%d)\n", r);

	if (fdp->fdr_postcall != NULL)
		fdp->fdr_postcall();
}

/*
 * Terminate the file server as soon as the file system has been unmounted.
 */
void
fsdriver_terminate(void)
{

	fsdriver_running = FALSE;

	sef_cancel();
}

/*
 * Main program of any file server task.
 */
void
fsdriver_task(struct fsdriver * fdp)
{
	message mess;
	int r, ipc_status;

	fsdriver_running = TRUE;

	while (fsdriver_running || fsdriver_mounted) {
		if ((r = sef_receive_status(ANY, &mess, &ipc_status)) != OK) {
			if (r == EINTR)
				continue;	/* sef_cancel() was called */

			panic("fsdriver: sef_receive_status failed: %d", r);
		}

		fsdriver_process(fdp, &mess, ipc_status, FALSE /*asyn_reply*/);
	}
}