Commit | Line | Data |
---|---|---|
f3e2d1ca KM |
1 | /* |
2 | * Copyright (c) 1982, 1986, 1989 Regents of the University of California. | |
3 | * All rights reserved. | |
4 | * | |
5 | * This code is derived from software contributed to Berkeley by | |
6 | * Scooter Morris at Genentech Inc. | |
7 | * | |
8 | * %sccs.include.redist.c% | |
9 | * | |
10 | * @(#)ufs_lockf.c 7.1 (Berkeley) %G% | |
11 | */ | |
12 | ||
13 | #include "param.h" | |
14 | #include "systm.h" | |
15 | #include "user.h" | |
16 | #include "kernel.h" | |
17 | #include "file.h" | |
18 | #include "proc.h" | |
19 | #include "socketvar.h" | |
20 | #include "socket.h" | |
21 | #include "vnode.h" | |
22 | #include "ioctl.h" | |
23 | #include "tty.h" | |
24 | #include "malloc.h" | |
25 | #include "fcntl.h" | |
26 | #include "../ufs/lockf.h" | |
27 | #include "../ufs/quota.h" | |
28 | #include "../ufs/inode.h" | |
29 | ||
30 | #ifdef LOCKF_DEBUG | |
31 | int lockf_debug = 0; | |
32 | #endif /* LOCKF_DEBUG */ | |
33 | ||
34 | /* | |
35 | * Common code for ufs byte range locking | |
36 | */ | |
37 | ||
38 | /* | |
39 | * Add a lock to the list. Upgrade or downgrade our locks, if | |
40 | * they conflict. | |
41 | */ | |
42 | struct lockf * | |
43 | lf_addlock(lock) | |
44 | register struct lockf *lock; | |
45 | { | |
46 | register struct lockf *lf = lock->lf_inode->i_lockf; | |
47 | struct lockf *lastlock = (struct lockf *)0; | |
48 | struct lockf *prev, *overlap, *ltmp; | |
49 | int ovcase; | |
50 | ||
51 | /* | |
52 | * First, see if we overlap with anything. | |
53 | */ | |
54 | ovcase = lf_findoverlap(lf, lock, &prev, &overlap); | |
55 | /* | |
56 | * Add the new lock | |
57 | */ | |
58 | if (prev != (struct lockf *)0) | |
59 | prev->lf_next = lock; | |
60 | else | |
61 | lock->lf_inode->i_lockf = lock; | |
62 | lock->lf_next = overlap; | |
63 | /* | |
64 | * Skip over locks owned by other processes. | |
65 | * Merge any locks that are owned by ourselves. | |
66 | */ | |
67 | for (;;) { | |
68 | for (;;) { | |
69 | /* | |
70 | * If no overlap, we are done. | |
71 | */ | |
72 | if (ovcase == 0) | |
73 | return; | |
74 | lf = overlap->lf_next; | |
75 | if (overlap->lf_id == lock->lf_id) | |
76 | break; | |
77 | /* | |
78 | * We overlap with another process. | |
79 | * If it is a block, panic. | |
80 | */ | |
81 | if (lock->lf_type == F_WRLCK || | |
82 | overlap->lf_type == F_WRLCK) | |
83 | panic("blocked in addlock"); | |
84 | ovcase = lf_findoverlap(lf, lock, &prev, &overlap); | |
85 | } | |
86 | /* | |
87 | * Five cases: | |
88 | * 1) overlap == lock | |
89 | * 2) overlap contains lock | |
90 | * 3) lock contains overlap | |
91 | * 4) overlap starts before lock | |
92 | * 5) overlap ends after lock | |
93 | */ | |
94 | switch (ovcase) { | |
95 | ||
96 | case 1: /* overlap == lock */ | |
97 | /* | |
98 | * Undo spurious addition of lock to list. | |
99 | */ | |
100 | if (prev != (struct lockf *)0) | |
101 | prev->lf_next = overlap; | |
102 | else | |
103 | lock->lf_inode->i_lockf = overlap; | |
104 | /* | |
105 | * If downgrading lock, others may be | |
106 | * able to acquire it. | |
107 | */ | |
108 | if (lock->lf_type == F_RDLCK && | |
109 | overlap->lf_type == F_WRLCK) | |
110 | lf_wakelock(overlap); | |
111 | overlap->lf_type = lock->lf_type; | |
112 | free(lock, M_LOCKF); | |
113 | return; | |
114 | ||
115 | case 2: /* overlap contains lock */ | |
116 | /* | |
117 | * Undo spurious addition of lock to list. | |
118 | */ | |
119 | if (prev != (struct lockf *)0) | |
120 | prev->lf_next = overlap; | |
121 | else | |
122 | lock->lf_inode->i_lockf = overlap; | |
123 | if (overlap->lf_type == lock->lf_type) { | |
124 | free(lock, M_LOCKF); | |
125 | return; | |
126 | } | |
127 | lf_split(overlap, lock); | |
128 | lf_wakelock(overlap); | |
129 | return; | |
130 | ||
131 | case 3: /* lock contains overlap */ | |
132 | /* | |
133 | * If downgrading lock, others may be able to | |
134 | * acquire it, otherwise take the list. | |
135 | */ | |
136 | if (lock->lf_type == F_RDLCK && | |
137 | overlap->lf_type == F_WRLCK) { | |
138 | lf_wakelock(overlap); | |
139 | } else { | |
140 | ltmp = lock->lf_block; | |
141 | lock->lf_block = overlap->lf_block; | |
142 | lf_addblock(lock, ltmp); | |
143 | } | |
144 | /* | |
145 | * Delete the overlap. | |
146 | */ | |
147 | lock->lf_next = overlap->lf_next; | |
148 | free(overlap, M_LOCKF); | |
149 | break; | |
150 | ||
151 | case 4: /* overlap starts before lock */ | |
152 | /* | |
153 | * Reverse lock and overlap on the list | |
154 | */ | |
155 | if (prev != (struct lockf *)0) | |
156 | prev->lf_next = overlap; | |
157 | else | |
158 | lock->lf_inode->i_lockf = overlap; | |
159 | lock->lf_next = overlap->lf_next; | |
160 | overlap->lf_next = lock; | |
161 | overlap->lf_end = lock->lf_start - 1; | |
162 | lf_wakelock(overlap); | |
163 | break; | |
164 | ||
165 | case 5: /* overlap ends after lock */ | |
166 | overlap->lf_start = lock->lf_end + 1; | |
167 | lf_wakelock(overlap); | |
168 | return; | |
169 | } | |
170 | ovcase = lf_findoverlap(lf, lock, &prev, &overlap); | |
171 | } | |
172 | /* NOTREACHED */ | |
173 | } | |
174 | ||
175 | /* | |
176 | * Walk the list of locks for an inode and | |
177 | * return the first blocking lock. | |
178 | */ | |
179 | struct lockf * | |
180 | lf_getblock(lock) | |
181 | register struct lockf *lock; | |
182 | { | |
183 | struct lockf *prev, *overlap, *lf = lock->lf_inode->i_lockf; | |
184 | int ovcase; | |
185 | ||
186 | while (ovcase = lf_findoverlap(lf, lock, &prev, &overlap)) { | |
187 | /* | |
188 | * We've found an overlap, see if it blocks us | |
189 | */ | |
190 | if ((lock->lf_type == F_WRLCK || overlap->lf_type == F_WRLCK) && | |
191 | overlap->lf_id != lock->lf_id) | |
192 | return (overlap); | |
193 | /* | |
194 | * Nope, point to the next one on the list and | |
195 | * see if it blocks us | |
196 | */ | |
197 | lf = overlap->lf_next; | |
198 | } | |
199 | return ((struct lockf *)0); | |
200 | } | |
201 | ||
202 | /* | |
203 | * Walk the list of locks for an inode to | |
204 | * find an overlapping lock (if any). | |
205 | * | |
206 | * NOTE: this returns only the FIRST overlapping lock. There | |
207 | * may be more than one. | |
208 | */ | |
209 | lf_findoverlap(list, lock, prev, overlap) | |
210 | struct lockf *list; | |
211 | struct lockf *lock; | |
212 | struct lockf **prev; | |
213 | struct lockf **overlap; | |
214 | { | |
215 | register struct lockf *lf = list; | |
216 | off_t start, end; | |
217 | ||
218 | *prev = (struct lockf *) 0; | |
219 | *overlap = lf; | |
220 | if ((lock == (struct lockf *)0) || (lf == (struct lockf *)0)) | |
221 | return (0); | |
222 | #ifdef LOCKF_DEBUG | |
223 | if (lockf_debug & 1) | |
224 | lf_print("lf_findoverlap: looking for overlap in", lock); | |
225 | #endif /* LOCKF_DEBUG */ | |
226 | start = lock->lf_start; | |
227 | end = lock->lf_end; | |
228 | while (lf != (struct lockf *)0) { | |
229 | #ifdef LOCKF_DEBUG | |
230 | if (lockf_debug & 1) | |
231 | lf_print("\tchecking", lf); | |
232 | #endif /* LOCKF_DEBUG */ | |
233 | /* | |
234 | * Have we gone far enough? | |
235 | */ | |
236 | if (end != -1 && lf->lf_start > end) | |
237 | #ifdef LOCKF_DEBUG | |
238 | if (lockf_debug & 1) | |
239 | print("no overlap\n"); | |
240 | #endif /* LOCKF_DEBUG */ | |
241 | return (0); | |
242 | /* | |
243 | * OK, find the overlap | |
244 | * | |
245 | * Five cases: | |
246 | * 1) overlap == lock | |
247 | * 2) overlap contains lock | |
248 | * 3) lock contains overlap | |
249 | * 4) overlap starts before lock | |
250 | * 5) overlap ends after lock | |
251 | */ | |
252 | if ((lf->lf_start == start) && (lf->lf_end == end)) { | |
253 | /* Case 1 */ | |
254 | #ifdef LOCKF_DEBUG | |
255 | if (lockf_debug & 1) | |
256 | printf("overlap == lock\n"); break; | |
257 | #endif /* LOCKF_DEBUG */ | |
258 | return (1); | |
259 | } else if ((lf->lf_start <= start) && | |
260 | (end != -1) && | |
261 | ((lf->lf_end >= end) || (lf->lf_end == -1))) { | |
262 | /* Case 2 */ | |
263 | #ifdef LOCKF_DEBUG | |
264 | if (lockf_debug & 1) | |
265 | printf("overlap contains lock\n"); break; | |
266 | #endif /* LOCKF_DEBUG */ | |
267 | return (2); | |
268 | } else if ((start <= lf->lf_start) && | |
269 | (lf->lf_end != -1) && | |
270 | ((end == -1) || (end >= lf->lf_end))) { | |
271 | /* Case 3 */ | |
272 | #ifdef LOCKF_DEBUG | |
273 | if (lockf_debug & 1) | |
274 | printf("lock contains overlap\n"); break; | |
275 | #endif /* LOCKF_DEBUG */ | |
276 | return (3); | |
277 | } else if ((lf->lf_start < start) && | |
278 | ((lf->lf_end >= start) || (lf->lf_end == -1))) { | |
279 | /* Case 4 */ | |
280 | #ifdef LOCKF_DEBUG | |
281 | if (lockf_debug & 1) | |
282 | printf("overlap starts before lock\n"); break; | |
283 | #endif /* LOCKF_DEBUG */ | |
284 | return (4); | |
285 | } else if ((lf->lf_start > start) && | |
286 | (end != -1) && | |
287 | ((lf->lf_end > end) || (lf->lf_end == -1))) { | |
288 | /* Case 5 */ | |
289 | #ifdef LOCKF_DEBUG | |
290 | if (lockf_debug & 1) | |
291 | printf("overlap ends after lock\n"); break; | |
292 | #endif /* LOCKF_DEBUG */ | |
293 | return (5); | |
294 | } | |
295 | *prev = lf; | |
296 | *overlap = lf = lf->lf_next; | |
297 | } | |
298 | /* No overlap */ | |
299 | #ifdef LOCKF_DEBUG | |
300 | if (lockf_debug & 1) | |
301 | print("no overlap\n"); | |
302 | #endif /* LOCKF_DEBUG */ | |
303 | return (0); | |
304 | } | |
305 | ||
306 | /* | |
307 | * Add a lock to the end of the blocked list. | |
308 | */ | |
309 | lf_addblock(lock, blocked) | |
310 | struct lockf *lock; | |
311 | struct lockf *blocked; | |
312 | { | |
313 | register struct lockf *lf; | |
314 | ||
315 | if (lock == (struct lockf *)0) | |
316 | return; | |
317 | if ((lf = lock->lf_block) == (struct lockf *)0) { | |
318 | lock->lf_block = blocked; | |
319 | return; | |
320 | } | |
321 | while (lf->lf_block != (struct lockf *)0) | |
322 | lf = lf->lf_block; | |
323 | lf->lf_block = blocked; | |
324 | return; | |
325 | } | |
326 | ||
327 | /* | |
328 | * Combine two locks into a single lock | |
329 | */ | |
330 | lf_combine(lock1, lock2) | |
331 | struct lockf *lock1; | |
332 | struct lockf *lock2; | |
333 | { | |
334 | #ifdef LOCKF_DEBUG | |
335 | if (lockf_debug & 1) { | |
336 | lf_print("lf_combine", lock1); | |
337 | lf_print("combining with", lock2); | |
338 | } | |
339 | #endif /* LOCKF_DEBUG */ | |
340 | /* | |
341 | * Sanity check | |
342 | */ | |
343 | if ( (lock1->lf_id != lock2->lf_id) || | |
344 | (lock1->lf_type != lock2->lf_type) ) | |
345 | panic("lf_combine"); | |
346 | if (lock1->lf_start > lock2->lf_start) | |
347 | lock1->lf_start = lock2->lf_start; | |
348 | if ((lock1->lf_end == -1) || (lock2->lf_end == -1)) | |
349 | lock1->lf_end == -1; | |
350 | else if (lock1->lf_end < lock2->lf_end) | |
351 | lock1->lf_end = lock2->lf_end; | |
352 | /* Add the block lists together */ | |
353 | lf_addblock(lock1, lock2->lf_block); | |
354 | free(lock2, M_LOCKF); | |
355 | } | |
356 | ||
357 | /* | |
358 | * Split a lock and a contained region into | |
359 | * three locks | |
360 | */ | |
361 | lf_split(lock1, lock2) | |
362 | register struct lockf *lock1; | |
363 | register struct lockf *lock2; | |
364 | { | |
365 | register struct lockf *splitlock; | |
366 | ||
367 | #ifdef LOCKF_DEBUG | |
368 | if (lockf_debug & 1) { | |
369 | lf_print("lf_split", lock1); | |
370 | lf_print("splitting from", lock2); | |
371 | } | |
372 | #endif /* LOCKF_DEBUG */ | |
373 | /* | |
374 | * Make a new lock consisting of the last part of | |
375 | * the encompassing lock | |
376 | */ | |
377 | MALLOC(splitlock, struct lockf *, sizeof *splitlock, M_LOCKF, M_WAITOK); | |
378 | bcopy((caddr_t)lock1, (caddr_t)splitlock, sizeof *splitlock); | |
379 | splitlock->lf_end = lock2->lf_end + 1; | |
380 | lock1->lf_end = lock2->lf_start - 1; | |
381 | /* | |
382 | * OK, now link it in | |
383 | */ | |
384 | splitlock->lf_next = lock1->lf_next; | |
385 | lock2->lf_next = splitlock; | |
386 | lock1->lf_next = lock2; | |
387 | } | |
388 | ||
389 | /* | |
390 | * lf_remove: remove a lock (or a portion of a lock) from the lock list | |
391 | */ | |
392 | struct lockf * | |
393 | lf_remove(lfun) | |
394 | register struct lockf *lfun; | |
395 | { | |
396 | struct inode *ip = lfun->lf_inode; | |
397 | register struct lockf *lf = ip->i_lockf; | |
398 | struct lockf *blocklist = (struct lockf *)0; | |
399 | struct lockf *overlap, *prev; | |
400 | int ovcase; | |
401 | ||
402 | if (lf == (struct lockf *)0) | |
403 | return((struct lockf *)0); | |
404 | #ifdef LOCKF_DEBUG | |
405 | if (lockf_debug & 1) | |
406 | printf("lf_remove", lfun); | |
407 | #endif LOCKF_DEBUG | |
408 | while (ovcase = lf_findoverlap(lf, lfun, &prev, &overlap)) { | |
409 | /* | |
410 | * Point to the next element for the loop | |
411 | */ | |
412 | lf = overlap->lf_next; | |
413 | /* | |
414 | * Check to see if it is our lock. | |
415 | */ | |
416 | if (lfun->lf_id == overlap->lf_id) { | |
417 | /* | |
418 | * Save the list of locks to be retried. | |
419 | */ | |
420 | if (blocklist == (struct lockf *)0) | |
421 | blocklist = overlap->lf_block; | |
422 | else | |
423 | lf_addblock(blocklist, overlap->lf_block); | |
424 | ||
425 | switch (ovcase) { | |
426 | ||
427 | case 1: /* overlap == lock */ | |
428 | if (prev != (struct lockf *)0) | |
429 | prev->lf_next = overlap->lf_next; | |
430 | else | |
431 | ip->i_lockf = overlap->lf_next; | |
432 | free(overlap, M_LOCKF); | |
433 | return (blocklist); | |
434 | ||
435 | case 2: /* overlap contains lock: split it */ | |
436 | lf_split(overlap, lfun); | |
437 | overlap->lf_next = lfun->lf_next; | |
438 | return (blocklist); | |
439 | ||
440 | case 3: /* lock contains overlap */ | |
441 | if (prev != (struct lockf *)0) | |
442 | prev->lf_next = overlap->lf_next; | |
443 | else | |
444 | ip->i_lockf = overlap->lf_next; | |
445 | free(overlap, M_LOCKF); | |
446 | break; | |
447 | ||
448 | case 4: /* overlap starts before lock */ | |
449 | overlap->lf_end = lfun->lf_start - 1; | |
450 | break; | |
451 | ||
452 | case 5: /* overlap ends after lock */ | |
453 | overlap->lf_start = lfun->lf_end + 1; | |
454 | return (blocklist); | |
455 | } | |
456 | } | |
457 | } | |
458 | return (blocklist); | |
459 | } | |
460 | ||
461 | /* | |
462 | * Wakeup a blocklist | |
463 | */ | |
464 | lf_wakelock(blocklist) | |
465 | register struct lockf *blocklist; | |
466 | { | |
467 | register struct lockf *wakelock; | |
468 | ||
469 | while (blocklist != (struct lockf *)0) { | |
470 | wakelock = blocklist; | |
471 | blocklist = blocklist->lf_block; | |
472 | wakelock->lf_block = (struct lockf *)0; | |
473 | wakelock->lf_next = (struct lockf *)0; | |
474 | #ifdef LOCKF_DEBUG | |
475 | if (lockf_debug & 4) | |
476 | lf_print("ufs_wakelock: awakening", wakelock); | |
477 | #endif /* LOCKF_DEBUG */ | |
478 | wakeup((caddr_t)wakelock); | |
479 | } | |
480 | } | |
481 | ||
482 | #ifdef LOCKF_DEBUG | |
483 | /* | |
484 | * Print out a lock. | |
485 | */ | |
486 | lf_print(tag, lock) | |
487 | char *tag; | |
488 | register lockf *lock; | |
489 | { | |
490 | ||
491 | printf("%s: lock 0x%X for proc %d in ino %d on dev <%d, %d>, ", | |
492 | tag, lock, lock->lp_proc->p_pid, lock->lf_inode->i_number, | |
493 | major(lock->lf_inode->i_dev), minor(lock->lf_inode->i_dev)); | |
494 | printf("type %s, start %d, end %d\n", | |
495 | lock->lf_type == F_RDLCK ? "shared" : | |
496 | lock->lf_type == F_WRLCK ? "exclusive" : | |
497 | "unknown", start, end); | |
498 | } | |
499 | #endif /* LOCKF_DEBUG */ |