xref: /minix3/minix/drivers/storage/fbd/rule.c (revision 63ce03db6646a88deff65bad27b873bbfe71a4e1)
1433d6423SLionel Sambuc #include <minix/drivers.h>
2433d6423SLionel Sambuc #include <minix/ioctl.h>
3433d6423SLionel Sambuc #include <sys/ioc_fbd.h>
4433d6423SLionel Sambuc 
5433d6423SLionel Sambuc #include "action.h"
6433d6423SLionel Sambuc #include "rule.h"
7433d6423SLionel Sambuc 
8433d6423SLionel Sambuc static struct fbd_rule rules[MAX_RULES];
9433d6423SLionel Sambuc static struct fbd_rule *matches[MAX_RULES];
10433d6423SLionel Sambuc static int nr_matches;
11433d6423SLionel Sambuc 
12433d6423SLionel Sambuc /*===========================================================================*
13433d6423SLionel Sambuc  *				rule_ctl				     *
14433d6423SLionel Sambuc  *===========================================================================*/
rule_ctl(unsigned long request,endpoint_t endpt,cp_grant_id_t grant)15*63ce03dbSDavid van Moolenbroek int rule_ctl(unsigned long request, endpoint_t endpt, cp_grant_id_t grant)
16433d6423SLionel Sambuc {
17433d6423SLionel Sambuc 	/* Handle an I/O control request regarding rules. */
18433d6423SLionel Sambuc 	fbd_rulenum_t i;
19433d6423SLionel Sambuc 	int r;
20433d6423SLionel Sambuc 
21433d6423SLionel Sambuc 	/* Note that any of the safecopy calls may fail if the ioctl is
22433d6423SLionel Sambuc 	 * improperly defined in userland; never panic if they fail!
23433d6423SLionel Sambuc 	 */
24433d6423SLionel Sambuc 	switch (request) {
25433d6423SLionel Sambuc 	case FBDCADDRULE:
26433d6423SLionel Sambuc 		/* Find a free rule slot. */
27433d6423SLionel Sambuc 		for (i = 1; i <= MAX_RULES; i++)
28433d6423SLionel Sambuc 			if (rules[i-1].num == 0)
29433d6423SLionel Sambuc 				break;
30433d6423SLionel Sambuc 
31433d6423SLionel Sambuc 		if (i == MAX_RULES+1)
32433d6423SLionel Sambuc 			return ENOMEM;
33433d6423SLionel Sambuc 
34433d6423SLionel Sambuc 		/* Copy in the rule. */
35433d6423SLionel Sambuc 		if ((r = sys_safecopyfrom(endpt, grant, 0,
36433d6423SLionel Sambuc 				(vir_bytes) &rules[i-1], sizeof(rules[0]))) != OK)
37433d6423SLionel Sambuc 			return r;
38433d6423SLionel Sambuc 
39433d6423SLionel Sambuc 		/* Mark the rule as active, and return its number. */
40433d6423SLionel Sambuc 		rules[i-1].num = i;
41433d6423SLionel Sambuc 
42433d6423SLionel Sambuc 		return i;
43433d6423SLionel Sambuc 
44433d6423SLionel Sambuc 	case FBDCDELRULE:
45433d6423SLionel Sambuc 		/* Copy in the given rule number. */
46433d6423SLionel Sambuc 		if ((r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &i,
47433d6423SLionel Sambuc 				sizeof(i))) != OK)
48433d6423SLionel Sambuc 			return r;
49433d6423SLionel Sambuc 
50433d6423SLionel Sambuc 		/* Fail if the given rule number is not valid or in use.
51433d6423SLionel Sambuc 		 * Allow the caller to determine the maximum rule number.
52433d6423SLionel Sambuc 		 */
53433d6423SLionel Sambuc 		if (i <= 0 || i > MAX_RULES) return EINVAL;
54433d6423SLionel Sambuc 
55433d6423SLionel Sambuc 		if (rules[i-1].num != i) return ENOENT;
56433d6423SLionel Sambuc 
57433d6423SLionel Sambuc 		/* Mark the rule as not active. */
58433d6423SLionel Sambuc 		rules[i-1].num = 0;
59433d6423SLionel Sambuc 
60433d6423SLionel Sambuc 		return OK;
61433d6423SLionel Sambuc 
62433d6423SLionel Sambuc 	case FBDCGETRULE:
63433d6423SLionel Sambuc 		/* Copy in just the rule number from the given structure. */
64433d6423SLionel Sambuc 		if ((r = sys_safecopyfrom(endpt, grant,
65433d6423SLionel Sambuc 				offsetof(struct fbd_rule, num), (vir_bytes) &i,
66433d6423SLionel Sambuc 				sizeof(i))) != OK)
67433d6423SLionel Sambuc 			return r;
68433d6423SLionel Sambuc 
69433d6423SLionel Sambuc 		/* Fail if the given rule number is not valid or in use.
70433d6423SLionel Sambuc 		 * Allow the caller to determine the maximum rule number.
71433d6423SLionel Sambuc 		 */
72433d6423SLionel Sambuc 		if (i <= 0 || i > MAX_RULES) return EINVAL;
73433d6423SLionel Sambuc 
74433d6423SLionel Sambuc 		if (rules[i-1].num != i) return ENOENT;
75433d6423SLionel Sambuc 
76433d6423SLionel Sambuc 		/* Copy out the entire rule as is. */
77433d6423SLionel Sambuc 		return sys_safecopyto(endpt, grant, 0, (vir_bytes) &rules[i-1],
78433d6423SLionel Sambuc 				sizeof(rules[0]));
79433d6423SLionel Sambuc 
80433d6423SLionel Sambuc 	default:
81433d6423SLionel Sambuc 		return EINVAL;
82433d6423SLionel Sambuc 	}
83433d6423SLionel Sambuc }
84433d6423SLionel Sambuc 
85433d6423SLionel Sambuc /*===========================================================================*
86433d6423SLionel Sambuc  *				rule_match				     *
87433d6423SLionel Sambuc  *===========================================================================*/
rule_match(struct fbd_rule * rule,u64_t pos,size_t size,int flag)88433d6423SLionel Sambuc static int rule_match(struct fbd_rule *rule, u64_t pos, size_t size, int flag)
89433d6423SLionel Sambuc {
90433d6423SLionel Sambuc 	/* Check whether the given rule matches the given parameters. As side
91433d6423SLionel Sambuc 	 * effect, update counters in the rule as appropriate.
92433d6423SLionel Sambuc 	 */
93433d6423SLionel Sambuc 
94433d6423SLionel Sambuc 	/* Ranges must overlap (start < pos+size && end > pos). */
95433d6423SLionel Sambuc 	if (rule->start >= pos + size ||
96433d6423SLionel Sambuc 			(rule->end != 0 && rule->end <= pos))
97433d6423SLionel Sambuc 		return FALSE;
98433d6423SLionel Sambuc 
99433d6423SLionel Sambuc 	/* Flags must match. */
100433d6423SLionel Sambuc 	if (!(rule->flags & flag)) return FALSE;
101433d6423SLionel Sambuc 
102433d6423SLionel Sambuc 	/* This is a match, but is it supposed to trigger yet? */
103433d6423SLionel Sambuc 	if (rule->skip > 0) {
104433d6423SLionel Sambuc 		rule->skip--;
105433d6423SLionel Sambuc 
106433d6423SLionel Sambuc 		return FALSE;
107433d6423SLionel Sambuc 	}
108433d6423SLionel Sambuc 
109433d6423SLionel Sambuc 	return TRUE;
110433d6423SLionel Sambuc }
111433d6423SLionel Sambuc 
112433d6423SLionel Sambuc /*===========================================================================*
113433d6423SLionel Sambuc  *				rule_find				     *
114433d6423SLionel Sambuc  *===========================================================================*/
rule_find(u64_t pos,size_t size,int flag)115433d6423SLionel Sambuc int rule_find(u64_t pos, size_t size, int flag)
116433d6423SLionel Sambuc {
117433d6423SLionel Sambuc 	/* Find all matching rules, and return a hook mask. */
118433d6423SLionel Sambuc 	struct fbd_rule *rule;
119433d6423SLionel Sambuc 	int i, hooks;
120433d6423SLionel Sambuc 
121433d6423SLionel Sambuc 	nr_matches = 0;
122433d6423SLionel Sambuc 	hooks = 0;
123433d6423SLionel Sambuc 
124433d6423SLionel Sambuc 	for (i = 0; i < MAX_RULES; i++) {
125433d6423SLionel Sambuc 		rule = &rules[i];
126433d6423SLionel Sambuc 
127433d6423SLionel Sambuc 		if (rule->num == 0) continue;
128433d6423SLionel Sambuc 
129433d6423SLionel Sambuc 		if (!rule_match(rule, pos, size, flag))
130433d6423SLionel Sambuc 			continue;
131433d6423SLionel Sambuc 
132433d6423SLionel Sambuc 		matches[nr_matches++] = rule;
133433d6423SLionel Sambuc 
134433d6423SLionel Sambuc 		/* If the rule has a limited lifetime, update it now. */
135433d6423SLionel Sambuc 		if (rule->count > 0) {
136433d6423SLionel Sambuc 			rule->count--;
137433d6423SLionel Sambuc 
138433d6423SLionel Sambuc 			/* Disable the rule from future matching. */
139433d6423SLionel Sambuc 			if (rule->count == 0)
140433d6423SLionel Sambuc 				rule->num = 0;
141433d6423SLionel Sambuc 		}
142433d6423SLionel Sambuc 
143433d6423SLionel Sambuc 		hooks |= action_mask(rule);
144433d6423SLionel Sambuc 	}
145433d6423SLionel Sambuc 
146433d6423SLionel Sambuc 	return hooks;
147433d6423SLionel Sambuc }
148433d6423SLionel Sambuc 
149433d6423SLionel Sambuc /*===========================================================================*
150433d6423SLionel Sambuc  *				rule_pre_hook				     *
151433d6423SLionel Sambuc  *===========================================================================*/
rule_pre_hook(iovec_t * iov,unsigned * count,size_t * size,u64_t * pos)152433d6423SLionel Sambuc void rule_pre_hook(iovec_t *iov, unsigned *count, size_t *size,
153433d6423SLionel Sambuc 	u64_t *pos)
154433d6423SLionel Sambuc {
155433d6423SLionel Sambuc 	int i;
156433d6423SLionel Sambuc 
157433d6423SLionel Sambuc 	for (i = 0; i < nr_matches; i++)
158433d6423SLionel Sambuc 		if (action_mask(matches[i]) & PRE_HOOK)
159433d6423SLionel Sambuc 			action_pre_hook(matches[i], iov, count, size, pos);
160433d6423SLionel Sambuc }
161433d6423SLionel Sambuc 
162433d6423SLionel Sambuc /*===========================================================================*
163433d6423SLionel Sambuc  *				rule_io_hook				     *
164433d6423SLionel Sambuc  *===========================================================================*/
rule_io_hook(char * buf,size_t size,u64_t pos,int flag)165433d6423SLionel Sambuc void rule_io_hook(char *buf, size_t size, u64_t pos, int flag)
166433d6423SLionel Sambuc {
167433d6423SLionel Sambuc 	int i;
168433d6423SLionel Sambuc 
169433d6423SLionel Sambuc 	for (i = 0; i < nr_matches; i++)
170433d6423SLionel Sambuc 		if (action_mask(matches[i]) & IO_HOOK)
171433d6423SLionel Sambuc 			action_io_hook(matches[i], buf, size, pos, flag);
172433d6423SLionel Sambuc }
173433d6423SLionel Sambuc 
174433d6423SLionel Sambuc /*===========================================================================*
175433d6423SLionel Sambuc  *				rule_post_hook				     *
176433d6423SLionel Sambuc  *===========================================================================*/
rule_post_hook(size_t osize,int * result)177433d6423SLionel Sambuc void rule_post_hook(size_t osize, int *result)
178433d6423SLionel Sambuc {
179433d6423SLionel Sambuc 	int i;
180433d6423SLionel Sambuc 
181433d6423SLionel Sambuc 	for (i = 0; i < nr_matches; i++)
182433d6423SLionel Sambuc 		if (action_mask(matches[i]) & POST_HOOK)
183433d6423SLionel Sambuc 			action_post_hook(matches[i], osize, result);
184433d6423SLionel Sambuc }
185