xref: /minix3/minix/drivers/storage/fbd/rule.c (revision 63ce03db6646a88deff65bad27b873bbfe71a4e1)
1 #include <minix/drivers.h>
2 #include <minix/ioctl.h>
3 #include <sys/ioc_fbd.h>
4 
5 #include "action.h"
6 #include "rule.h"
7 
8 static struct fbd_rule rules[MAX_RULES];
9 static struct fbd_rule *matches[MAX_RULES];
10 static int nr_matches;
11 
12 /*===========================================================================*
13  *				rule_ctl				     *
14  *===========================================================================*/
rule_ctl(unsigned long request,endpoint_t endpt,cp_grant_id_t grant)15 int rule_ctl(unsigned long request, endpoint_t endpt, cp_grant_id_t grant)
16 {
17 	/* Handle an I/O control request regarding rules. */
18 	fbd_rulenum_t i;
19 	int r;
20 
21 	/* Note that any of the safecopy calls may fail if the ioctl is
22 	 * improperly defined in userland; never panic if they fail!
23 	 */
24 	switch (request) {
25 	case FBDCADDRULE:
26 		/* Find a free rule slot. */
27 		for (i = 1; i <= MAX_RULES; i++)
28 			if (rules[i-1].num == 0)
29 				break;
30 
31 		if (i == MAX_RULES+1)
32 			return ENOMEM;
33 
34 		/* Copy in the rule. */
35 		if ((r = sys_safecopyfrom(endpt, grant, 0,
36 				(vir_bytes) &rules[i-1], sizeof(rules[0]))) != OK)
37 			return r;
38 
39 		/* Mark the rule as active, and return its number. */
40 		rules[i-1].num = i;
41 
42 		return i;
43 
44 	case FBDCDELRULE:
45 		/* Copy in the given rule number. */
46 		if ((r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &i,
47 				sizeof(i))) != OK)
48 			return r;
49 
50 		/* Fail if the given rule number is not valid or in use.
51 		 * Allow the caller to determine the maximum rule number.
52 		 */
53 		if (i <= 0 || i > MAX_RULES) return EINVAL;
54 
55 		if (rules[i-1].num != i) return ENOENT;
56 
57 		/* Mark the rule as not active. */
58 		rules[i-1].num = 0;
59 
60 		return OK;
61 
62 	case FBDCGETRULE:
63 		/* Copy in just the rule number from the given structure. */
64 		if ((r = sys_safecopyfrom(endpt, grant,
65 				offsetof(struct fbd_rule, num), (vir_bytes) &i,
66 				sizeof(i))) != OK)
67 			return r;
68 
69 		/* Fail if the given rule number is not valid or in use.
70 		 * Allow the caller to determine the maximum rule number.
71 		 */
72 		if (i <= 0 || i > MAX_RULES) return EINVAL;
73 
74 		if (rules[i-1].num != i) return ENOENT;
75 
76 		/* Copy out the entire rule as is. */
77 		return sys_safecopyto(endpt, grant, 0, (vir_bytes) &rules[i-1],
78 				sizeof(rules[0]));
79 
80 	default:
81 		return EINVAL;
82 	}
83 }
84 
85 /*===========================================================================*
86  *				rule_match				     *
87  *===========================================================================*/
rule_match(struct fbd_rule * rule,u64_t pos,size_t size,int flag)88 static int rule_match(struct fbd_rule *rule, u64_t pos, size_t size, int flag)
89 {
90 	/* Check whether the given rule matches the given parameters. As side
91 	 * effect, update counters in the rule as appropriate.
92 	 */
93 
94 	/* Ranges must overlap (start < pos+size && end > pos). */
95 	if (rule->start >= pos + size ||
96 			(rule->end != 0 && rule->end <= pos))
97 		return FALSE;
98 
99 	/* Flags must match. */
100 	if (!(rule->flags & flag)) return FALSE;
101 
102 	/* This is a match, but is it supposed to trigger yet? */
103 	if (rule->skip > 0) {
104 		rule->skip--;
105 
106 		return FALSE;
107 	}
108 
109 	return TRUE;
110 }
111 
112 /*===========================================================================*
113  *				rule_find				     *
114  *===========================================================================*/
rule_find(u64_t pos,size_t size,int flag)115 int rule_find(u64_t pos, size_t size, int flag)
116 {
117 	/* Find all matching rules, and return a hook mask. */
118 	struct fbd_rule *rule;
119 	int i, hooks;
120 
121 	nr_matches = 0;
122 	hooks = 0;
123 
124 	for (i = 0; i < MAX_RULES; i++) {
125 		rule = &rules[i];
126 
127 		if (rule->num == 0) continue;
128 
129 		if (!rule_match(rule, pos, size, flag))
130 			continue;
131 
132 		matches[nr_matches++] = rule;
133 
134 		/* If the rule has a limited lifetime, update it now. */
135 		if (rule->count > 0) {
136 			rule->count--;
137 
138 			/* Disable the rule from future matching. */
139 			if (rule->count == 0)
140 				rule->num = 0;
141 		}
142 
143 		hooks |= action_mask(rule);
144 	}
145 
146 	return hooks;
147 }
148 
149 /*===========================================================================*
150  *				rule_pre_hook				     *
151  *===========================================================================*/
rule_pre_hook(iovec_t * iov,unsigned * count,size_t * size,u64_t * pos)152 void rule_pre_hook(iovec_t *iov, unsigned *count, size_t *size,
153 	u64_t *pos)
154 {
155 	int i;
156 
157 	for (i = 0; i < nr_matches; i++)
158 		if (action_mask(matches[i]) & PRE_HOOK)
159 			action_pre_hook(matches[i], iov, count, size, pos);
160 }
161 
162 /*===========================================================================*
163  *				rule_io_hook				     *
164  *===========================================================================*/
rule_io_hook(char * buf,size_t size,u64_t pos,int flag)165 void rule_io_hook(char *buf, size_t size, u64_t pos, int flag)
166 {
167 	int i;
168 
169 	for (i = 0; i < nr_matches; i++)
170 		if (action_mask(matches[i]) & IO_HOOK)
171 			action_io_hook(matches[i], buf, size, pos, flag);
172 }
173 
174 /*===========================================================================*
175  *				rule_post_hook				     *
176  *===========================================================================*/
rule_post_hook(size_t osize,int * result)177 void rule_post_hook(size_t osize, int *result)
178 {
179 	int i;
180 
181 	for (i = 0; i < nr_matches; i++)
182 		if (action_mask(matches[i]) & POST_HOOK)
183 			action_post_hook(matches[i], osize, result);
184 }
185