This source file includes following definitions.
- acquire_lock
- free_lock
- acquire_lock_interlocked
- free_lock_interlocked
- sema_init
- sema_get
- sema_release
- softdep_free
- softdep_freequeue_add
- softdep_freequeue_process
- worklist_insert
- worklist_remove
- workitem_free
- add_to_worklist
- softdep_process_worklist
- process_worklist_item
- softdep_move_dependencies
- softdep_flushworklist
- softdep_flushfiles
- LIST_HEAD
- LIST_HEAD
- LIST_HEAD
- softdep_initialize
- softdep_mount
- softdep_setup_inomapdep
- softdep_setup_blkmapdep
- bmsafemap_lookup
- softdep_setup_allocdirect
- allocdirect_merge
- newfreefrag
- handle_workitem_freefrag
- newallocindir
- softdep_setup_allocindir_page
- softdep_setup_allocindir_meta
- setup_allocindir_phase2
- softdep_setup_freeblocks
- deallocate_dependencies
- free_allocdirect
- free_newdirblk
- softdep_freefile
- check_inode_unwritten
- free_inodedep
- handle_workitem_freeblocks
- indir_trunc
- free_allocindir
- softdep_setup_directory_add
- softdep_change_directoryentry_offset
- free_diradd
- softdep_setup_remove
- newdirrem
- softdep_setup_directory_change
- softdep_change_linkcnt
- handle_workitem_remove
- handle_workitem_freefile
- softdep_disk_io_initiation
- initiate_write_filepage
- initiate_write_inodeblock_ufs1
- initiate_write_inodeblock_ufs2
- softdep_disk_write_complete
- handle_allocdirect_partdone
- handle_allocindir_partdone
- handle_written_inodeblock
- diradd_inode_written
- handle_written_mkdir
- handle_written_filepage
- softdep_load_inodeblock
- softdep_update_inodeblock
- merge_inode_lists
- softdep_fsync
- softdep_fsync_mountdev
- softdep_sync_metadata
- flush_inodedep_deps
- flush_pagedep_deps
- softdep_slowdown
- request_cleanup
- pause_timer
- clear_remove
- clear_inodedeps
- softdep_count_dependencies
- getdirtybuf
- drain_output
- softdep_deallocate_dependencies
- softdep_error
- softdep_print
- worklist_print
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 #include <sys/param.h>
45 #include <sys/buf.h>
46 #include <sys/kernel.h>
47 #include <sys/malloc.h>
48 #include <sys/mount.h>
49 #include <sys/proc.h>
50 #include <sys/pool.h>
51 #include <sys/syslog.h>
52 #include <sys/systm.h>
53 #include <sys/vnode.h>
54 #include <miscfs/specfs/specdev.h>
55 #include <ufs/ufs/dir.h>
56 #include <ufs/ufs/quota.h>
57 #include <ufs/ufs/inode.h>
58 #include <ufs/ufs/ufsmount.h>
59 #include <ufs/ffs/fs.h>
60 #include <ufs/ffs/softdep.h>
61 #include <ufs/ffs/ffs_extern.h>
62 #include <ufs/ufs/ufs_extern.h>
63
64 #define STATIC
65
66
67
68
69 #define D_PAGEDEP 0
70 #define D_INODEDEP 1
71 #define D_NEWBLK 2
72 #define D_BMSAFEMAP 3
73 #define D_ALLOCDIRECT 4
74 #define D_INDIRDEP 5
75 #define D_ALLOCINDIR 6
76 #define D_FREEFRAG 7
77 #define D_FREEBLKS 8
78 #define D_FREEFILE 9
79 #define D_DIRADD 10
80 #define D_MKDIR 11
81 #define D_DIRREM 12
82 #define D_NEWDIRBLK 13
83 #define D_LAST 13
84
85
86
87 const char *softdep_typenames[] = {
88 "pagedep",
89 "inodedep",
90 "newblk",
91 "bmsafemap",
92 "allocdirect",
93 "indirdep",
94 "allocindir",
95 "freefrag",
96 "freeblks",
97 "freefile",
98 "diradd",
99 "mkdir",
100 "dirrem",
101 "newdirblk",
102 };
103 #define TYPENAME(type) \
104 ((unsigned)(type) <= D_LAST ? softdep_typenames[type] : "???")
105
106
107
108 #define CURPROC curproc
109
110
111
112
113
114
115
116 STATIC void softdep_error(char *, int);
117 STATIC void drain_output(struct vnode *, int);
118 STATIC int getdirtybuf(struct buf *, int);
119 STATIC void clear_remove(struct proc *);
120 STATIC void clear_inodedeps(struct proc *);
121 STATIC int flush_pagedep_deps(struct vnode *, struct mount *,
122 struct diraddhd *);
123 STATIC int flush_inodedep_deps(struct fs *, ino_t);
124 STATIC int handle_written_filepage(struct pagedep *, struct buf *);
125 STATIC void diradd_inode_written(struct diradd *, struct inodedep *);
126 STATIC int handle_written_inodeblock(struct inodedep *, struct buf *);
127 STATIC void handle_allocdirect_partdone(struct allocdirect *);
128 STATIC void handle_allocindir_partdone(struct allocindir *);
129 STATIC void initiate_write_filepage(struct pagedep *, struct buf *);
130 STATIC void handle_written_mkdir(struct mkdir *, int);
131 STATIC void initiate_write_inodeblock_ufs1(struct inodedep *, struct buf *);
132 #ifdef FFS2
133 STATIC void initiate_write_inodeblock_ufs2(struct inodedep *, struct buf *);
134 #endif
135 STATIC void handle_workitem_freefile(struct freefile *);
136 STATIC void handle_workitem_remove(struct dirrem *);
137 STATIC struct dirrem *newdirrem(struct buf *, struct inode *,
138 struct inode *, int, struct dirrem **);
139 STATIC void free_diradd(struct diradd *);
140 STATIC void free_allocindir(struct allocindir *, struct inodedep *);
141 STATIC void free_newdirblk(struct newdirblk *);
142 STATIC int indir_trunc(struct inode *, daddr_t, int, daddr64_t, long *);
143 STATIC void deallocate_dependencies(struct buf *, struct inodedep *);
144 STATIC void free_allocdirect(struct allocdirectlst *,
145 struct allocdirect *, int);
146 STATIC int check_inode_unwritten(struct inodedep *);
147 STATIC int free_inodedep(struct inodedep *);
148 STATIC void handle_workitem_freeblocks(struct freeblks *);
149 STATIC void merge_inode_lists(struct inodedep *);
150 STATIC void setup_allocindir_phase2(struct buf *, struct inode *,
151 struct allocindir *);
152 STATIC struct allocindir *newallocindir(struct inode *, int, daddr_t,
153 daddr_t);
154 STATIC void handle_workitem_freefrag(struct freefrag *);
155 STATIC struct freefrag *newfreefrag(struct inode *, daddr_t, long);
156 STATIC void allocdirect_merge(struct allocdirectlst *,
157 struct allocdirect *, struct allocdirect *);
158 STATIC struct bmsafemap *bmsafemap_lookup(struct buf *);
159 STATIC int newblk_lookup(struct fs *, daddr_t, int,
160 struct newblk **);
161 STATIC int inodedep_lookup(struct fs *, ino_t, int, struct inodedep **);
162 STATIC int pagedep_lookup(struct inode *, daddr64_t, int, struct pagedep **);
163 STATIC void pause_timer(void *);
164 STATIC int request_cleanup(int, int);
165 STATIC int process_worklist_item(struct mount *, int);
166 STATIC void add_to_worklist(struct worklist *);
167
168
169
170
171 void softdep_disk_io_initiation(struct buf *);
172 void softdep_disk_write_complete(struct buf *);
173 void softdep_deallocate_dependencies(struct buf *);
174 void softdep_move_dependencies(struct buf *, struct buf *);
175 int softdep_count_dependencies(struct buf *bp, int, int);
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192 #ifndef DEBUG
193 STATIC struct lockit {
194 int lkt_spl;
195 } lk = { 0 };
196 #define ACQUIRE_LOCK(lk) (lk)->lkt_spl = splbio()
197 #define FREE_LOCK(lk) splx((lk)->lkt_spl)
198 #define ACQUIRE_LOCK_INTERLOCKED(lk,s) (lk)->lkt_spl = (s)
199 #define FREE_LOCK_INTERLOCKED(lk) ((lk)->lkt_spl)
200
201 #else
202 STATIC struct lockit {
203 int lkt_spl;
204 pid_t lkt_held;
205 int lkt_line;
206 } lk = { 0, -1 };
207 STATIC int lockcnt;
208
209 STATIC void acquire_lock(struct lockit *, int);
210 STATIC void free_lock(struct lockit *, int);
211 STATIC void acquire_lock_interlocked(struct lockit *, int, int);
212 STATIC int free_lock_interlocked(struct lockit *, int);
213
214 #define ACQUIRE_LOCK(lk) acquire_lock(lk, __LINE__)
215 #define FREE_LOCK(lk) free_lock(lk, __LINE__)
216 #define ACQUIRE_LOCK_INTERLOCKED(lk,s) acquire_lock_interlocked(lk, (s), __LINE__)
217 #define FREE_LOCK_INTERLOCKED(lk) free_lock_interlocked(lk, __LINE__)
218
219 STATIC void
220 acquire_lock(lk, line)
221 struct lockit *lk;
222 int line;
223 {
224 pid_t holder;
225 int original_line;
226
227 if (lk->lkt_held != -1) {
228 holder = lk->lkt_held;
229 original_line = lk->lkt_line;
230 FREE_LOCK(lk);
231 if (holder == CURPROC->p_pid)
232 panic("softdep_lock: locking against myself, acquired at line %d, relocked at line %d", original_line, line);
233 else
234 panic("softdep_lock: lock held by %d, acquired at line %d, relocked at line %d", holder, original_line, line);
235 }
236 lk->lkt_spl = splbio();
237 lk->lkt_held = CURPROC->p_pid;
238 lk->lkt_line = line;
239 lockcnt++;
240 }
241
242 STATIC void
243 free_lock(lk, line)
244 struct lockit *lk;
245 int line;
246 {
247
248 if (lk->lkt_held == -1)
249 panic("softdep_unlock: lock not held at line %d", line);
250 lk->lkt_held = -1;
251 splx(lk->lkt_spl);
252 }
253
254 STATIC void
255 acquire_lock_interlocked(lk, s, line)
256 struct lockit *lk;
257 int s;
258 int line;
259 {
260 pid_t holder;
261 int original_line;
262
263 if (lk->lkt_held != -1) {
264 holder = lk->lkt_held;
265 original_line = lk->lkt_line;
266 FREE_LOCK_INTERLOCKED(lk);
267 if (holder == CURPROC->p_pid)
268 panic("softdep_lock: locking against myself, acquired at line %d, relocked at line %d", original_line, line);
269 else
270 panic("softdep_lock: lock held by %d, acquired at line %d, relocked at line %d", holder, original_line, line);
271 }
272 lk->lkt_held = CURPROC->p_pid;
273 lk->lkt_line = line;
274 lk->lkt_spl = s;
275 lockcnt++;
276 }
277
278 STATIC int
279 free_lock_interlocked(lk, line)
280 struct lockit *lk;
281 int line;
282 {
283
284 if (lk->lkt_held == -1)
285 panic("softdep_unlock_interlocked: lock not held at line %d", line);
286 lk->lkt_held = -1;
287
288 return (lk->lkt_spl);
289 }
290 #endif
291
292
293
294
295 struct sema {
296 int value;
297 pid_t holder;
298 char *name;
299 int prio;
300 int timo;
301 };
302 STATIC void sema_init(struct sema *, char *, int, int);
303 STATIC int sema_get(struct sema *, struct lockit *);
304 STATIC void sema_release(struct sema *);
305
306 STATIC void
307 sema_init(semap, name, prio, timo)
308 struct sema *semap;
309 char *name;
310 int prio, timo;
311 {
312
313 semap->holder = -1;
314 semap->value = 0;
315 semap->name = name;
316 semap->prio = prio;
317 semap->timo = timo;
318 }
319
320 STATIC int
321 sema_get(semap, interlock)
322 struct sema *semap;
323 struct lockit *interlock;
324 {
325 int s;
326
327 if (semap->value++ > 0) {
328 if (interlock != NULL)
329 s = FREE_LOCK_INTERLOCKED(interlock);
330 tsleep((caddr_t)semap, semap->prio, semap->name, semap->timo);
331 if (interlock != NULL) {
332 ACQUIRE_LOCK_INTERLOCKED(interlock, s);
333 FREE_LOCK(interlock);
334 }
335 return (0);
336 }
337 semap->holder = CURPROC->p_pid;
338 if (interlock != NULL)
339 FREE_LOCK(interlock);
340 return (1);
341 }
342
343 STATIC void
344 sema_release(semap)
345 struct sema *semap;
346 {
347
348 if (semap->value <= 0 || semap->holder != CURPROC->p_pid) {
349 #ifdef DEBUG
350 if (lk.lkt_held != -1)
351 FREE_LOCK(&lk);
352 #endif
353 panic("sema_release: not held");
354 }
355 if (--semap->value > 0) {
356 semap->value = 0;
357 wakeup(semap);
358 }
359 semap->holder = -1;
360 }
361
362
363
364
365 STATIC struct pool pagedep_pool;
366 STATIC struct pool inodedep_pool;
367 STATIC struct pool newblk_pool;
368 STATIC struct pool bmsafemap_pool;
369 STATIC struct pool allocdirect_pool;
370 STATIC struct pool indirdep_pool;
371 STATIC struct pool allocindir_pool;
372 STATIC struct pool freefrag_pool;
373 STATIC struct pool freeblks_pool;
374 STATIC struct pool freefile_pool;
375 STATIC struct pool diradd_pool;
376 STATIC struct pool mkdir_pool;
377 STATIC struct pool dirrem_pool;
378 STATIC struct pool newdirblk_pool;
379
380 static __inline void
381 softdep_free(struct worklist *item, int type)
382 {
383
384 switch (type) {
385 case D_PAGEDEP:
386 pool_put(&pagedep_pool, item);
387 break;
388
389 case D_INODEDEP:
390 pool_put(&inodedep_pool, item);
391 break;
392
393 case D_BMSAFEMAP:
394 pool_put(&bmsafemap_pool, item);
395 break;
396
397 case D_ALLOCDIRECT:
398 pool_put(&allocdirect_pool, item);
399 break;
400
401 case D_INDIRDEP:
402 pool_put(&indirdep_pool, item);
403 break;
404
405 case D_ALLOCINDIR:
406 pool_put(&allocindir_pool, item);
407 break;
408
409 case D_FREEFRAG:
410 pool_put(&freefrag_pool, item);
411 break;
412
413 case D_FREEBLKS:
414 pool_put(&freeblks_pool, item);
415 break;
416
417 case D_FREEFILE:
418 pool_put(&freefile_pool, item);
419 break;
420
421 case D_DIRADD:
422 pool_put(&diradd_pool, item);
423 break;
424
425 case D_MKDIR:
426 pool_put(&mkdir_pool, item);
427 break;
428
429 case D_DIRREM:
430 pool_put(&dirrem_pool, item);
431 break;
432
433 case D_NEWDIRBLK:
434 pool_put(&newdirblk_pool, item);
435 break;
436
437 default:
438 #ifdef DEBUG
439 if (lk.lkt_held != -1)
440 FREE_LOCK(&lk);
441 #endif
442 panic("softdep_free: unknown type %d", type);
443 }
444 }
445
446 struct workhead softdep_freequeue;
447
448 static __inline void
449 softdep_freequeue_add(struct worklist *item)
450 {
451 int s;
452
453 s = splbio();
454 LIST_INSERT_HEAD(&softdep_freequeue, item, wk_list);
455 splx(s);
456 }
457
458 static __inline void
459 softdep_freequeue_process(void)
460 {
461 struct worklist *wk;
462
463 splassert(IPL_BIO);
464
465 while ((wk = LIST_FIRST(&softdep_freequeue)) != NULL) {
466 LIST_REMOVE(wk, wk_list);
467 FREE_LOCK(&lk);
468 softdep_free(wk, wk->wk_type);
469 ACQUIRE_LOCK(&lk);
470 }
471 }
472
473
474
475
476
477 #ifndef DEBUG
478 #define WORKLIST_INSERT(head, item) do { \
479 (item)->wk_state |= ONWORKLIST; \
480 LIST_INSERT_HEAD(head, item, wk_list); \
481 } while (0)
482 #define WORKLIST_REMOVE(item) do { \
483 (item)->wk_state &= ~ONWORKLIST; \
484 LIST_REMOVE(item, wk_list); \
485 } while (0)
486 #define WORKITEM_FREE(item, type) softdep_freequeue_add((struct worklist *)item)
487
488 #else
489 STATIC void worklist_insert(struct workhead *, struct worklist *);
490 STATIC void worklist_remove(struct worklist *);
491 STATIC void workitem_free(struct worklist *);
492
493 #define WORKLIST_INSERT(head, item) worklist_insert(head, item)
494 #define WORKLIST_REMOVE(item) worklist_remove(item)
495 #define WORKITEM_FREE(item, type) workitem_free((struct worklist *)item)
496
497 STATIC void
498 worklist_insert(head, item)
499 struct workhead *head;
500 struct worklist *item;
501 {
502
503 if (lk.lkt_held == -1)
504 panic("worklist_insert: lock not held");
505 if (item->wk_state & ONWORKLIST) {
506 FREE_LOCK(&lk);
507 panic("worklist_insert: already on list");
508 }
509 item->wk_state |= ONWORKLIST;
510 LIST_INSERT_HEAD(head, item, wk_list);
511 }
512
513 STATIC void
514 worklist_remove(item)
515 struct worklist *item;
516 {
517
518 if (lk.lkt_held == -1)
519 panic("worklist_remove: lock not held");
520 if ((item->wk_state & ONWORKLIST) == 0) {
521 FREE_LOCK(&lk);
522 panic("worklist_remove: not on list");
523 }
524 item->wk_state &= ~ONWORKLIST;
525 LIST_REMOVE(item, wk_list);
526 }
527
528 STATIC void
529 workitem_free(item)
530 struct worklist *item;
531 {
532
533 if (item->wk_state & ONWORKLIST) {
534 if (lk.lkt_held != -1)
535 FREE_LOCK(&lk);
536 panic("workitem_free: still on list");
537 }
538 softdep_freequeue_add(item);
539 }
540 #endif
541
542
543
544
545 STATIC struct workhead softdep_workitem_pending;
546 STATIC struct worklist *worklist_tail;
547 STATIC int num_on_worklist;
548 STATIC int softdep_worklist_busy;
549 STATIC int softdep_worklist_req;
550 STATIC int max_softdeps;
551 STATIC int tickdelay = 2;
552 STATIC int proc_waiting;
553 STATIC int *stat_countp;
554 STATIC struct timeout proc_waiting_timeout;
555 STATIC struct proc *filesys_syncer;
556 STATIC int req_clear_inodedeps;
557 #define FLUSH_INODES 1
558 STATIC int req_clear_remove;
559 #define FLUSH_REMOVE 2
560
561
562
563 STATIC int stat_worklist_push;
564 STATIC int stat_blk_limit_push;
565 STATIC int stat_ino_limit_push;
566 STATIC int stat_blk_limit_hit;
567 STATIC int stat_ino_limit_hit;
568 STATIC int stat_sync_limit_hit;
569 STATIC int stat_indir_blk_ptrs;
570 STATIC int stat_inode_bitmap;
571 STATIC int stat_direct_blk_ptrs;
572 STATIC int stat_dir_entry;
573
574
575
576
577
578
579
580
581 STATIC void
582 add_to_worklist(wk)
583 struct worklist *wk;
584 {
585
586 if (wk->wk_state & ONWORKLIST) {
587 #ifdef DEBUG
588 if (lk.lkt_held != -1)
589 FREE_LOCK(&lk);
590 #endif
591 panic("add_to_worklist: already on list");
592 }
593 wk->wk_state |= ONWORKLIST;
594 if (LIST_FIRST(&softdep_workitem_pending) == NULL)
595 LIST_INSERT_HEAD(&softdep_workitem_pending, wk, wk_list);
596 else
597 LIST_INSERT_AFTER(worklist_tail, wk, wk_list);
598 worklist_tail = wk;
599 num_on_worklist += 1;
600 }
601
602
603
604
605
606
607
608
609
610
611 int
612 softdep_process_worklist(matchmnt)
613 struct mount *matchmnt;
614 {
615 struct proc *p = CURPROC;
616 int matchcnt, loopcount;
617 struct timeval starttime;
618
619
620
621
622 ACQUIRE_LOCK(&lk);
623 softdep_freequeue_process();
624 FREE_LOCK(&lk);
625
626
627
628
629
630
631
632
633 filesys_syncer = syncerproc;
634 matchcnt = 0;
635
636
637
638
639
640
641
642 if (matchmnt == NULL) {
643 if (softdep_worklist_busy < 0)
644 return(-1);
645 softdep_worklist_busy += 1;
646 }
647
648
649
650
651 if (req_clear_inodedeps) {
652 clear_inodedeps(p);
653 req_clear_inodedeps -= 1;
654 wakeup_one(&proc_waiting);
655 }
656 if (req_clear_remove) {
657 clear_remove(p);
658 req_clear_remove -= 1;
659 wakeup_one(&proc_waiting);
660 }
661 loopcount = 1;
662 getmicrouptime(&starttime);
663 while (num_on_worklist > 0) {
664 matchcnt += process_worklist_item(matchmnt, 0);
665
666
667
668
669
670 if (softdep_worklist_req && matchmnt == NULL) {
671 matchcnt = -1;
672 break;
673 }
674
675
676
677
678 if (req_clear_inodedeps) {
679 clear_inodedeps(p);
680 req_clear_inodedeps -= 1;
681 wakeup_one(&proc_waiting);
682 }
683 if (req_clear_remove) {
684 clear_remove(p);
685 req_clear_remove -= 1;
686 wakeup_one(&proc_waiting);
687 }
688
689
690
691
692 #if 0
693 if (loopcount++ % 128 == 0)
694 bwillwrite();
695 #endif
696
697
698
699
700
701 {
702 struct timeval diff;
703 struct timeval tv;
704
705 getmicrouptime(&tv);
706 timersub(&tv, &starttime, &diff);
707 if (diff.tv_sec != 0 && matchmnt == NULL) {
708 matchcnt = -1;
709 break;
710 }
711 }
712
713
714
715
716 ACQUIRE_LOCK(&lk);
717 softdep_freequeue_process();
718 FREE_LOCK(&lk);
719 }
720 if (matchmnt == NULL) {
721 softdep_worklist_busy -= 1;
722 if (softdep_worklist_req && softdep_worklist_busy == 0)
723 wakeup(&softdep_worklist_req);
724 }
725 return (matchcnt);
726 }
727
728
729
730
731 STATIC int
732 process_worklist_item(matchmnt, flags)
733 struct mount *matchmnt;
734 int flags;
735 {
736 struct worklist *wk, *wkend;
737 struct dirrem *dirrem;
738 struct mount *mp;
739 struct vnode *vp;
740 int matchcnt = 0;
741
742 ACQUIRE_LOCK(&lk);
743
744
745
746
747
748
749 LIST_FOREACH(wk, &softdep_workitem_pending, wk_list) {
750 if ((flags & LK_NOWAIT) == 0 || wk->wk_type != D_DIRREM)
751 break;
752 dirrem = WK_DIRREM(wk);
753 vp = ufs_ihashlookup(VFSTOUFS(dirrem->dm_mnt)->um_dev,
754 dirrem->dm_oldinum);
755 if (vp == NULL || !VOP_ISLOCKED(vp))
756 break;
757 }
758 if (wk == 0) {
759 FREE_LOCK(&lk);
760 return (0);
761 }
762
763
764
765
766
767
768
769 WORKLIST_REMOVE(wk);
770 if (wk == worklist_tail) {
771 LIST_FOREACH(wkend, &softdep_workitem_pending, wk_list)
772 if (LIST_NEXT(wkend, wk_list) == NULL)
773 break;
774 worklist_tail = wkend;
775 }
776 num_on_worklist -= 1;
777 FREE_LOCK(&lk);
778 switch (wk->wk_type) {
779
780 case D_DIRREM:
781
782 mp = WK_DIRREM(wk)->dm_mnt;
783 #if 0
784 if (vn_write_suspend_wait(NULL, mp, V_NOWAIT))
785 panic("%s: dirrem on suspended filesystem",
786 "process_worklist_item");
787 #endif
788 if (mp == matchmnt)
789 matchcnt += 1;
790 handle_workitem_remove(WK_DIRREM(wk));
791 break;
792
793 case D_FREEBLKS:
794
795 mp = WK_FREEBLKS(wk)->fb_mnt;
796 #if 0
797 if (vn_write_suspend_wait(NULL, mp, V_NOWAIT))
798 panic("%s: freeblks on suspended filesystem",
799 "process_worklist_item");
800 #endif
801 if (mp == matchmnt)
802 matchcnt += 1;
803 handle_workitem_freeblocks(WK_FREEBLKS(wk));
804 break;
805
806 case D_FREEFRAG:
807
808 mp = WK_FREEFRAG(wk)->ff_mnt;
809 #if 0
810 if (vn_write_suspend_wait(NULL, mp, V_NOWAIT))
811 panic("%s: freefrag on suspended filesystem",
812 "process_worklist_item");
813 #endif
814 if (mp == matchmnt)
815 matchcnt += 1;
816 handle_workitem_freefrag(WK_FREEFRAG(wk));
817 break;
818
819 case D_FREEFILE:
820
821 mp = WK_FREEFILE(wk)->fx_mnt;
822 #if 0
823 if (vn_write_suspend_wait(NULL, mp, V_NOWAIT))
824 panic("%s: freefile on suspended filesystem",
825 "process_worklist_item");
826 #endif
827 if (mp == matchmnt)
828 matchcnt += 1;
829 handle_workitem_freefile(WK_FREEFILE(wk));
830 break;
831
832 default:
833 panic("%s_process_worklist: Unknown type %s",
834 "softdep", TYPENAME(wk->wk_type));
835
836 }
837 return (matchcnt);
838 }
839
840
841
842
843 void
844 softdep_move_dependencies(oldbp, newbp)
845 struct buf *oldbp;
846 struct buf *newbp;
847 {
848 struct worklist *wk, *wktail;
849
850 if (LIST_FIRST(&newbp->b_dep) != NULL)
851 panic("softdep_move_dependencies: need merge code");
852 wktail = 0;
853 ACQUIRE_LOCK(&lk);
854 while ((wk = LIST_FIRST(&oldbp->b_dep)) != NULL) {
855 LIST_REMOVE(wk, wk_list);
856 if (wktail == 0)
857 LIST_INSERT_HEAD(&newbp->b_dep, wk, wk_list);
858 else
859 LIST_INSERT_AFTER(wktail, wk, wk_list);
860 wktail = wk;
861 }
862 FREE_LOCK(&lk);
863 }
864
865
866
867
868 int
869 softdep_flushworklist(oldmnt, countp, p)
870 struct mount *oldmnt;
871 int *countp;
872 struct proc *p;
873 {
874 struct vnode *devvp;
875 int count, error = 0;
876
877
878
879
880 while (softdep_worklist_busy) {
881 softdep_worklist_req += 1;
882 tsleep(&softdep_worklist_req, PRIBIO, "softflush", 0);
883 softdep_worklist_req -= 1;
884 }
885 softdep_worklist_busy = -1;
886
887
888
889
890
891
892 *countp = 0;
893 devvp = VFSTOUFS(oldmnt)->um_devvp;
894 while ((count = softdep_process_worklist(oldmnt)) > 0) {
895 *countp += count;
896 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
897 error = VOP_FSYNC(devvp, p->p_ucred, MNT_WAIT, p);
898 VOP_UNLOCK(devvp, 0, p);
899 if (error)
900 break;
901 }
902 softdep_worklist_busy = 0;
903 if (softdep_worklist_req)
904 wakeup(&softdep_worklist_req);
905 return (error);
906 }
907
908
909
910
911 int
912 softdep_flushfiles(oldmnt, flags, p)
913 struct mount *oldmnt;
914 int flags;
915 struct proc *p;
916 {
917 int error, count, loopcnt;
918
919
920
921
922
923
924
925 for (loopcnt = 10; loopcnt > 0; loopcnt--) {
926
927
928
929
930 if ((error = ffs_flushfiles(oldmnt, flags, p)) != 0)
931 break;
932 if ((error = softdep_flushworklist(oldmnt, &count, p)) != 0 ||
933 count == 0)
934 break;
935 }
936
937
938
939
940
941 if (loopcnt == 0) {
942 error = EBUSY;
943 }
944 return (error);
945 }
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969 #define DEPALLOC 0x0001
970 #define NODELAY 0x0002
971
972
973
974
975 LIST_HEAD(pagedep_hashhead, pagedep) *pagedep_hashtbl;
976 u_long pagedep_hash;
977 #define PAGEDEP_HASH(mp, inum, lbn) \
978 (&pagedep_hashtbl[((((register_t)(mp)) >> 13) + (inum) + (lbn)) & \
979 pagedep_hash])
980 STATIC struct sema pagedep_in_progress;
981
982
983
984
985
986
987
988
989 STATIC int
990 pagedep_lookup(ip, lbn, flags, pagedeppp)
991 struct inode *ip;
992 daddr64_t lbn;
993 int flags;
994 struct pagedep **pagedeppp;
995 {
996 struct pagedep *pagedep;
997 struct pagedep_hashhead *pagedephd;
998 struct mount *mp;
999 int i;
1000
1001 splassert(IPL_BIO);
1002
1003 #ifdef DEBUG
1004 if (lk.lkt_held == -1)
1005 panic("pagedep_lookup: lock not held");
1006 #endif
1007 mp = ITOV(ip)->v_mount;
1008 pagedephd = PAGEDEP_HASH(mp, ip->i_number, lbn);
1009 top:
1010 LIST_FOREACH(pagedep, pagedephd, pd_hash)
1011 if (ip->i_number == pagedep->pd_ino &&
1012 lbn == pagedep->pd_lbn &&
1013 mp == pagedep->pd_mnt)
1014 break;
1015 if (pagedep) {
1016 *pagedeppp = pagedep;
1017 if ((flags & DEPALLOC) != 0 &&
1018 (pagedep->pd_state & ONWORKLIST) == 0)
1019 return (0);
1020 return (1);
1021 }
1022 if ((flags & DEPALLOC) == 0) {
1023 *pagedeppp = NULL;
1024 return (0);
1025 }
1026 if (sema_get(&pagedep_in_progress, &lk) == 0) {
1027 ACQUIRE_LOCK(&lk);
1028 goto top;
1029 }
1030 pagedep = pool_get(&pagedep_pool, PR_WAITOK);
1031 bzero(pagedep, sizeof(struct pagedep));
1032 pagedep->pd_list.wk_type = D_PAGEDEP;
1033 pagedep->pd_mnt = mp;
1034 pagedep->pd_ino = ip->i_number;
1035 pagedep->pd_lbn = lbn;
1036 LIST_INIT(&pagedep->pd_dirremhd);
1037 LIST_INIT(&pagedep->pd_pendinghd);
1038 for (i = 0; i < DAHASHSZ; i++)
1039 LIST_INIT(&pagedep->pd_diraddhd[i]);
1040 ACQUIRE_LOCK(&lk);
1041 LIST_INSERT_HEAD(pagedephd, pagedep, pd_hash);
1042 sema_release(&pagedep_in_progress);
1043 *pagedeppp = pagedep;
1044 return (0);
1045 }
1046
1047
1048
1049
1050 LIST_HEAD(inodedep_hashhead, inodedep) *inodedep_hashtbl;
1051 STATIC u_long inodedep_hash;
1052 STATIC long num_inodedep;
1053 #define INODEDEP_HASH(fs, inum) \
1054 (&inodedep_hashtbl[((((register_t)(fs)) >> 13) + (inum)) & inodedep_hash])
1055 STATIC struct sema inodedep_in_progress;
1056
1057
1058
1059
1060
1061
1062
1063 STATIC int
1064 inodedep_lookup(fs, inum, flags, inodedeppp)
1065 struct fs *fs;
1066 ino_t inum;
1067 int flags;
1068 struct inodedep **inodedeppp;
1069 {
1070 struct inodedep *inodedep;
1071 struct inodedep_hashhead *inodedephd;
1072 int firsttry;
1073
1074 splassert(IPL_BIO);
1075
1076 #ifdef DEBUG
1077 if (lk.lkt_held == -1)
1078 panic("inodedep_lookup: lock not held");
1079 #endif
1080 firsttry = 1;
1081 inodedephd = INODEDEP_HASH(fs, inum);
1082 top:
1083 LIST_FOREACH(inodedep, inodedephd, id_hash)
1084 if (inum == inodedep->id_ino && fs == inodedep->id_fs)
1085 break;
1086 if (inodedep) {
1087 *inodedeppp = inodedep;
1088 return (1);
1089 }
1090 if ((flags & DEPALLOC) == 0) {
1091 *inodedeppp = NULL;
1092 return (0);
1093 }
1094
1095
1096
1097 if (num_inodedep > max_softdeps && firsttry && (flags & NODELAY) == 0 &&
1098 request_cleanup(FLUSH_INODES, 1)) {
1099 firsttry = 0;
1100 goto top;
1101 }
1102 if (sema_get(&inodedep_in_progress, &lk) == 0) {
1103 ACQUIRE_LOCK(&lk);
1104 goto top;
1105 }
1106 num_inodedep += 1;
1107 inodedep = pool_get(&inodedep_pool, PR_WAITOK);
1108 inodedep->id_list.wk_type = D_INODEDEP;
1109 inodedep->id_fs = fs;
1110 inodedep->id_ino = inum;
1111 inodedep->id_state = ALLCOMPLETE;
1112 inodedep->id_nlinkdelta = 0;
1113 inodedep->id_savedino1 = NULL;
1114 inodedep->id_savedsize = -1;
1115 inodedep->id_buf = NULL;
1116 LIST_INIT(&inodedep->id_pendinghd);
1117 LIST_INIT(&inodedep->id_inowait);
1118 LIST_INIT(&inodedep->id_bufwait);
1119 TAILQ_INIT(&inodedep->id_inoupdt);
1120 TAILQ_INIT(&inodedep->id_newinoupdt);
1121 ACQUIRE_LOCK(&lk);
1122 LIST_INSERT_HEAD(inodedephd, inodedep, id_hash);
1123 sema_release(&inodedep_in_progress);
1124 *inodedeppp = inodedep;
1125 return (0);
1126 }
1127
1128
1129
1130
1131 LIST_HEAD(newblk_hashhead, newblk) *newblk_hashtbl;
1132 u_long newblk_hash;
1133 #define NEWBLK_HASH(fs, inum) \
1134 (&newblk_hashtbl[((((register_t)(fs)) >> 13) + (inum)) & newblk_hash])
1135 STATIC struct sema newblk_in_progress;
1136
1137
1138
1139
1140
1141
1142 STATIC int
1143 newblk_lookup(fs, newblkno, flags, newblkpp)
1144 struct fs *fs;
1145 daddr_t newblkno;
1146 int flags;
1147 struct newblk **newblkpp;
1148 {
1149 struct newblk *newblk;
1150 struct newblk_hashhead *newblkhd;
1151
1152 newblkhd = NEWBLK_HASH(fs, newblkno);
1153 top:
1154 LIST_FOREACH(newblk, newblkhd, nb_hash)
1155 if (newblkno == newblk->nb_newblkno && fs == newblk->nb_fs)
1156 break;
1157 if (newblk) {
1158 *newblkpp = newblk;
1159 return (1);
1160 }
1161 if ((flags & DEPALLOC) == 0) {
1162 *newblkpp = NULL;
1163 return (0);
1164 }
1165 if (sema_get(&newblk_in_progress, 0) == 0)
1166 goto top;
1167 newblk = pool_get(&newblk_pool, PR_WAITOK);
1168 newblk->nb_state = 0;
1169 newblk->nb_fs = fs;
1170 newblk->nb_newblkno = newblkno;
1171 LIST_INSERT_HEAD(newblkhd, newblk, nb_hash);
1172 sema_release(&newblk_in_progress);
1173 *newblkpp = newblk;
1174 return (0);
1175 }
1176
1177
1178
1179
1180
1181 void
1182 softdep_initialize()
1183 {
1184
1185 bioops.io_start = softdep_disk_io_initiation;
1186 bioops.io_complete = softdep_disk_write_complete;
1187 bioops.io_deallocate = softdep_deallocate_dependencies;
1188 bioops.io_movedeps = softdep_move_dependencies;
1189 bioops.io_countdeps = softdep_count_dependencies;
1190
1191 LIST_INIT(&mkdirlisthd);
1192 LIST_INIT(&softdep_workitem_pending);
1193 #ifdef KMEMSTATS
1194 max_softdeps = min (desiredvnodes * 8,
1195 kmemstats[M_INODEDEP].ks_limit / (2 * sizeof(struct inodedep)));
1196 #else
1197 max_softdeps = desiredvnodes * 4;
1198 #endif
1199 pagedep_hashtbl = hashinit(desiredvnodes / 5, M_PAGEDEP, M_WAITOK,
1200 &pagedep_hash);
1201 sema_init(&pagedep_in_progress, "pagedep", PRIBIO, 0);
1202 inodedep_hashtbl = hashinit(desiredvnodes, M_INODEDEP, M_WAITOK,
1203 &inodedep_hash);
1204 sema_init(&inodedep_in_progress, "inodedep", PRIBIO, 0);
1205 newblk_hashtbl = hashinit(64, M_NEWBLK, M_WAITOK, &newblk_hash);
1206 sema_init(&newblk_in_progress, "newblk", PRIBIO, 0);
1207 timeout_set(&proc_waiting_timeout, pause_timer, 0);
1208 pool_init(&pagedep_pool, sizeof(struct pagedep), 0, 0, 0,
1209 "pagedeppl", &pool_allocator_nointr);
1210 pool_init(&inodedep_pool, sizeof(struct inodedep), 0, 0, 0,
1211 "inodedeppl", &pool_allocator_nointr);
1212 pool_init(&newblk_pool, sizeof(struct newblk), 0, 0, 0,
1213 "newblkpl", &pool_allocator_nointr);
1214 pool_init(&bmsafemap_pool, sizeof(struct bmsafemap), 0, 0, 0,
1215 "bmsafemappl", &pool_allocator_nointr);
1216 pool_init(&allocdirect_pool, sizeof(struct allocdirect), 0, 0, 0,
1217 "allocdirectpl", &pool_allocator_nointr);
1218 pool_init(&indirdep_pool, sizeof(struct indirdep), 0, 0, 0,
1219 "indirdeppl", &pool_allocator_nointr);
1220 pool_init(&allocindir_pool, sizeof(struct allocindir), 0, 0, 0,
1221 "allocindirpl", &pool_allocator_nointr);
1222 pool_init(&freefrag_pool, sizeof(struct freefrag), 0, 0, 0,
1223 "freefragpl", &pool_allocator_nointr);
1224 pool_init(&freeblks_pool, sizeof(struct freeblks), 0, 0, 0,
1225 "freeblkspl", &pool_allocator_nointr);
1226 pool_init(&freefile_pool, sizeof(struct freefile), 0, 0, 0,
1227 "freefilepl", &pool_allocator_nointr);
1228 pool_init(&diradd_pool, sizeof(struct diradd), 0, 0, 0,
1229 "diraddpl", &pool_allocator_nointr);
1230 pool_init(&mkdir_pool, sizeof(struct mkdir), 0, 0, 0,
1231 "mkdirpl", &pool_allocator_nointr);
1232 pool_init(&dirrem_pool, sizeof(struct dirrem), 0, 0, 0,
1233 "dirrempl", &pool_allocator_nointr);
1234 pool_init(&newdirblk_pool, sizeof(struct newdirblk), 0, 0, 0,
1235 "newdirblkpl", &pool_allocator_nointr);
1236 }
1237
1238
1239
1240
1241
1242 int
1243 softdep_mount(devvp, mp, fs, cred)
1244 struct vnode *devvp;
1245 struct mount *mp;
1246 struct fs *fs;
1247 struct ucred *cred;
1248 {
1249 struct csum_total cstotal;
1250 struct cg *cgp;
1251 struct buf *bp;
1252 int error, cyl;
1253
1254
1255
1256
1257
1258
1259 if ((fs->fs_flags & FS_UNCLEAN) == 0)
1260 return (0);
1261 bzero(&cstotal, sizeof cstotal);
1262 for (cyl = 0; cyl < fs->fs_ncg; cyl++) {
1263 if ((error = bread(devvp, fsbtodb(fs, cgtod(fs, cyl)),
1264 fs->fs_cgsize, cred, &bp)) != 0) {
1265 brelse(bp);
1266 return (error);
1267 }
1268 cgp = (struct cg *)bp->b_data;
1269 cstotal.cs_nffree += cgp->cg_cs.cs_nffree;
1270 cstotal.cs_nbfree += cgp->cg_cs.cs_nbfree;
1271 cstotal.cs_nifree += cgp->cg_cs.cs_nifree;
1272 cstotal.cs_ndir += cgp->cg_cs.cs_ndir;
1273 fs->fs_cs(fs, cyl) = cgp->cg_cs;
1274 brelse(bp);
1275 }
1276 #ifdef DEBUG
1277 if (bcmp(&cstotal, &fs->fs_cstotal, sizeof cstotal))
1278 printf("ffs_mountfs: superblock updated for soft updates\n");
1279 #endif
1280 bcopy(&cstotal, &fs->fs_cstotal, sizeof cstotal);
1281 return (0);
1282 }
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319 void
1320 softdep_setup_inomapdep(bp, ip, newinum)
1321 struct buf *bp;
1322 struct inode *ip;
1323 ino_t newinum;
1324 {
1325 struct inodedep *inodedep;
1326 struct bmsafemap *bmsafemap;
1327
1328
1329
1330
1331
1332
1333
1334 ACQUIRE_LOCK(&lk);
1335 if (inodedep_lookup(ip->i_fs, newinum, DEPALLOC | NODELAY, &inodedep)
1336 != 0) {
1337 FREE_LOCK(&lk);
1338 panic("softdep_setup_inomapdep: found inode");
1339 }
1340 inodedep->id_buf = bp;
1341 inodedep->id_state &= ~DEPCOMPLETE;
1342 bmsafemap = bmsafemap_lookup(bp);
1343 LIST_INSERT_HEAD(&bmsafemap->sm_inodedephd, inodedep, id_deps);
1344 FREE_LOCK(&lk);
1345 }
1346
1347
1348
1349
1350
1351 void
1352 softdep_setup_blkmapdep(bp, fs, newblkno)
1353 struct buf *bp;
1354 struct fs *fs;
1355 daddr_t newblkno;
1356 {
1357 struct newblk *newblk;
1358 struct bmsafemap *bmsafemap;
1359
1360
1361
1362
1363
1364
1365 if (newblk_lookup(fs, newblkno, DEPALLOC, &newblk) != 0)
1366 panic("softdep_setup_blkmapdep: found block");
1367 ACQUIRE_LOCK(&lk);
1368 newblk->nb_bmsafemap = bmsafemap = bmsafemap_lookup(bp);
1369 LIST_INSERT_HEAD(&bmsafemap->sm_newblkhd, newblk, nb_deps);
1370 FREE_LOCK(&lk);
1371 }
1372
1373
1374
1375
1376
1377
1378
1379 STATIC struct bmsafemap *
1380 bmsafemap_lookup(bp)
1381 struct buf *bp;
1382 {
1383 struct bmsafemap *bmsafemap;
1384 struct worklist *wk;
1385
1386 splassert(IPL_BIO);
1387
1388 #ifdef DEBUG
1389 if (lk.lkt_held == -1)
1390 panic("bmsafemap_lookup: lock not held");
1391 #endif
1392 LIST_FOREACH(wk, &bp->b_dep, wk_list)
1393 if (wk->wk_type == D_BMSAFEMAP)
1394 return (WK_BMSAFEMAP(wk));
1395 FREE_LOCK(&lk);
1396 bmsafemap = pool_get(&bmsafemap_pool, PR_WAITOK);
1397 bmsafemap->sm_list.wk_type = D_BMSAFEMAP;
1398 bmsafemap->sm_list.wk_state = 0;
1399 bmsafemap->sm_buf = bp;
1400 LIST_INIT(&bmsafemap->sm_allocdirecthd);
1401 LIST_INIT(&bmsafemap->sm_allocindirhd);
1402 LIST_INIT(&bmsafemap->sm_inodedephd);
1403 LIST_INIT(&bmsafemap->sm_newblkhd);
1404 ACQUIRE_LOCK(&lk);
1405 WORKLIST_INSERT(&bp->b_dep, &bmsafemap->sm_list);
1406 return (bmsafemap);
1407 }
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438 void
1439 softdep_setup_allocdirect(ip, lbn, newblkno, oldblkno, newsize, oldsize, bp)
1440 struct inode *ip;
1441 daddr64_t lbn;
1442 daddr_t newblkno;
1443 daddr_t oldblkno;
1444 long newsize;
1445 long oldsize;
1446 struct buf *bp;
1447 {
1448 struct allocdirect *adp, *oldadp;
1449 struct allocdirectlst *adphead;
1450 struct bmsafemap *bmsafemap;
1451 struct inodedep *inodedep;
1452 struct pagedep *pagedep;
1453 struct newblk *newblk;
1454
1455 adp = pool_get(&allocdirect_pool, PR_WAITOK);
1456 bzero(adp, sizeof(struct allocdirect));
1457 adp->ad_list.wk_type = D_ALLOCDIRECT;
1458 adp->ad_lbn = lbn;
1459 adp->ad_newblkno = newblkno;
1460 adp->ad_oldblkno = oldblkno;
1461 adp->ad_newsize = newsize;
1462 adp->ad_oldsize = oldsize;
1463 adp->ad_state = ATTACHED;
1464 LIST_INIT(&adp->ad_newdirblk);
1465 if (newblkno == oldblkno)
1466 adp->ad_freefrag = NULL;
1467 else
1468 adp->ad_freefrag = newfreefrag(ip, oldblkno, oldsize);
1469
1470 if (newblk_lookup(ip->i_fs, newblkno, 0, &newblk) == 0)
1471 panic("softdep_setup_allocdirect: lost block");
1472
1473 ACQUIRE_LOCK(&lk);
1474 inodedep_lookup(ip->i_fs, ip->i_number, DEPALLOC | NODELAY, &inodedep);
1475 adp->ad_inodedep = inodedep;
1476
1477 if (newblk->nb_state == DEPCOMPLETE) {
1478 adp->ad_state |= DEPCOMPLETE;
1479 adp->ad_buf = NULL;
1480 } else {
1481 bmsafemap = newblk->nb_bmsafemap;
1482 adp->ad_buf = bmsafemap->sm_buf;
1483 LIST_REMOVE(newblk, nb_deps);
1484 LIST_INSERT_HEAD(&bmsafemap->sm_allocdirecthd, adp, ad_deps);
1485 }
1486 LIST_REMOVE(newblk, nb_hash);
1487 pool_put(&newblk_pool, newblk);
1488
1489 if (bp == NULL) {
1490
1491
1492
1493 panic("softdep_setup_allocdirect: Bonk art in the head");
1494 }
1495 WORKLIST_INSERT(&bp->b_dep, &adp->ad_list);
1496 if (lbn >= NDADDR) {
1497
1498 if (oldblkno != 0) {
1499 FREE_LOCK(&lk);
1500 panic("softdep_setup_allocdirect: non-zero indir");
1501 }
1502 } else {
1503
1504
1505
1506
1507
1508
1509
1510 if ((DIP(ip, mode) & IFMT) == IFDIR &&
1511 pagedep_lookup(ip, lbn, DEPALLOC, &pagedep) == 0)
1512 WORKLIST_INSERT(&bp->b_dep, &pagedep->pd_list);
1513 }
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526 adphead = &inodedep->id_newinoupdt;
1527 oldadp = TAILQ_LAST(adphead, allocdirectlst);
1528 if (oldadp == NULL || oldadp->ad_lbn <= lbn) {
1529
1530 TAILQ_INSERT_TAIL(adphead, adp, ad_next);
1531 if (oldadp != NULL && oldadp->ad_lbn == lbn)
1532 allocdirect_merge(adphead, adp, oldadp);
1533 FREE_LOCK(&lk);
1534 return;
1535 }
1536 TAILQ_FOREACH(oldadp, adphead, ad_next) {
1537 if (oldadp->ad_lbn >= lbn)
1538 break;
1539 }
1540 if (oldadp == NULL) {
1541 FREE_LOCK(&lk);
1542 panic("softdep_setup_allocdirect: lost entry");
1543 }
1544
1545 TAILQ_INSERT_BEFORE(oldadp, adp, ad_next);
1546 if (oldadp->ad_lbn == lbn)
1547 allocdirect_merge(adphead, adp, oldadp);
1548 FREE_LOCK(&lk);
1549 }
1550
1551
1552
1553
1554
1555 STATIC void
1556 allocdirect_merge(adphead, newadp, oldadp)
1557 struct allocdirectlst *adphead;
1558 struct allocdirect *newadp;
1559 struct allocdirect *oldadp;
1560 {
1561 struct worklist *wk;
1562 struct freefrag *freefrag;
1563 struct newdirblk *newdirblk;
1564
1565 splassert(IPL_BIO);
1566
1567 #ifdef DEBUG
1568 if (lk.lkt_held == -1)
1569 panic("allocdirect_merge: lock not held");
1570 #endif
1571 if (newadp->ad_oldblkno != oldadp->ad_newblkno ||
1572 newadp->ad_oldsize != oldadp->ad_newsize ||
1573 newadp->ad_lbn >= NDADDR) {
1574 FREE_LOCK(&lk);
1575 panic("allocdirect_merge: old %d != new %d || lbn %ld >= %d",
1576 newadp->ad_oldblkno, oldadp->ad_newblkno, newadp->ad_lbn,
1577 NDADDR);
1578 }
1579 newadp->ad_oldblkno = oldadp->ad_oldblkno;
1580 newadp->ad_oldsize = oldadp->ad_oldsize;
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597 if (oldadp->ad_freefrag != NULL || oldadp->ad_oldblkno == 0) {
1598 freefrag = newadp->ad_freefrag;
1599 newadp->ad_freefrag = oldadp->ad_freefrag;
1600 oldadp->ad_freefrag = freefrag;
1601 }
1602
1603
1604
1605
1606 if ((wk = LIST_FIRST(&oldadp->ad_newdirblk)) != NULL) {
1607 newdirblk = WK_NEWDIRBLK(wk);
1608 WORKLIST_REMOVE(&newdirblk->db_list);
1609 if (LIST_FIRST(&oldadp->ad_newdirblk) != NULL)
1610 panic("allocdirect_merge: extra newdirblk");
1611 WORKLIST_INSERT(&newadp->ad_newdirblk, &newdirblk->db_list);
1612 }
1613 free_allocdirect(adphead, oldadp, 0);
1614 }
1615
1616
1617
1618
1619 STATIC struct freefrag *
1620 newfreefrag(ip, blkno, size)
1621 struct inode *ip;
1622 daddr_t blkno;
1623 long size;
1624 {
1625 struct freefrag *freefrag;
1626 struct fs *fs;
1627
1628 if (blkno == 0)
1629 return (NULL);
1630 fs = ip->i_fs;
1631 if (fragnum(fs, blkno) + numfrags(fs, size) > fs->fs_frag)
1632 panic("newfreefrag: frag size");
1633 freefrag = pool_get(&freefrag_pool, PR_WAITOK);
1634 freefrag->ff_list.wk_type = D_FREEFRAG;
1635 freefrag->ff_state = DIP(ip, uid) & ~ONWORKLIST;
1636 freefrag->ff_inum = ip->i_number;
1637 freefrag->ff_mnt = ITOV(ip)->v_mount;
1638 freefrag->ff_devvp = ip->i_devvp;
1639 freefrag->ff_blkno = blkno;
1640 freefrag->ff_fragsize = size;
1641 return (freefrag);
1642 }
1643
1644
1645
1646
1647
1648 STATIC void
1649 handle_workitem_freefrag(freefrag)
1650 struct freefrag *freefrag;
1651 {
1652 struct inode tip;
1653 struct ufs1_dinode dtip1;
1654
1655 tip.i_vnode = NULL;
1656 tip.i_din1 = &dtip1;
1657 tip.i_fs = VFSTOUFS(freefrag->ff_mnt)->um_fs;
1658 tip.i_ump = VFSTOUFS(freefrag->ff_mnt);
1659 tip.i_dev = freefrag->ff_devvp->v_rdev;
1660 tip.i_number = freefrag->ff_inum;
1661 tip.i_ffs1_uid = freefrag->ff_state & ~ONWORKLIST;
1662 ffs_blkfree(&tip, freefrag->ff_blkno, freefrag->ff_fragsize);
1663 pool_put(&freefrag_pool, freefrag);
1664 }
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694 STATIC struct allocindir *
1695 newallocindir(ip, ptrno, newblkno, oldblkno)
1696 struct inode *ip;
1697 int ptrno;
1698 daddr_t newblkno;
1699 daddr_t oldblkno;
1700 {
1701 struct allocindir *aip;
1702
1703 aip = pool_get(&allocindir_pool, PR_WAITOK);
1704 bzero(aip,sizeof(struct allocindir));
1705 aip->ai_list.wk_type = D_ALLOCINDIR;
1706 aip->ai_state = ATTACHED;
1707 aip->ai_offset = ptrno;
1708 aip->ai_newblkno = newblkno;
1709 aip->ai_oldblkno = oldblkno;
1710 aip->ai_freefrag = newfreefrag(ip, oldblkno, ip->i_fs->fs_bsize);
1711 return (aip);
1712 }
1713
1714
1715
1716
1717
1718 void
1719 softdep_setup_allocindir_page(ip, lbn, bp, ptrno, newblkno, oldblkno, nbp)
1720 struct inode *ip;
1721 daddr64_t lbn;
1722 struct buf *bp;
1723 int ptrno;
1724 daddr_t newblkno;
1725 daddr_t oldblkno;
1726 struct buf *nbp;
1727 {
1728 struct allocindir *aip;
1729 struct pagedep *pagedep;
1730
1731 aip = newallocindir(ip, ptrno, newblkno, oldblkno);
1732 ACQUIRE_LOCK(&lk);
1733
1734
1735
1736
1737
1738 if ((DIP(ip, mode) & IFMT) == IFDIR &&
1739 pagedep_lookup(ip, lbn, DEPALLOC, &pagedep) == 0)
1740 WORKLIST_INSERT(&nbp->b_dep, &pagedep->pd_list);
1741 if (nbp == NULL) {
1742
1743
1744
1745 panic("softdep_setup_allocindir_page: Bonk art in the head");
1746 }
1747 WORKLIST_INSERT(&nbp->b_dep, &aip->ai_list);
1748 FREE_LOCK(&lk);
1749 setup_allocindir_phase2(bp, ip, aip);
1750 }
1751
1752
1753
1754
1755
1756 void
1757 softdep_setup_allocindir_meta(nbp, ip, bp, ptrno, newblkno)
1758 struct buf *nbp;
1759 struct inode *ip;
1760 struct buf *bp;
1761 int ptrno;
1762 daddr_t newblkno;
1763 {
1764 struct allocindir *aip;
1765
1766 aip = newallocindir(ip, ptrno, newblkno, 0);
1767 ACQUIRE_LOCK(&lk);
1768 WORKLIST_INSERT(&nbp->b_dep, &aip->ai_list);
1769 FREE_LOCK(&lk);
1770 setup_allocindir_phase2(bp, ip, aip);
1771 }
1772
1773
1774
1775
1776
1777 STATIC void
1778 setup_allocindir_phase2(bp, ip, aip)
1779 struct buf *bp;
1780 struct inode *ip;
1781 struct allocindir *aip;
1782 {
1783 struct worklist *wk;
1784 struct indirdep *indirdep, *newindirdep;
1785 struct bmsafemap *bmsafemap;
1786 struct allocindir *oldaip;
1787 struct freefrag *freefrag;
1788 struct newblk *newblk;
1789
1790 if (bp->b_lblkno >= 0)
1791 panic("setup_allocindir_phase2: not indir blk");
1792 for (indirdep = NULL, newindirdep = NULL; ; ) {
1793 ACQUIRE_LOCK(&lk);
1794 LIST_FOREACH(wk, &bp->b_dep, wk_list) {
1795 if (wk->wk_type != D_INDIRDEP)
1796 continue;
1797 indirdep = WK_INDIRDEP(wk);
1798 break;
1799 }
1800 if (indirdep == NULL && newindirdep) {
1801 indirdep = newindirdep;
1802 WORKLIST_INSERT(&bp->b_dep, &indirdep->ir_list);
1803 newindirdep = NULL;
1804 }
1805 FREE_LOCK(&lk);
1806 if (indirdep) {
1807 if (newblk_lookup(ip->i_fs, aip->ai_newblkno, 0,
1808 &newblk) == 0)
1809 panic("setup_allocindir: lost block");
1810 ACQUIRE_LOCK(&lk);
1811 if (newblk->nb_state == DEPCOMPLETE) {
1812 aip->ai_state |= DEPCOMPLETE;
1813 aip->ai_buf = NULL;
1814 } else {
1815 bmsafemap = newblk->nb_bmsafemap;
1816 aip->ai_buf = bmsafemap->sm_buf;
1817 LIST_REMOVE(newblk, nb_deps);
1818 LIST_INSERT_HEAD(&bmsafemap->sm_allocindirhd,
1819 aip, ai_deps);
1820 }
1821 LIST_REMOVE(newblk, nb_hash);
1822 pool_put(&newblk_pool, newblk);
1823 aip->ai_indirdep = indirdep;
1824
1825
1826
1827
1828
1829 if (aip->ai_oldblkno == 0)
1830 oldaip = NULL;
1831 else
1832
1833 LIST_FOREACH(oldaip, &indirdep->ir_deplisthd, ai_next)
1834 if (oldaip->ai_offset == aip->ai_offset)
1835 break;
1836 freefrag = NULL;
1837 if (oldaip != NULL) {
1838 if (oldaip->ai_newblkno != aip->ai_oldblkno) {
1839 FREE_LOCK(&lk);
1840 panic("setup_allocindir_phase2: blkno");
1841 }
1842 aip->ai_oldblkno = oldaip->ai_oldblkno;
1843 freefrag = aip->ai_freefrag;
1844 aip->ai_freefrag = oldaip->ai_freefrag;
1845 oldaip->ai_freefrag = NULL;
1846 free_allocindir(oldaip, NULL);
1847 }
1848 LIST_INSERT_HEAD(&indirdep->ir_deplisthd, aip, ai_next);
1849 if (ip->i_ump->um_fstype == UM_UFS1)
1850 ((int32_t *)indirdep->ir_savebp->b_data)
1851 [aip->ai_offset] = aip->ai_oldblkno;
1852 else
1853 ((int64_t *)indirdep->ir_savebp->b_data)
1854 [aip->ai_offset] = aip->ai_oldblkno;
1855 FREE_LOCK(&lk);
1856 if (freefrag != NULL)
1857 handle_workitem_freefrag(freefrag);
1858 }
1859 if (newindirdep) {
1860 if (indirdep->ir_savebp != NULL)
1861 brelse(newindirdep->ir_savebp);
1862 WORKITEM_FREE(newindirdep, D_INDIRDEP);
1863 }
1864 if (indirdep)
1865 break;
1866 newindirdep = pool_get(&indirdep_pool, PR_WAITOK);
1867 newindirdep->ir_list.wk_type = D_INDIRDEP;
1868 newindirdep->ir_state = ATTACHED;
1869 if (ip->i_ump->um_fstype == UM_UFS1)
1870 newindirdep->ir_state |= UFS1FMT;
1871 LIST_INIT(&newindirdep->ir_deplisthd);
1872 LIST_INIT(&newindirdep->ir_donehd);
1873 if (bp->b_blkno == bp->b_lblkno) {
1874 VOP_BMAP(bp->b_vp, bp->b_lblkno, NULL, &bp->b_blkno,
1875 NULL);
1876 }
1877 newindirdep->ir_savebp =
1878 getblk(ip->i_devvp, bp->b_blkno, bp->b_bcount, 0, 0);
1879 #if 0
1880 BUF_KERNPROC(newindirdep->ir_savebp);
1881 #endif
1882 bcopy(bp->b_data, newindirdep->ir_savebp->b_data, bp->b_bcount);
1883 }
1884 }
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915 void
1916 softdep_setup_freeblocks(ip, length)
1917 struct inode *ip;
1918 off_t length;
1919 {
1920 struct freeblks *freeblks;
1921 struct inodedep *inodedep;
1922 struct allocdirect *adp;
1923 struct vnode *vp;
1924 struct buf *bp;
1925 struct fs *fs;
1926 int i, delay, error;
1927
1928 fs = ip->i_fs;
1929 if (length != 0)
1930 panic("softdep_setup_freeblocks: non-zero length");
1931 freeblks = pool_get(&freeblks_pool, PR_WAITOK);
1932 bzero(freeblks, sizeof(struct freeblks));
1933 freeblks->fb_list.wk_type = D_FREEBLKS;
1934 freeblks->fb_state = ATTACHED;
1935 freeblks->fb_uid = DIP(ip, uid);
1936 freeblks->fb_previousinum = ip->i_number;
1937 freeblks->fb_devvp = ip->i_devvp;
1938 freeblks->fb_mnt = ITOV(ip)->v_mount;
1939 freeblks->fb_oldsize = DIP(ip, size);
1940 freeblks->fb_newsize = length;
1941 freeblks->fb_chkcnt = DIP(ip, blocks);
1942
1943 for (i = 0; i < NDADDR; i++) {
1944 freeblks->fb_dblks[i] = DIP(ip, db[i]);
1945 DIP_ASSIGN(ip, db[i], 0);
1946 }
1947
1948 for (i = 0; i < NIADDR; i++) {
1949 freeblks->fb_iblks[i] = DIP(ip, ib[i]);
1950 DIP_ASSIGN(ip, ib[i], 0);
1951 }
1952
1953 DIP_ASSIGN(ip, blocks, 0);
1954 DIP_ASSIGN(ip, size, 0);
1955
1956
1957
1958
1959
1960
1961 if ((error = bread(ip->i_devvp,
1962 fsbtodb(fs, ino_to_fsba(fs, ip->i_number)),
1963 (int)fs->fs_bsize, NOCRED, &bp)) != 0)
1964 softdep_error("softdep_setup_freeblocks", error);
1965
1966 if (ip->i_ump->um_fstype == UM_UFS1)
1967 *((struct ufs1_dinode *) bp->b_data +
1968 ino_to_fsbo(fs, ip->i_number)) = *ip->i_din1;
1969 else
1970 *((struct ufs2_dinode *) bp->b_data +
1971 ino_to_fsbo(fs, ip->i_number)) = *ip->i_din2;
1972
1973
1974
1975
1976 ACQUIRE_LOCK(&lk);
1977 (void) inodedep_lookup(fs, ip->i_number, DEPALLOC, &inodedep);
1978 if ((inodedep->id_state & IOSTARTED) != 0) {
1979 FREE_LOCK(&lk);
1980 panic("softdep_setup_freeblocks: inode busy");
1981 }
1982
1983
1984
1985
1986
1987
1988
1989 delay = (inodedep->id_state & DEPCOMPLETE);
1990 if (delay)
1991 WORKLIST_INSERT(&inodedep->id_bufwait, &freeblks->fb_list);
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001 merge_inode_lists(inodedep);
2002 while ((adp = TAILQ_FIRST(&inodedep->id_inoupdt)) != 0)
2003 free_allocdirect(&inodedep->id_inoupdt, adp, delay);
2004 FREE_LOCK(&lk);
2005 bdwrite(bp);
2006
2007
2008
2009
2010
2011
2012 vp = ITOV(ip);
2013 ACQUIRE_LOCK(&lk);
2014 drain_output(vp, 1);
2015 while ((bp = LIST_FIRST(&vp->v_dirtyblkhd))) {
2016 if (!getdirtybuf(bp, MNT_WAIT))
2017 break;
2018 (void) inodedep_lookup(fs, ip->i_number, 0, &inodedep);
2019 deallocate_dependencies(bp, inodedep);
2020 bp->b_flags |= B_INVAL | B_NOCACHE;
2021 FREE_LOCK(&lk);
2022 brelse(bp);
2023 ACQUIRE_LOCK(&lk);
2024 }
2025 if (inodedep_lookup(fs, ip->i_number, 0, &inodedep) != 0)
2026 (void) free_inodedep(inodedep);
2027
2028 if (delay) {
2029 freeblks->fb_state |= DEPCOMPLETE;
2030
2031
2032
2033
2034
2035
2036
2037 if ((freeblks->fb_state & ALLCOMPLETE) == ALLCOMPLETE)
2038 add_to_worklist(&freeblks->fb_list);
2039 }
2040
2041 FREE_LOCK(&lk);
2042
2043
2044
2045
2046
2047 if (!delay)
2048 handle_workitem_freeblocks(freeblks);
2049 }
2050
2051
2052
2053
2054
2055
2056
2057
2058 STATIC void
2059 deallocate_dependencies(bp, inodedep)
2060 struct buf *bp;
2061 struct inodedep *inodedep;
2062 {
2063 struct worklist *wk;
2064 struct indirdep *indirdep;
2065 struct allocindir *aip;
2066 struct pagedep *pagedep;
2067 struct dirrem *dirrem;
2068 struct diradd *dap;
2069 int i;
2070
2071 while ((wk = LIST_FIRST(&bp->b_dep)) != NULL) {
2072 switch (wk->wk_type) {
2073
2074 case D_INDIRDEP:
2075 indirdep = WK_INDIRDEP(wk);
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090 if (indirdep->ir_state & GOINGAWAY) {
2091 FREE_LOCK(&lk);
2092 panic("deallocate_dependencies: already gone");
2093 }
2094 indirdep->ir_state |= GOINGAWAY;
2095 while ((aip = LIST_FIRST(&indirdep->ir_deplisthd)) != 0)
2096 free_allocindir(aip, inodedep);
2097 if (bp->b_lblkno >= 0 ||
2098 bp->b_blkno != indirdep->ir_savebp->b_lblkno) {
2099 FREE_LOCK(&lk);
2100 panic("deallocate_dependencies: not indir");
2101 }
2102 bcopy(bp->b_data, indirdep->ir_savebp->b_data,
2103 bp->b_bcount);
2104 WORKLIST_REMOVE(wk);
2105 WORKLIST_INSERT(&indirdep->ir_savebp->b_dep, wk);
2106 continue;
2107
2108 case D_PAGEDEP:
2109 pagedep = WK_PAGEDEP(wk);
2110
2111
2112
2113
2114 for (i = 0; i < DAHASHSZ; i++)
2115 while ((dap =
2116 LIST_FIRST(&pagedep->pd_diraddhd[i])))
2117 free_diradd(dap);
2118 while ((dap = LIST_FIRST(&pagedep->pd_pendinghd)) != 0)
2119 free_diradd(dap);
2120
2121
2122
2123
2124
2125
2126 while ((dirrem = LIST_FIRST(&pagedep->pd_dirremhd))) {
2127 LIST_REMOVE(dirrem, dm_next);
2128 dirrem->dm_dirinum = pagedep->pd_ino;
2129 if (inodedep == NULL ||
2130 (inodedep->id_state & ALLCOMPLETE) ==
2131 ALLCOMPLETE)
2132 add_to_worklist(&dirrem->dm_list);
2133 else
2134 WORKLIST_INSERT(&inodedep->id_bufwait,
2135 &dirrem->dm_list);
2136 }
2137 if ((pagedep->pd_state & NEWBLOCK) != 0) {
2138 LIST_FOREACH(wk, &inodedep->id_bufwait, wk_list)
2139 if (wk->wk_type == D_NEWDIRBLK &&
2140 WK_NEWDIRBLK(wk)->db_pagedep ==
2141 pagedep)
2142 break;
2143 if (wk != NULL) {
2144 WORKLIST_REMOVE(wk);
2145 free_newdirblk(WK_NEWDIRBLK(wk));
2146 } else {
2147 FREE_LOCK(&lk);
2148 panic("deallocate_dependencies: "
2149 "lost pagedep");
2150 }
2151 }
2152 WORKLIST_REMOVE(&pagedep->pd_list);
2153 LIST_REMOVE(pagedep, pd_hash);
2154 WORKITEM_FREE(pagedep, D_PAGEDEP);
2155 continue;
2156
2157 case D_ALLOCINDIR:
2158 free_allocindir(WK_ALLOCINDIR(wk), inodedep);
2159 continue;
2160
2161 case D_ALLOCDIRECT:
2162 case D_INODEDEP:
2163 FREE_LOCK(&lk);
2164 panic("deallocate_dependencies: Unexpected type %s",
2165 TYPENAME(wk->wk_type));
2166
2167
2168 default:
2169 FREE_LOCK(&lk);
2170 panic("deallocate_dependencies: Unknown type %s",
2171 TYPENAME(wk->wk_type));
2172
2173 }
2174 }
2175 }
2176
2177
2178
2179
2180
2181 STATIC void
2182 free_allocdirect(adphead, adp, delay)
2183 struct allocdirectlst *adphead;
2184 struct allocdirect *adp;
2185 int delay;
2186 {
2187 struct newdirblk *newdirblk;
2188 struct worklist *wk;
2189
2190 splassert(IPL_BIO);
2191
2192 #ifdef DEBUG
2193 if (lk.lkt_held == -1)
2194 panic("free_allocdirect: lock not held");
2195 #endif
2196 if ((adp->ad_state & DEPCOMPLETE) == 0)
2197 LIST_REMOVE(adp, ad_deps);
2198 TAILQ_REMOVE(adphead, adp, ad_next);
2199 if ((adp->ad_state & COMPLETE) == 0)
2200 WORKLIST_REMOVE(&adp->ad_list);
2201 if (adp->ad_freefrag != NULL) {
2202 if (delay)
2203 WORKLIST_INSERT(&adp->ad_inodedep->id_bufwait,
2204 &adp->ad_freefrag->ff_list);
2205 else
2206 add_to_worklist(&adp->ad_freefrag->ff_list);
2207 }
2208 if ((wk = LIST_FIRST(&adp->ad_newdirblk)) != NULL) {
2209 newdirblk = WK_NEWDIRBLK(wk);
2210 WORKLIST_REMOVE(&newdirblk->db_list);
2211 if (LIST_FIRST(&adp->ad_newdirblk) != NULL)
2212 panic("free_allocdirect: extra newdirblk");
2213 if (delay)
2214 WORKLIST_INSERT(&adp->ad_inodedep->id_bufwait,
2215 &newdirblk->db_list);
2216 else
2217 free_newdirblk(newdirblk);
2218 }
2219 WORKITEM_FREE(adp, D_ALLOCDIRECT);
2220 }
2221
2222
2223
2224
2225
2226 void
2227 free_newdirblk(newdirblk)
2228 struct newdirblk *newdirblk;
2229 {
2230 struct pagedep *pagedep;
2231 struct diradd *dap;
2232 int i;
2233
2234 splassert(IPL_BIO);
2235
2236 #ifdef DEBUG
2237 if (lk.lkt_held == -1)
2238 panic("free_newdirblk: lock not held");
2239 #endif
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250 pagedep = newdirblk->db_pagedep;
2251 pagedep->pd_state &= ~NEWBLOCK;
2252 if ((pagedep->pd_state & ONWORKLIST) == 0)
2253 while ((dap = LIST_FIRST(&pagedep->pd_pendinghd)) != NULL)
2254 free_diradd(dap);
2255
2256
2257
2258 for (i = 0; i < DAHASHSZ; i++)
2259 if (LIST_FIRST(&pagedep->pd_diraddhd[i]) != NULL)
2260 break;
2261 if (i == DAHASHSZ && (pagedep->pd_state & ONWORKLIST) == 0) {
2262 LIST_REMOVE(pagedep, pd_hash);
2263 WORKITEM_FREE(pagedep, D_PAGEDEP);
2264 }
2265 WORKITEM_FREE(newdirblk, D_NEWDIRBLK);
2266 }
2267
2268
2269
2270
2271
2272 void
2273 softdep_freefile(pvp, ino, mode)
2274 struct vnode *pvp;
2275 ino_t ino;
2276 mode_t mode;
2277 {
2278 struct inode *ip = VTOI(pvp);
2279 struct inodedep *inodedep;
2280 struct freefile *freefile;
2281
2282
2283
2284
2285 freefile = pool_get(&freefile_pool, PR_WAITOK);
2286 freefile->fx_list.wk_type = D_FREEFILE;
2287 freefile->fx_list.wk_state = 0;
2288 freefile->fx_mode = mode;
2289 freefile->fx_oldinum = ino;
2290 freefile->fx_devvp = ip->i_devvp;
2291 freefile->fx_mnt = ITOV(ip)->v_mount;
2292
2293
2294
2295
2296
2297
2298
2299 ACQUIRE_LOCK(&lk);
2300 if (inodedep_lookup(ip->i_fs, ino, 0, &inodedep) == 0 ||
2301 check_inode_unwritten(inodedep)) {
2302 FREE_LOCK(&lk);
2303 handle_workitem_freefile(freefile);
2304 return;
2305 }
2306 WORKLIST_INSERT(&inodedep->id_inowait, &freefile->fx_list);
2307 FREE_LOCK(&lk);
2308 }
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325 STATIC int
2326 check_inode_unwritten(inodedep)
2327 struct inodedep *inodedep;
2328 {
2329 splassert(IPL_BIO);
2330
2331 if ((inodedep->id_state & DEPCOMPLETE) != 0 ||
2332 LIST_FIRST(&inodedep->id_pendinghd) != NULL ||
2333 LIST_FIRST(&inodedep->id_bufwait) != NULL ||
2334 LIST_FIRST(&inodedep->id_inowait) != NULL ||
2335 TAILQ_FIRST(&inodedep->id_inoupdt) != NULL ||
2336 TAILQ_FIRST(&inodedep->id_newinoupdt) != NULL ||
2337 inodedep->id_nlinkdelta != 0)
2338 return (0);
2339 inodedep->id_state |= ALLCOMPLETE;
2340 LIST_REMOVE(inodedep, id_deps);
2341 inodedep->id_buf = NULL;
2342 if (inodedep->id_state & ONWORKLIST)
2343 WORKLIST_REMOVE(&inodedep->id_list);
2344 if (inodedep->id_savedino1 != NULL) {
2345 FREE(inodedep->id_savedino1, M_INODEDEP);
2346 inodedep->id_savedino1 = NULL;
2347 }
2348 if (free_inodedep(inodedep) == 0) {
2349 FREE_LOCK(&lk);
2350 panic("check_inode_unwritten: busy inode");
2351 }
2352 return (1);
2353 }
2354
2355
2356
2357
2358 STATIC int
2359 free_inodedep(inodedep)
2360 struct inodedep *inodedep;
2361 {
2362
2363 if ((inodedep->id_state & ONWORKLIST) != 0 ||
2364 (inodedep->id_state & ALLCOMPLETE) != ALLCOMPLETE ||
2365 LIST_FIRST(&inodedep->id_pendinghd) != NULL ||
2366 LIST_FIRST(&inodedep->id_bufwait) != NULL ||
2367 LIST_FIRST(&inodedep->id_inowait) != NULL ||
2368 TAILQ_FIRST(&inodedep->id_inoupdt) != NULL ||
2369 TAILQ_FIRST(&inodedep->id_newinoupdt) != NULL ||
2370 inodedep->id_nlinkdelta != 0 || inodedep->id_savedino1 != NULL)
2371 return (0);
2372 LIST_REMOVE(inodedep, id_hash);
2373 WORKITEM_FREE(inodedep, D_INODEDEP);
2374 num_inodedep -= 1;
2375 return (1);
2376 }
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386 STATIC void
2387 handle_workitem_freeblocks(freeblks)
2388 struct freeblks *freeblks;
2389 {
2390 struct inode tip;
2391 daddr_t bn;
2392 union {
2393 struct ufs1_dinode di1;
2394 struct ufs2_dinode di2;
2395 } di;
2396 struct fs *fs;
2397 int i, level, bsize;
2398 long nblocks, blocksreleased = 0;
2399 int error, allerror = 0;
2400 daddr64_t baselbns[NIADDR], tmpval;
2401
2402 if (VFSTOUFS(freeblks->fb_mnt)->um_fstype == UM_UFS1)
2403 tip.i_din1 = &di.di1;
2404 else
2405 tip.i_din2 = &di.di2;
2406
2407 tip.i_fs = fs = VFSTOUFS(freeblks->fb_mnt)->um_fs;
2408 tip.i_number = freeblks->fb_previousinum;
2409 tip.i_ump = VFSTOUFS(freeblks->fb_mnt);
2410 tip.i_dev = freeblks->fb_devvp->v_rdev;
2411 DIP_ASSIGN(&tip, size, freeblks->fb_oldsize);
2412 DIP_ASSIGN(&tip, uid, freeblks->fb_uid);
2413 tip.i_vnode = NULL;
2414 tmpval = 1;
2415 baselbns[0] = NDADDR;
2416 for (i = 1; i < NIADDR; i++) {
2417 tmpval *= NINDIR(fs);
2418 baselbns[i] = baselbns[i - 1] + tmpval;
2419 }
2420 nblocks = btodb(fs->fs_bsize);
2421 blocksreleased = 0;
2422
2423
2424
2425 for (level = (NIADDR - 1); level >= 0; level--) {
2426 if ((bn = freeblks->fb_iblks[level]) == 0)
2427 continue;
2428 if ((error = indir_trunc(&tip, fsbtodb(fs, bn), level,
2429 baselbns[level], &blocksreleased)) != 0)
2430 allerror = error;
2431 ffs_blkfree(&tip, bn, fs->fs_bsize);
2432 blocksreleased += nblocks;
2433 }
2434
2435
2436
2437 for (i = (NDADDR - 1); i >= 0; i--) {
2438 if ((bn = freeblks->fb_dblks[i]) == 0)
2439 continue;
2440 bsize = blksize(fs, &tip, i);
2441 ffs_blkfree(&tip, bn, bsize);
2442 blocksreleased += btodb(bsize);
2443 }
2444
2445 #ifdef DIAGNOSTIC
2446 if (freeblks->fb_chkcnt != blocksreleased)
2447 printf("handle_workitem_freeblocks: block count\n");
2448 if (allerror)
2449 softdep_error("handle_workitem_freeblks", allerror);
2450 #endif
2451 WORKITEM_FREE(freeblks, D_FREEBLKS);
2452 }
2453
2454
2455
2456
2457
2458
2459
2460 STATIC int
2461 indir_trunc(ip, dbn, level, lbn, countp)
2462 struct inode *ip;
2463 daddr_t dbn;
2464 int level;
2465 daddr64_t lbn;
2466 long *countp;
2467 {
2468 struct buf *bp;
2469 int32_t *bap1 = NULL;
2470 int64_t nb, *bap2 = NULL;
2471 struct fs *fs;
2472 struct worklist *wk;
2473 struct indirdep *indirdep;
2474 int i, lbnadd, nblocks, ufs1fmt;
2475 int error, allerror = 0;
2476
2477 fs = ip->i_fs;
2478 lbnadd = 1;
2479 for (i = level; i > 0; i--)
2480 lbnadd *= NINDIR(fs);
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493 ACQUIRE_LOCK(&lk);
2494 if ((bp = incore(ip->i_devvp, dbn)) != NULL &&
2495 (wk = LIST_FIRST(&bp->b_dep)) != NULL) {
2496 if (wk->wk_type != D_INDIRDEP ||
2497 (indirdep = WK_INDIRDEP(wk))->ir_savebp != bp ||
2498 (indirdep->ir_state & GOINGAWAY) == 0) {
2499 FREE_LOCK(&lk);
2500 panic("indir_trunc: lost indirdep");
2501 }
2502 WORKLIST_REMOVE(wk);
2503 WORKITEM_FREE(indirdep, D_INDIRDEP);
2504 if (LIST_FIRST(&bp->b_dep) != NULL) {
2505 FREE_LOCK(&lk);
2506 panic("indir_trunc: dangling dep");
2507 }
2508 FREE_LOCK(&lk);
2509 } else {
2510 FREE_LOCK(&lk);
2511 error = bread(ip->i_devvp, dbn, (int)fs->fs_bsize, NOCRED, &bp);
2512 if (error)
2513 return (error);
2514 }
2515
2516
2517
2518 if (ip->i_ump->um_fstype == UM_UFS1) {
2519 ufs1fmt = 1;
2520 bap1 = (int32_t *)bp->b_data;
2521 } else {
2522 ufs1fmt = 0;
2523 bap2 = (int64_t *)bp->b_data;
2524 }
2525 nblocks = btodb(fs->fs_bsize);
2526 for (i = NINDIR(fs) - 1; i >= 0; i--) {
2527 if (ufs1fmt)
2528 nb = bap1[i];
2529 else
2530 nb = bap2[i];
2531 if (nb == 0)
2532 continue;
2533 if (level != 0) {
2534 if ((error = indir_trunc(ip, fsbtodb(fs, nb),
2535 level - 1, lbn + (i * lbnadd), countp)) != 0)
2536 allerror = error;
2537 }
2538 ffs_blkfree(ip, nb, fs->fs_bsize);
2539 *countp += nblocks;
2540 }
2541 bp->b_flags |= B_INVAL | B_NOCACHE;
2542 brelse(bp);
2543 return (allerror);
2544 }
2545
2546
2547
2548
2549
2550 STATIC void
2551 free_allocindir(aip, inodedep)
2552 struct allocindir *aip;
2553 struct inodedep *inodedep;
2554 {
2555 struct freefrag *freefrag;
2556
2557 splassert(IPL_BIO);
2558
2559 #ifdef DEBUG
2560 if (lk.lkt_held == -1)
2561 panic("free_allocindir: lock not held");
2562 #endif
2563 if ((aip->ai_state & DEPCOMPLETE) == 0)
2564 LIST_REMOVE(aip, ai_deps);
2565 if (aip->ai_state & ONWORKLIST)
2566 WORKLIST_REMOVE(&aip->ai_list);
2567 LIST_REMOVE(aip, ai_next);
2568 if ((freefrag = aip->ai_freefrag) != NULL) {
2569 if (inodedep == NULL)
2570 add_to_worklist(&freefrag->ff_list);
2571 else
2572 WORKLIST_INSERT(&inodedep->id_bufwait,
2573 &freefrag->ff_list);
2574 }
2575 WORKITEM_FREE(aip, D_ALLOCINDIR);
2576 }
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601 int
2602 softdep_setup_directory_add(bp, dp, diroffset, newinum, newdirbp, isnewblk)
2603 struct buf *bp;
2604 struct inode *dp;
2605 off_t diroffset;
2606 long newinum;
2607 struct buf *newdirbp;
2608 int isnewblk;
2609 {
2610 int offset;
2611 daddr64_t lbn;
2612 struct fs *fs;
2613 struct diradd *dap;
2614 struct allocdirect *adp;
2615 struct pagedep *pagedep;
2616 struct inodedep *inodedep;
2617 struct newdirblk *newdirblk = NULL;
2618 struct mkdir *mkdir1, *mkdir2;
2619
2620
2621 fs = dp->i_fs;
2622 lbn = lblkno(fs, diroffset);
2623 offset = blkoff(fs, diroffset);
2624 dap = pool_get(&diradd_pool, PR_WAITOK);
2625 bzero(dap,sizeof(struct diradd));
2626 dap->da_list.wk_type = D_DIRADD;
2627 dap->da_offset = offset;
2628 dap->da_newinum = newinum;
2629 dap->da_state = ATTACHED;
2630 if (isnewblk && lbn < NDADDR && fragoff(fs, diroffset) == 0) {
2631 newdirblk = pool_get(&newdirblk_pool, PR_WAITOK);
2632 newdirblk->db_list.wk_type = D_NEWDIRBLK;
2633 newdirblk->db_state = 0;
2634 }
2635 if (newdirbp == NULL) {
2636 dap->da_state |= DEPCOMPLETE;
2637 ACQUIRE_LOCK(&lk);
2638 } else {
2639 dap->da_state |= MKDIR_BODY | MKDIR_PARENT;
2640 mkdir1 = pool_get(&mkdir_pool, PR_WAITOK);
2641 mkdir1->md_list.wk_type = D_MKDIR;
2642 mkdir1->md_state = MKDIR_BODY;
2643 mkdir1->md_diradd = dap;
2644 mkdir2 = pool_get(&mkdir_pool, PR_WAITOK);
2645 mkdir2->md_list.wk_type = D_MKDIR;
2646 mkdir2->md_state = MKDIR_PARENT;
2647 mkdir2->md_diradd = dap;
2648
2649
2650
2651 mkdir1->md_buf = newdirbp;
2652 ACQUIRE_LOCK(&lk);
2653 LIST_INSERT_HEAD(&mkdirlisthd, mkdir1, md_mkdirs);
2654 WORKLIST_INSERT(&newdirbp->b_dep, &mkdir1->md_list);
2655 FREE_LOCK(&lk);
2656 bdwrite(newdirbp);
2657
2658
2659
2660 ACQUIRE_LOCK(&lk);
2661 if (inodedep_lookup(fs, dp->i_number, 0, &inodedep) == 0
2662 || (inodedep->id_state & ALLCOMPLETE) == ALLCOMPLETE) {
2663 dap->da_state &= ~MKDIR_PARENT;
2664 WORKITEM_FREE(mkdir2, D_MKDIR);
2665 } else {
2666 LIST_INSERT_HEAD(&mkdirlisthd, mkdir2, md_mkdirs);
2667 WORKLIST_INSERT(&inodedep->id_bufwait,&mkdir2->md_list);
2668 }
2669 }
2670
2671
2672
2673 if (pagedep_lookup(dp, lbn, DEPALLOC, &pagedep) == 0)
2674 WORKLIST_INSERT(&bp->b_dep, &pagedep->pd_list);
2675 dap->da_pagedep = pagedep;
2676 LIST_INSERT_HEAD(&pagedep->pd_diraddhd[DIRADDHASH(offset)], dap,
2677 da_pdlist);
2678
2679
2680
2681
2682
2683 (void) inodedep_lookup(fs, newinum, DEPALLOC, &inodedep);
2684 if ((inodedep->id_state & ALLCOMPLETE) == ALLCOMPLETE)
2685 diradd_inode_written(dap, inodedep);
2686 else
2687 WORKLIST_INSERT(&inodedep->id_bufwait, &dap->da_list);
2688 if (isnewblk) {
2689
2690
2691
2692
2693
2694
2695
2696 if (lbn >= NDADDR) {
2697 FREE_LOCK(&lk);
2698
2699
2700
2701
2702
2703 if (blkoff(fs, diroffset) == 0)
2704 return (1);
2705 return (0);
2706 }
2707
2708
2709
2710
2711
2712
2713 if (fragoff(fs, diroffset) != 0) {
2714 FREE_LOCK(&lk);
2715 return (0);
2716 }
2717
2718 if ((pagedep->pd_state & NEWBLOCK) != 0) {
2719 WORKITEM_FREE(newdirblk, D_NEWDIRBLK);
2720 FREE_LOCK(&lk);
2721 return (0);
2722 }
2723
2724
2725
2726 if (inodedep_lookup(fs, dp->i_number, 0, &inodedep) == 0)
2727 panic("softdep_setup_directory_add: lost inodedep");
2728 adp = TAILQ_LAST(&inodedep->id_newinoupdt, allocdirectlst);
2729 if (adp == NULL || adp->ad_lbn != lbn) {
2730 FREE_LOCK(&lk);
2731 panic("softdep_setup_directory_add: lost entry");
2732 }
2733 pagedep->pd_state |= NEWBLOCK;
2734 newdirblk->db_pagedep = pagedep;
2735 WORKLIST_INSERT(&adp->ad_newdirblk, &newdirblk->db_list);
2736 }
2737 FREE_LOCK(&lk);
2738 return (0);
2739 }
2740
2741
2742
2743
2744
2745
2746
2747
2748 void
2749 softdep_change_directoryentry_offset(dp, base, oldloc, newloc, entrysize)
2750 struct inode *dp;
2751 caddr_t base;
2752 caddr_t oldloc;
2753 caddr_t newloc;
2754 int entrysize;
2755 {
2756 int offset, oldoffset, newoffset;
2757 struct pagedep *pagedep;
2758 struct diradd *dap;
2759 daddr64_t lbn;
2760
2761 ACQUIRE_LOCK(&lk);
2762 lbn = lblkno(dp->i_fs, dp->i_offset);
2763 offset = blkoff(dp->i_fs, dp->i_offset);
2764 if (pagedep_lookup(dp, lbn, 0, &pagedep) == 0)
2765 goto done;
2766 oldoffset = offset + (oldloc - base);
2767 newoffset = offset + (newloc - base);
2768
2769 LIST_FOREACH(dap, &pagedep->pd_diraddhd[DIRADDHASH(oldoffset)], da_pdlist) {
2770 if (dap->da_offset != oldoffset)
2771 continue;
2772 dap->da_offset = newoffset;
2773 if (DIRADDHASH(newoffset) == DIRADDHASH(oldoffset))
2774 break;
2775 LIST_REMOVE(dap, da_pdlist);
2776 LIST_INSERT_HEAD(&pagedep->pd_diraddhd[DIRADDHASH(newoffset)],
2777 dap, da_pdlist);
2778 break;
2779 }
2780 if (dap == NULL) {
2781
2782 LIST_FOREACH(dap, &pagedep->pd_pendinghd, da_pdlist) {
2783 if (dap->da_offset == oldoffset) {
2784 dap->da_offset = newoffset;
2785 break;
2786 }
2787 }
2788 }
2789 done:
2790 bcopy(oldloc, newloc, entrysize);
2791 FREE_LOCK(&lk);
2792 }
2793
2794
2795
2796
2797
2798 STATIC void
2799 free_diradd(dap)
2800 struct diradd *dap;
2801 {
2802 struct dirrem *dirrem;
2803 struct pagedep *pagedep;
2804 struct inodedep *inodedep;
2805 struct mkdir *mkdir, *nextmd;
2806
2807 splassert(IPL_BIO);
2808
2809 #ifdef DEBUG
2810 if (lk.lkt_held == -1)
2811 panic("free_diradd: lock not held");
2812 #endif
2813 WORKLIST_REMOVE(&dap->da_list);
2814 LIST_REMOVE(dap, da_pdlist);
2815 if ((dap->da_state & DIRCHG) == 0) {
2816 pagedep = dap->da_pagedep;
2817 } else {
2818 dirrem = dap->da_previous;
2819 pagedep = dirrem->dm_pagedep;
2820 dirrem->dm_dirinum = pagedep->pd_ino;
2821 add_to_worklist(&dirrem->dm_list);
2822 }
2823 if (inodedep_lookup(VFSTOUFS(pagedep->pd_mnt)->um_fs, dap->da_newinum,
2824 0, &inodedep) != 0)
2825 (void) free_inodedep(inodedep);
2826 if ((dap->da_state & (MKDIR_PARENT | MKDIR_BODY)) != 0) {
2827 for (mkdir = LIST_FIRST(&mkdirlisthd); mkdir; mkdir = nextmd) {
2828 nextmd = LIST_NEXT(mkdir, md_mkdirs);
2829 if (mkdir->md_diradd != dap)
2830 continue;
2831 dap->da_state &= ~mkdir->md_state;
2832 WORKLIST_REMOVE(&mkdir->md_list);
2833 LIST_REMOVE(mkdir, md_mkdirs);
2834 WORKITEM_FREE(mkdir, D_MKDIR);
2835 }
2836 if ((dap->da_state & (MKDIR_PARENT | MKDIR_BODY)) != 0) {
2837 FREE_LOCK(&lk);
2838 panic("free_diradd: unfound ref");
2839 }
2840 }
2841 WORKITEM_FREE(dap, D_DIRADD);
2842 }
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861 void
2862 softdep_setup_remove(bp, dp, ip, isrmdir)
2863 struct buf *bp;
2864 struct inode *dp;
2865 struct inode *ip;
2866 int isrmdir;
2867 {
2868 struct dirrem *dirrem, *prevdirrem;
2869
2870
2871
2872
2873 dirrem = newdirrem(bp, dp, ip, isrmdir, &prevdirrem);
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886 if ((dirrem->dm_state & COMPLETE) == 0) {
2887 LIST_INSERT_HEAD(&dirrem->dm_pagedep->pd_dirremhd, dirrem,
2888 dm_next);
2889 FREE_LOCK(&lk);
2890 } else {
2891 if (prevdirrem != NULL)
2892 LIST_INSERT_HEAD(&dirrem->dm_pagedep->pd_dirremhd,
2893 prevdirrem, dm_next);
2894 dirrem->dm_dirinum = dirrem->dm_pagedep->pd_ino;
2895 FREE_LOCK(&lk);
2896 handle_workitem_remove(dirrem);
2897 }
2898 }
2899
2900
2901
2902
2903
2904 STATIC long num_dirrem;
2905 STATIC struct dirrem *
2906 newdirrem(bp, dp, ip, isrmdir, prevdirremp)
2907 struct buf *bp;
2908 struct inode *dp;
2909 struct inode *ip;
2910 int isrmdir;
2911 struct dirrem **prevdirremp;
2912 {
2913 int offset;
2914 daddr64_t lbn;
2915 struct diradd *dap;
2916 struct dirrem *dirrem;
2917 struct pagedep *pagedep;
2918
2919
2920
2921
2922 if (ip == NULL)
2923 panic("newdirrem: whiteout");
2924
2925
2926
2927
2928
2929 if (num_dirrem > max_softdeps / 2)
2930 (void) request_cleanup(FLUSH_REMOVE, 0);
2931 num_dirrem += 1;
2932 dirrem = pool_get(&dirrem_pool, PR_WAITOK);
2933 bzero(dirrem,sizeof(struct dirrem));
2934 dirrem->dm_list.wk_type = D_DIRREM;
2935 dirrem->dm_state = isrmdir ? RMDIR : 0;
2936 dirrem->dm_mnt = ITOV(ip)->v_mount;
2937 dirrem->dm_oldinum = ip->i_number;
2938 *prevdirremp = NULL;
2939
2940 ACQUIRE_LOCK(&lk);
2941 lbn = lblkno(dp->i_fs, dp->i_offset);
2942 offset = blkoff(dp->i_fs, dp->i_offset);
2943 if (pagedep_lookup(dp, lbn, DEPALLOC, &pagedep) == 0)
2944 WORKLIST_INSERT(&bp->b_dep, &pagedep->pd_list);
2945 dirrem->dm_pagedep = pagedep;
2946
2947
2948
2949
2950
2951
2952
2953 LIST_FOREACH(dap, &pagedep->pd_diraddhd[DIRADDHASH(offset)], da_pdlist)
2954 if (dap->da_offset == offset)
2955 break;
2956 if (dap == NULL) {
2957
2958 LIST_FOREACH(dap, &pagedep->pd_pendinghd, da_pdlist)
2959 if (dap->da_offset == offset)
2960 break;
2961 if (dap == NULL)
2962 return (dirrem);
2963 }
2964
2965
2966
2967 if ((dap->da_state & ATTACHED) == 0) {
2968 FREE_LOCK(&lk);
2969 panic("newdirrem: not ATTACHED");
2970 }
2971 if (dap->da_newinum != ip->i_number) {
2972 FREE_LOCK(&lk);
2973 panic("newdirrem: inum %d should be %d",
2974 ip->i_number, dap->da_newinum);
2975 }
2976
2977
2978
2979
2980
2981 if ((dap->da_state & DIRCHG) != 0) {
2982 *prevdirremp = dap->da_previous;
2983 dap->da_state &= ~DIRCHG;
2984 dap->da_pagedep = pagedep;
2985 }
2986
2987
2988
2989
2990 dirrem->dm_state |= COMPLETE;
2991 free_diradd(dap);
2992 return (dirrem);
2993 }
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012 void
3013 softdep_setup_directory_change(bp, dp, ip, newinum, isrmdir)
3014 struct buf *bp;
3015 struct inode *dp;
3016 struct inode *ip;
3017 long newinum;
3018 int isrmdir;
3019 {
3020 int offset;
3021 struct diradd *dap = NULL;
3022 struct dirrem *dirrem, *prevdirrem;
3023 struct pagedep *pagedep;
3024 struct inodedep *inodedep;
3025
3026 offset = blkoff(dp->i_fs, dp->i_offset);
3027 dap = pool_get(&diradd_pool, PR_WAITOK);
3028 bzero(dap,sizeof(struct diradd));
3029 dap->da_list.wk_type = D_DIRADD;
3030 dap->da_state = DIRCHG | ATTACHED | DEPCOMPLETE;
3031 dap->da_offset = offset;
3032 dap->da_newinum = newinum;
3033
3034
3035
3036
3037 dirrem = newdirrem(bp, dp, ip, isrmdir, &prevdirrem);
3038 pagedep = dirrem->dm_pagedep;
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051 if (isrmdir > 1)
3052 dirrem->dm_state |= DIRCHG;
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067 if ((dirrem->dm_state & COMPLETE) == 0) {
3068 dap->da_previous = dirrem;
3069 } else {
3070 if (prevdirrem != NULL) {
3071 dap->da_previous = prevdirrem;
3072 } else {
3073 dap->da_state &= ~DIRCHG;
3074 dap->da_pagedep = pagedep;
3075 }
3076 dirrem->dm_dirinum = pagedep->pd_ino;
3077 add_to_worklist(&dirrem->dm_list);
3078 }
3079
3080
3081
3082
3083
3084 if (inodedep_lookup(dp->i_fs, newinum, DEPALLOC, &inodedep) == 0 ||
3085 (inodedep->id_state & ALLCOMPLETE) == ALLCOMPLETE) {
3086 dap->da_state |= COMPLETE;
3087 LIST_INSERT_HEAD(&pagedep->pd_pendinghd, dap, da_pdlist);
3088 WORKLIST_INSERT(&inodedep->id_pendinghd, &dap->da_list);
3089 } else {
3090 LIST_INSERT_HEAD(&pagedep->pd_diraddhd[DIRADDHASH(offset)],
3091 dap, da_pdlist);
3092 WORKLIST_INSERT(&inodedep->id_bufwait, &dap->da_list);
3093 }
3094 FREE_LOCK(&lk);
3095 }
3096
3097
3098
3099
3100
3101
3102
3103 void
3104 softdep_change_linkcnt(ip, nodelay)
3105 struct inode *ip;
3106 int nodelay;
3107 {
3108 struct inodedep *inodedep;
3109 int flags;
3110
3111
3112
3113
3114 flags = DEPALLOC;
3115 if (nodelay)
3116 flags |= NODELAY;
3117
3118 ACQUIRE_LOCK(&lk);
3119
3120 (void) inodedep_lookup(ip->i_fs, ip->i_number, flags, &inodedep);
3121 if (DIP(ip, nlink) < ip->i_effnlink) {
3122 FREE_LOCK(&lk);
3123 panic("softdep_change_linkcnt: bad delta");
3124 }
3125
3126 inodedep->id_nlinkdelta = DIP(ip, nlink) - ip->i_effnlink;
3127
3128 FREE_LOCK(&lk);
3129 }
3130
3131
3132
3133
3134
3135 STATIC void
3136 handle_workitem_remove(dirrem)
3137 struct dirrem *dirrem;
3138 {
3139 struct proc *p = CURPROC;
3140 struct inodedep *inodedep;
3141 struct vnode *vp;
3142 struct inode *ip;
3143 ino_t oldinum;
3144 int error;
3145
3146 if ((error = VFS_VGET(dirrem->dm_mnt, dirrem->dm_oldinum, &vp)) != 0) {
3147 softdep_error("handle_workitem_remove: vget", error);
3148 return;
3149 }
3150 ip = VTOI(vp);
3151 ACQUIRE_LOCK(&lk);
3152 if ((inodedep_lookup(ip->i_fs, dirrem->dm_oldinum, 0, &inodedep))
3153 == 0) {
3154 FREE_LOCK(&lk);
3155 panic("handle_workitem_remove: lost inodedep");
3156 }
3157
3158
3159
3160 if ((dirrem->dm_state & RMDIR) == 0) {
3161 DIP_ADD(ip, nlink, -1);
3162 ip->i_flag |= IN_CHANGE;
3163 if (DIP(ip, nlink) < ip->i_effnlink) {
3164 FREE_LOCK(&lk);
3165 panic("handle_workitem_remove: bad file delta");
3166 }
3167 inodedep->id_nlinkdelta = DIP(ip, nlink) - ip->i_effnlink;
3168 FREE_LOCK(&lk);
3169 vput(vp);
3170 num_dirrem -= 1;
3171 WORKITEM_FREE(dirrem, D_DIRREM);
3172 return;
3173 }
3174
3175
3176
3177
3178
3179
3180
3181 DIP_ADD(ip, nlink, -2);
3182 ip->i_flag |= IN_CHANGE;
3183 if (DIP(ip, nlink) < ip->i_effnlink)
3184 panic("handle_workitem_remove: bad dir delta");
3185 inodedep->id_nlinkdelta = DIP(ip, nlink) - ip->i_effnlink;
3186 FREE_LOCK(&lk);
3187 if ((error = UFS_TRUNCATE(ip, (off_t)0, 0, p->p_ucred)) != 0)
3188 softdep_error("handle_workitem_remove: truncate", error);
3189
3190
3191
3192
3193
3194 if (dirrem->dm_state & DIRCHG) {
3195 vput(vp);
3196 num_dirrem -= 1;
3197 WORKITEM_FREE(dirrem, D_DIRREM);
3198 return;
3199 }
3200
3201
3202
3203
3204
3205
3206 ACQUIRE_LOCK(&lk);
3207 dirrem->dm_state = 0;
3208 oldinum = dirrem->dm_oldinum;
3209 dirrem->dm_oldinum = dirrem->dm_dirinum;
3210 if (inodedep_lookup(ip->i_fs, oldinum, 0, &inodedep) == 0 ||
3211 check_inode_unwritten(inodedep)) {
3212 FREE_LOCK(&lk);
3213 vput(vp);
3214 handle_workitem_remove(dirrem);
3215 return;
3216 }
3217 WORKLIST_INSERT(&inodedep->id_inowait, &dirrem->dm_list);
3218 FREE_LOCK(&lk);
3219 ip->i_flag |= IN_CHANGE;
3220 UFS_UPDATE(VTOI(vp), 0);
3221 vput(vp);
3222 }
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238 STATIC void
3239 handle_workitem_freefile(freefile)
3240 struct freefile *freefile;
3241 {
3242 struct fs *fs;
3243 struct vnode vp;
3244 struct inode tip;
3245 #ifdef DEBUG
3246 struct inodedep *idp;
3247 #endif
3248 int error;
3249
3250 fs = VFSTOUFS(freefile->fx_mnt)->um_fs;
3251 #ifdef DEBUG
3252 ACQUIRE_LOCK(&lk);
3253 error = inodedep_lookup(fs, freefile->fx_oldinum, 0, &idp);
3254 FREE_LOCK(&lk);
3255 if (error)
3256 panic("handle_workitem_freefile: inodedep survived");
3257 #endif
3258 tip.i_ump = VFSTOUFS(freefile->fx_mnt);
3259 tip.i_dev = freefile->fx_devvp->v_rdev;
3260 tip.i_fs = fs;
3261 tip.i_vnode = &vp;
3262 vp.v_data = &tip;
3263
3264 if ((error = ffs_freefile(&tip, freefile->fx_oldinum,
3265 freefile->fx_mode)) != 0) {
3266 softdep_error("handle_workitem_freefile", error);
3267 }
3268 WORKITEM_FREE(freefile, D_FREEFILE);
3269 }
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293 void
3294 softdep_disk_io_initiation(bp)
3295 struct buf *bp;
3296 {
3297 struct worklist *wk, *nextwk;
3298 struct indirdep *indirdep;
3299 struct inodedep *inodedep;
3300 struct buf *sbp;
3301
3302
3303
3304
3305
3306 if (bp->b_flags & B_READ)
3307 panic("softdep_disk_io_initiation: read");
3308
3309 ACQUIRE_LOCK(&lk);
3310
3311
3312
3313
3314 for (wk = LIST_FIRST(&bp->b_dep); wk; wk = nextwk) {
3315 nextwk = LIST_NEXT(wk, wk_list);
3316 switch (wk->wk_type) {
3317
3318 case D_PAGEDEP:
3319 initiate_write_filepage(WK_PAGEDEP(wk), bp);
3320 continue;
3321
3322 case D_INODEDEP:
3323 inodedep = WK_INODEDEP(wk);
3324 if (inodedep->id_fs->fs_magic == FS_UFS1_MAGIC)
3325 initiate_write_inodeblock_ufs1(inodedep, bp);
3326 #ifdef FFS2
3327 else
3328 initiate_write_inodeblock_ufs2(inodedep, bp);
3329 #endif
3330 continue;
3331
3332 case D_INDIRDEP:
3333 indirdep = WK_INDIRDEP(wk);
3334 if (indirdep->ir_state & GOINGAWAY)
3335 panic("disk_io_initiation: indirdep gone");
3336
3337
3338
3339
3340
3341 if (LIST_FIRST(&indirdep->ir_deplisthd) == NULL) {
3342 sbp = indirdep->ir_savebp;
3343 sbp->b_flags |= B_INVAL | B_NOCACHE;
3344
3345 wk->wk_state &= ~ONWORKLIST;
3346 LIST_REMOVE(wk, wk_list);
3347 WORKITEM_FREE(indirdep, D_INDIRDEP);
3348 FREE_LOCK(&lk);
3349 brelse(sbp);
3350 ACQUIRE_LOCK(&lk);
3351 continue;
3352 }
3353
3354
3355
3356 FREE_LOCK(&lk);
3357 indirdep->ir_saveddata = malloc(bp->b_bcount,
3358 M_INDIRDEP, M_WAITOK);
3359 ACQUIRE_LOCK(&lk);
3360 indirdep->ir_state &= ~ATTACHED;
3361 indirdep->ir_state |= UNDONE;
3362 bcopy(bp->b_data, indirdep->ir_saveddata, bp->b_bcount);
3363 bcopy(indirdep->ir_savebp->b_data, bp->b_data,
3364 bp->b_bcount);
3365 continue;
3366
3367 case D_MKDIR:
3368 case D_BMSAFEMAP:
3369 case D_ALLOCDIRECT:
3370 case D_ALLOCINDIR:
3371 continue;
3372
3373 default:
3374 FREE_LOCK(&lk);
3375 panic("handle_disk_io_initiation: Unexpected type %s",
3376 TYPENAME(wk->wk_type));
3377
3378 }
3379 }
3380
3381 FREE_LOCK(&lk);
3382 }
3383
3384
3385
3386
3387
3388
3389
3390 STATIC void
3391 initiate_write_filepage(pagedep, bp)
3392 struct pagedep *pagedep;
3393 struct buf *bp;
3394 {
3395 struct diradd *dap;
3396 struct direct *ep;
3397 int i;
3398
3399 if (pagedep->pd_state & IOSTARTED) {
3400
3401
3402
3403
3404
3405 printf("initiate_write_filepage: already started\n");
3406 return;
3407 }
3408 pagedep->pd_state |= IOSTARTED;
3409 for (i = 0; i < DAHASHSZ; i++) {
3410 LIST_FOREACH(dap, &pagedep->pd_diraddhd[i], da_pdlist) {
3411 ep = (struct direct *)
3412 ((char *)bp->b_data + dap->da_offset);
3413 if (ep->d_ino != dap->da_newinum) {
3414 FREE_LOCK(&lk);
3415 panic("%s: dir inum %d != new %d",
3416 "initiate_write_filepage",
3417 ep->d_ino, dap->da_newinum);
3418 }
3419 if (dap->da_state & DIRCHG)
3420 ep->d_ino = dap->da_previous->dm_oldinum;
3421 else
3422 ep->d_ino = 0;
3423 dap->da_state &= ~ATTACHED;
3424 dap->da_state |= UNDONE;
3425 }
3426 }
3427 }
3428
3429
3430
3431
3432
3433
3434
3435 STATIC void
3436 initiate_write_inodeblock_ufs1(inodedep, bp)
3437 struct inodedep *inodedep;
3438 struct buf *bp;
3439 {
3440 struct allocdirect *adp, *lastadp;
3441 struct ufs1_dinode *dp;
3442 struct fs *fs;
3443 #ifdef DIAGNOSTIC
3444 daddr64_t prevlbn = 0;
3445 int32_t d1, d2;
3446 #endif
3447 int i, deplist;
3448
3449 if (inodedep->id_state & IOSTARTED) {
3450 FREE_LOCK(&lk);
3451 panic("initiate_write_inodeblock: already started");
3452 }
3453 inodedep->id_state |= IOSTARTED;
3454 fs = inodedep->id_fs;
3455 dp = (struct ufs1_dinode *)bp->b_data +
3456 ino_to_fsbo(fs, inodedep->id_ino);
3457
3458
3459
3460
3461 if ((inodedep->id_state & DEPCOMPLETE) == 0) {
3462 if (inodedep->id_savedino1 != NULL) {
3463 FREE_LOCK(&lk);
3464 panic("initiate_write_inodeblock: already doing I/O");
3465 }
3466 FREE_LOCK(&lk);
3467 MALLOC(inodedep->id_savedino1, struct ufs1_dinode *,
3468 sizeof(struct ufs1_dinode), M_INODEDEP, M_WAITOK);
3469 ACQUIRE_LOCK(&lk);
3470 *inodedep->id_savedino1 = *dp;
3471 bzero((caddr_t)dp, sizeof(struct ufs1_dinode));
3472 return;
3473 }
3474
3475
3476
3477 inodedep->id_savedsize = dp->di_size;
3478 if (TAILQ_FIRST(&inodedep->id_inoupdt) == NULL)
3479 return;
3480
3481
3482
3483 for (deplist = 0, adp = TAILQ_FIRST(&inodedep->id_inoupdt); adp;
3484 adp = TAILQ_NEXT(adp, ad_next)) {
3485 #ifdef DIAGNOSTIC
3486 if (deplist != 0 && prevlbn >= adp->ad_lbn) {
3487 FREE_LOCK(&lk);
3488 panic("softdep_write_inodeblock: lbn order");
3489 }
3490 prevlbn = adp->ad_lbn;
3491 if (adp->ad_lbn < NDADDR &&
3492 (d1 = dp->di_db[adp->ad_lbn]) != (d2 = adp->ad_newblkno)) {
3493 FREE_LOCK(&lk);
3494 panic("%s: direct pointer #%ld mismatch %d != %d",
3495 "softdep_write_inodeblock", adp->ad_lbn, d1, d2);
3496 }
3497 if (adp->ad_lbn >= NDADDR &&
3498 (d1 = dp->di_ib[adp->ad_lbn - NDADDR]) !=
3499 (d2 = adp->ad_newblkno)) {
3500 FREE_LOCK(&lk);
3501 panic("%s: indirect pointer #%ld mismatch %d != %d",
3502 "softdep_write_inodeblock", adp->ad_lbn - NDADDR,
3503 d1, d2);
3504 }
3505 deplist |= 1 << adp->ad_lbn;
3506 if ((adp->ad_state & ATTACHED) == 0) {
3507 FREE_LOCK(&lk);
3508 panic("softdep_write_inodeblock: Unknown state 0x%x",
3509 adp->ad_state);
3510 }
3511 #endif
3512 adp->ad_state &= ~ATTACHED;
3513 adp->ad_state |= UNDONE;
3514 }
3515
3516
3517
3518
3519
3520
3521 for (lastadp = NULL, adp = TAILQ_FIRST(&inodedep->id_inoupdt); adp;
3522 lastadp = adp, adp = TAILQ_NEXT(adp, ad_next)) {
3523 if (adp->ad_lbn >= NDADDR)
3524 break;
3525 dp->di_db[adp->ad_lbn] = adp->ad_oldblkno;
3526
3527 if (adp->ad_oldsize == 0 || adp->ad_oldsize == fs->fs_bsize)
3528 continue;
3529 dp->di_size = fs->fs_bsize * adp->ad_lbn + adp->ad_oldsize;
3530 for (i = adp->ad_lbn + 1; i < NDADDR; i++) {
3531 #ifdef DIAGNOSTIC
3532 if (dp->di_db[i] != 0 && (deplist & (1 << i)) == 0) {
3533 FREE_LOCK(&lk);
3534 panic("softdep_write_inodeblock: lost dep1");
3535 }
3536 #endif
3537 dp->di_db[i] = 0;
3538 }
3539 for (i = 0; i < NIADDR; i++) {
3540 #ifdef DIAGNOSTIC
3541 if (dp->di_ib[i] != 0 &&
3542 (deplist & ((1 << NDADDR) << i)) == 0) {
3543 FREE_LOCK(&lk);
3544 panic("softdep_write_inodeblock: lost dep2");
3545 }
3546 #endif
3547 dp->di_ib[i] = 0;
3548 }
3549 return;
3550 }
3551
3552
3553
3554
3555
3556
3557 if (lastadp != NULL &&
3558 dp->di_size <= (lastadp->ad_lbn + 1) * fs->fs_bsize) {
3559 for (i = lastadp->ad_lbn; i >= 0; i--)
3560 if (dp->di_db[i] != 0)
3561 break;
3562 dp->di_size = (i + 1) * fs->fs_bsize;
3563 }
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575 for (; adp; adp = TAILQ_NEXT(adp, ad_next))
3576 dp->di_ib[adp->ad_lbn - NDADDR] = 0;
3577 }
3578
3579 #ifdef FFS2
3580
3581
3582
3583 STATIC void
3584 initiate_write_inodeblock_ufs2(inodedep, bp)
3585 struct inodedep *inodedep;
3586 struct buf *bp;
3587 {
3588 struct allocdirect *adp, *lastadp;
3589 struct ufs2_dinode *dp;
3590 struct fs *fs = inodedep->id_fs;
3591 #ifdef DIAGNOSTIC
3592 daddr64_t prevlbn = -1, d1, d2;
3593 #endif
3594 int deplist, i;
3595
3596 if (inodedep->id_state & IOSTARTED)
3597 panic("initiate_write_inodeblock_ufs2: already started");
3598 inodedep->id_state |= IOSTARTED;
3599 fs = inodedep->id_fs;
3600 dp = (struct ufs2_dinode *)bp->b_data +
3601 ino_to_fsbo(fs, inodedep->id_ino);
3602
3603
3604
3605
3606 if ((inodedep->id_state & DEPCOMPLETE) == 0) {
3607 if (inodedep->id_savedino2 != NULL)
3608 panic("initiate_write_inodeblock_ufs2: I/O underway");
3609 MALLOC(inodedep->id_savedino2, struct ufs2_dinode *,
3610 sizeof(struct ufs2_dinode), M_INODEDEP, M_WAITOK);
3611 *inodedep->id_savedino2 = *dp;
3612 bzero((caddr_t)dp, sizeof(struct ufs2_dinode));
3613 return;
3614 }
3615
3616
3617
3618 inodedep->id_savedsize = dp->di_size;
3619 if (TAILQ_FIRST(&inodedep->id_inoupdt) == NULL)
3620 return;
3621
3622 #ifdef notyet
3623 inodedep->id_savedextsize = dp->di_extsize;
3624 if (TAILQ_FIRST(&inodedep->id_inoupdt) == NULL &&
3625 TAILQ_FIRST(&inodedep->id_extupdt) == NULL)
3626 return;
3627
3628
3629
3630 for (deplist = 0, adp = TAILQ_FIRST(&inodedep->id_extupdt); adp;
3631 adp = TAILQ_NEXT(adp, ad_next)) {
3632 #ifdef DIAGNOSTIC
3633 if (deplist != 0 && prevlbn >= adp->ad_lbn) {
3634 FREE_LOCK(&lk);
3635 panic("softdep_write_inodeblock: lbn order");
3636 }
3637 prevlbn = adp->ad_lbn;
3638 if ((d1 = dp->di_extb[adp->ad_lbn]) !=
3639 (d2 = adp->ad_newblkno)) {
3640 FREE_LOCK(&lk);
3641 panic("%s: direct pointer #%ld mismatch %ld != %ld",
3642 "softdep_write_inodeblock", adp->ad_lbn, d1, d2);
3643 }
3644 deplist |= 1 << adp->ad_lbn;
3645 if ((adp->ad_state & ATTACHED) == 0) {
3646 FREE_LOCK(&lk);
3647 panic("softdep_write_inodeblock: Unknown state 0x%x",
3648 adp->ad_state);
3649 }
3650 #endif
3651 adp->ad_state &= ~ATTACHED;
3652 adp->ad_state |= UNDONE;
3653 }
3654
3655
3656
3657
3658
3659
3660 for (lastadp = NULL, adp = TAILQ_FIRST(&inodedep->id_extupdt); adp;
3661 lastadp = adp, adp = TAILQ_NEXT(adp, ad_next)) {
3662 dp->di_extb[adp->ad_lbn] = adp->ad_oldblkno;
3663
3664 if (adp->ad_oldsize == 0 || adp->ad_oldsize == fs->fs_bsize)
3665 continue;
3666 dp->di_extsize = fs->fs_bsize * adp->ad_lbn + adp->ad_oldsize;
3667 for (i = adp->ad_lbn + 1; i < NXADDR; i++) {
3668 #ifdef DIAGNOSTIC
3669 if (dp->di_extb[i] != 0 && (deplist & (1 << i)) == 0) {
3670 FREE_LOCK(&lk);
3671 panic("softdep_write_inodeblock: lost dep1");
3672 }
3673 #endif
3674 dp->di_extb[i] = 0;
3675 }
3676 lastadp = NULL;
3677 break;
3678 }
3679
3680
3681
3682
3683
3684
3685 if (lastadp != NULL &&
3686 dp->di_extsize <= (lastadp->ad_lbn + 1) * fs->fs_bsize) {
3687 for (i = lastadp->ad_lbn; i >= 0; i--)
3688 if (dp->di_extb[i] != 0)
3689 break;
3690 dp->di_extsize = (i + 1) * fs->fs_bsize;
3691 }
3692 #endif
3693
3694
3695
3696
3697 for (deplist = 0, adp = TAILQ_FIRST(&inodedep->id_inoupdt); adp;
3698 adp = TAILQ_NEXT(adp, ad_next)) {
3699 #ifdef DIAGNOSTIC
3700 if (deplist != 0 && prevlbn >= adp->ad_lbn) {
3701 FREE_LOCK(&lk);
3702 panic("softdep_write_inodeblock: lbn order");
3703 }
3704 prevlbn = adp->ad_lbn;
3705 if (adp->ad_lbn < NDADDR &&
3706 (d1 = dp->di_db[adp->ad_lbn]) != (d2 = adp->ad_newblkno)) {
3707 FREE_LOCK(&lk);
3708 panic("%s: direct pointer #%ld mismatch %ld != %ld",
3709 "softdep_write_inodeblock", adp->ad_lbn, d1, d2);
3710 }
3711 if (adp->ad_lbn >= NDADDR &&
3712 (d1 = dp->di_ib[adp->ad_lbn - NDADDR]) !=
3713 (d2 = adp->ad_newblkno)) {
3714 FREE_LOCK(&lk);
3715 panic("%s: indirect pointer #%ld mismatch %ld != %ld",
3716 "softdep_write_inodeblock", adp->ad_lbn - NDADDR,
3717 d1, d2);
3718 }
3719 deplist |= 1 << adp->ad_lbn;
3720 if ((adp->ad_state & ATTACHED) == 0) {
3721 FREE_LOCK(&lk);
3722 panic("softdep_write_inodeblock: Unknown state 0x%x",
3723 adp->ad_state);
3724 }
3725 #endif
3726 adp->ad_state &= ~ATTACHED;
3727 adp->ad_state |= UNDONE;
3728 }
3729
3730
3731
3732
3733
3734
3735 for (lastadp = NULL, adp = TAILQ_FIRST(&inodedep->id_inoupdt); adp;
3736 lastadp = adp, adp = TAILQ_NEXT(adp, ad_next)) {
3737 if (adp->ad_lbn >= NDADDR)
3738 break;
3739 dp->di_db[adp->ad_lbn] = adp->ad_oldblkno;
3740
3741 if (adp->ad_oldsize == 0 || adp->ad_oldsize == fs->fs_bsize)
3742 continue;
3743 dp->di_size = fs->fs_bsize * adp->ad_lbn + adp->ad_oldsize;
3744 for (i = adp->ad_lbn + 1; i < NDADDR; i++) {
3745 #ifdef DIAGNOSTIC
3746 if (dp->di_db[i] != 0 && (deplist & (1 << i)) == 0) {
3747 FREE_LOCK(&lk);
3748 panic("softdep_write_inodeblock: lost dep2");
3749 }
3750 #endif
3751 dp->di_db[i] = 0;
3752 }
3753 for (i = 0; i < NIADDR; i++) {
3754 #ifdef DIAGNOSTIC
3755 if (dp->di_ib[i] != 0 &&
3756 (deplist & ((1 << NDADDR) << i)) == 0) {
3757 FREE_LOCK(&lk);
3758 panic("softdep_write_inodeblock: lost dep3");
3759 }
3760 #endif
3761 dp->di_ib[i] = 0;
3762 }
3763 return;
3764 }
3765
3766
3767
3768
3769
3770
3771 if (lastadp != NULL &&
3772 dp->di_size <= (lastadp->ad_lbn + 1) * fs->fs_bsize) {
3773 for (i = lastadp->ad_lbn; i >= 0; i--)
3774 if (dp->di_db[i] != 0)
3775 break;
3776 dp->di_size = (i + 1) * fs->fs_bsize;
3777 }
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789 for (; adp; adp = TAILQ_NEXT(adp, ad_next))
3790 dp->di_ib[adp->ad_lbn - NDADDR] = 0;
3791 }
3792 #endif
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802 void
3803 softdep_disk_write_complete(bp)
3804 struct buf *bp;
3805 {
3806 struct worklist *wk;
3807 struct workhead reattach;
3808 struct newblk *newblk;
3809 struct allocindir *aip;
3810 struct allocdirect *adp;
3811 struct indirdep *indirdep;
3812 struct inodedep *inodedep;
3813 struct bmsafemap *bmsafemap;
3814
3815
3816
3817
3818
3819 if ((bp->b_flags & B_ERROR) && !(bp->b_flags & B_INVAL))
3820 return;
3821
3822 #ifdef DEBUG
3823 if (lk.lkt_held != -1)
3824 panic("softdep_disk_write_complete: lock is held");
3825 lk.lkt_held = -2;
3826 #endif
3827 LIST_INIT(&reattach);
3828 while ((wk = LIST_FIRST(&bp->b_dep)) != NULL) {
3829 WORKLIST_REMOVE(wk);
3830 switch (wk->wk_type) {
3831
3832 case D_PAGEDEP:
3833 if (handle_written_filepage(WK_PAGEDEP(wk), bp))
3834 WORKLIST_INSERT(&reattach, wk);
3835 continue;
3836
3837 case D_INODEDEP:
3838 if (handle_written_inodeblock(WK_INODEDEP(wk), bp))
3839 WORKLIST_INSERT(&reattach, wk);
3840 continue;
3841
3842 case D_BMSAFEMAP:
3843 bmsafemap = WK_BMSAFEMAP(wk);
3844 while ((newblk = LIST_FIRST(&bmsafemap->sm_newblkhd))) {
3845 newblk->nb_state |= DEPCOMPLETE;
3846 newblk->nb_bmsafemap = NULL;
3847 LIST_REMOVE(newblk, nb_deps);
3848 }
3849 while ((adp =
3850 LIST_FIRST(&bmsafemap->sm_allocdirecthd))) {
3851 adp->ad_state |= DEPCOMPLETE;
3852 adp->ad_buf = NULL;
3853 LIST_REMOVE(adp, ad_deps);
3854 handle_allocdirect_partdone(adp);
3855 }
3856 while ((aip =
3857 LIST_FIRST(&bmsafemap->sm_allocindirhd))) {
3858 aip->ai_state |= DEPCOMPLETE;
3859 aip->ai_buf = NULL;
3860 LIST_REMOVE(aip, ai_deps);
3861 handle_allocindir_partdone(aip);
3862 }
3863 while ((inodedep =
3864 LIST_FIRST(&bmsafemap->sm_inodedephd)) != NULL) {
3865 inodedep->id_state |= DEPCOMPLETE;
3866 LIST_REMOVE(inodedep, id_deps);
3867 inodedep->id_buf = NULL;
3868 }
3869 WORKITEM_FREE(bmsafemap, D_BMSAFEMAP);
3870 continue;
3871
3872 case D_MKDIR:
3873 handle_written_mkdir(WK_MKDIR(wk), MKDIR_BODY);
3874 continue;
3875
3876 case D_ALLOCDIRECT:
3877 adp = WK_ALLOCDIRECT(wk);
3878 adp->ad_state |= COMPLETE;
3879 handle_allocdirect_partdone(adp);
3880 continue;
3881
3882 case D_ALLOCINDIR:
3883 aip = WK_ALLOCINDIR(wk);
3884 aip->ai_state |= COMPLETE;
3885 handle_allocindir_partdone(aip);
3886 continue;
3887
3888 case D_INDIRDEP:
3889 indirdep = WK_INDIRDEP(wk);
3890 if (indirdep->ir_state & GOINGAWAY)
3891 panic("disk_write_complete: indirdep gone");
3892 bcopy(indirdep->ir_saveddata, bp->b_data, bp->b_bcount);
3893 free(indirdep->ir_saveddata, M_INDIRDEP);
3894 indirdep->ir_saveddata = 0;
3895 indirdep->ir_state &= ~UNDONE;
3896 indirdep->ir_state |= ATTACHED;
3897 while ((aip = LIST_FIRST(&indirdep->ir_donehd)) != 0) {
3898 handle_allocindir_partdone(aip);
3899 if (aip == LIST_FIRST(&indirdep->ir_donehd))
3900 panic("disk_write_complete: not gone");
3901 }
3902 WORKLIST_INSERT(&reattach, wk);
3903 if ((bp->b_flags & B_DELWRI) == 0)
3904 stat_indir_blk_ptrs++;
3905 buf_dirty(bp);
3906 continue;
3907
3908 default:
3909 panic("handle_disk_write_complete: Unknown type %s",
3910 TYPENAME(wk->wk_type));
3911
3912 }
3913 }
3914
3915
3916
3917 while ((wk = LIST_FIRST(&reattach)) != NULL) {
3918 WORKLIST_REMOVE(wk);
3919 WORKLIST_INSERT(&bp->b_dep, wk);
3920 }
3921 #ifdef DEBUG
3922 if (lk.lkt_held != -2)
3923 panic("softdep_disk_write_complete: lock lost");
3924 lk.lkt_held = -1;
3925 #endif
3926 }
3927
3928
3929
3930
3931
3932
3933 STATIC void
3934 handle_allocdirect_partdone(adp)
3935 struct allocdirect *adp;
3936 {
3937 struct allocdirect *listadp;
3938 struct inodedep *inodedep;
3939 long bsize, delay;
3940
3941 splassert(IPL_BIO);
3942
3943 if ((adp->ad_state & ALLCOMPLETE) != ALLCOMPLETE)
3944 return;
3945 if (adp->ad_buf != NULL)
3946 panic("handle_allocdirect_partdone: dangling dep");
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957 inodedep = adp->ad_inodedep;
3958 bsize = inodedep->id_fs->fs_bsize;
3959 TAILQ_FOREACH(listadp, &inodedep->id_inoupdt, ad_next) {
3960
3961 if (listadp == adp)
3962 break;
3963
3964 if (listadp->ad_oldsize == 0 ||
3965 listadp->ad_oldsize == bsize)
3966 continue;
3967
3968 return;
3969 }
3970
3971
3972
3973
3974
3975
3976 if (listadp == NULL) {
3977 #ifdef DEBUG
3978 TAILQ_FOREACH(listadp, &inodedep->id_newinoupdt, ad_next)
3979
3980 if (listadp == adp)
3981 break;
3982 if (listadp == NULL)
3983 panic("handle_allocdirect_partdone: lost dep");
3984 #endif
3985 return;
3986 }
3987
3988
3989
3990
3991
3992
3993
3994 delay = (inodedep->id_state & DEPCOMPLETE);
3995 for (; adp; adp = listadp) {
3996 listadp = TAILQ_NEXT(adp, ad_next);
3997 if ((adp->ad_state & ALLCOMPLETE) != ALLCOMPLETE)
3998 return;
3999 free_allocdirect(&inodedep->id_inoupdt, adp, delay);
4000 }
4001 }
4002
4003
4004
4005
4006
4007
4008 STATIC void
4009 handle_allocindir_partdone(aip)
4010 struct allocindir *aip;
4011 {
4012 struct indirdep *indirdep;
4013
4014 splassert(IPL_BIO);
4015
4016 if ((aip->ai_state & ALLCOMPLETE) != ALLCOMPLETE)
4017 return;
4018 if (aip->ai_buf != NULL)
4019 panic("handle_allocindir_partdone: dangling dependency");
4020 indirdep = aip->ai_indirdep;
4021 if (indirdep->ir_state & UNDONE) {
4022 LIST_REMOVE(aip, ai_next);
4023 LIST_INSERT_HEAD(&indirdep->ir_donehd, aip, ai_next);
4024 return;
4025 }
4026 if (indirdep->ir_state & UFS1FMT)
4027 ((int32_t *)indirdep->ir_savebp->b_data)[aip->ai_offset] =
4028 aip->ai_newblkno;
4029 else
4030 ((int64_t *)indirdep->ir_savebp->b_data)[aip->ai_offset] =
4031 aip->ai_newblkno;
4032 LIST_REMOVE(aip, ai_next);
4033 if (aip->ai_freefrag != NULL)
4034 add_to_worklist(&aip->ai_freefrag->ff_list);
4035 WORKITEM_FREE(aip, D_ALLOCINDIR);
4036 }
4037
4038
4039
4040
4041
4042
4043
4044 STATIC int
4045 handle_written_inodeblock(inodedep, bp)
4046 struct inodedep *inodedep;
4047 struct buf *bp;
4048 {
4049 struct worklist *wk, *filefree;
4050 struct allocdirect *adp, *nextadp;
4051 struct ufs1_dinode *dp1 = NULL;
4052 struct ufs2_dinode *dp2 = NULL;
4053 int hadchanges, fstype;
4054
4055 splassert(IPL_BIO);
4056
4057 if ((inodedep->id_state & IOSTARTED) == 0)
4058 panic("handle_written_inodeblock: not started");
4059 inodedep->id_state &= ~IOSTARTED;
4060
4061 if (inodedep->id_fs->fs_magic == FS_UFS1_MAGIC) {
4062 fstype = UM_UFS1;
4063 dp1 = (struct ufs1_dinode *) bp->b_data +
4064 ino_to_fsbo(inodedep->id_fs, inodedep->id_ino);
4065 } else {
4066 fstype = UM_UFS2;
4067 dp2 = (struct ufs2_dinode *) bp->b_data +
4068 ino_to_fsbo(inodedep->id_fs, inodedep->id_ino);
4069 }
4070
4071
4072
4073
4074
4075
4076
4077
4078 if (inodedep->id_savedino1 != NULL) {
4079 if (fstype == UM_UFS1)
4080 *dp1 = *inodedep->id_savedino1;
4081 else
4082 *dp2 = *inodedep->id_savedino2;
4083 FREE(inodedep->id_savedino1, M_INODEDEP);
4084 inodedep->id_savedino1 = NULL;
4085 if ((bp->b_flags & B_DELWRI) == 0)
4086 stat_inode_bitmap++;
4087 buf_dirty(bp);
4088 return (1);
4089 }
4090 inodedep->id_state |= COMPLETE;
4091
4092
4093
4094
4095 hadchanges = 0;
4096 for (adp = TAILQ_FIRST(&inodedep->id_inoupdt); adp; adp = nextadp) {
4097 nextadp = TAILQ_NEXT(adp, ad_next);
4098 if (adp->ad_state & ATTACHED)
4099 panic("handle_written_inodeblock: new entry");
4100 if (fstype == UM_UFS1) {
4101 if (adp->ad_lbn < NDADDR) {
4102 if (dp1->di_db[adp->ad_lbn] != adp->ad_oldblkno)
4103 panic("%s: %s #%ld mismatch %d != %d",
4104 "handle_written_inodeblock",
4105 "direct pointer", adp->ad_lbn,
4106 dp1->di_db[adp->ad_lbn],
4107 adp->ad_oldblkno);
4108 dp1->di_db[adp->ad_lbn] = adp->ad_newblkno;
4109 } else {
4110 if (dp1->di_ib[adp->ad_lbn - NDADDR] != 0)
4111 panic("%s: %s #%ld allocated as %d",
4112 "handle_written_inodeblock",
4113 "indirect pointer",
4114 adp->ad_lbn - NDADDR,
4115 dp1->di_ib[adp->ad_lbn - NDADDR]);
4116 dp1->di_ib[adp->ad_lbn - NDADDR] =
4117 adp->ad_newblkno;
4118 }
4119 } else {
4120 if (adp->ad_lbn < NDADDR) {
4121 if (dp2->di_db[adp->ad_lbn] != adp->ad_oldblkno)
4122 panic("%s: %s #%ld mismatch %d != %d",
4123 "handle_written_inodeblock",
4124 "direct pointer", adp->ad_lbn,
4125 dp2->di_db[adp->ad_lbn],
4126 adp->ad_oldblkno);
4127 dp2->di_db[adp->ad_lbn] = adp->ad_newblkno;
4128 } else {
4129 if (dp2->di_ib[adp->ad_lbn - NDADDR] != 0)
4130 panic("%s: %s #%ld allocated as %d",
4131 "handle_written_inodeblock",
4132 "indirect pointer",
4133 adp->ad_lbn - NDADDR,
4134 dp2->di_ib[adp->ad_lbn - NDADDR]);
4135 dp2->di_ib[adp->ad_lbn - NDADDR] =
4136 adp->ad_newblkno;
4137 }
4138 }
4139 adp->ad_state &= ~UNDONE;
4140 adp->ad_state |= ATTACHED;
4141 hadchanges = 1;
4142 }
4143 if (hadchanges && (bp->b_flags & B_DELWRI) == 0)
4144 stat_direct_blk_ptrs++;
4145
4146
4147
4148 if (inodedep->id_savedsize == -1)
4149 panic("handle_written_inodeblock: bad size");
4150
4151 if (fstype == UM_UFS1) {
4152 if (dp1->di_size != inodedep->id_savedsize) {
4153 dp1->di_size = inodedep->id_savedsize;
4154 hadchanges = 1;
4155 }
4156 } else {
4157 if (dp2->di_size != inodedep->id_savedsize) {
4158 dp2->di_size = inodedep->id_savedsize;
4159 hadchanges = 1;
4160 }
4161 }
4162 inodedep->id_savedsize = -1;
4163
4164
4165
4166
4167
4168 if (hadchanges)
4169 buf_dirty(bp);
4170
4171
4172
4173 if ((adp = TAILQ_FIRST(&inodedep->id_inoupdt)) != NULL)
4174 handle_allocdirect_partdone(adp);
4175
4176
4177
4178
4179
4180
4181
4182 filefree = NULL;
4183 while ((wk = LIST_FIRST(&inodedep->id_bufwait)) != NULL) {
4184 WORKLIST_REMOVE(wk);
4185 switch (wk->wk_type) {
4186
4187 case D_FREEFILE:
4188
4189
4190
4191
4192
4193
4194 if (filefree != NULL)
4195 panic("handle_written_inodeblock: filefree");
4196 filefree = wk;
4197 continue;
4198
4199 case D_MKDIR:
4200 handle_written_mkdir(WK_MKDIR(wk), MKDIR_PARENT);
4201 continue;
4202
4203 case D_DIRADD:
4204 diradd_inode_written(WK_DIRADD(wk), inodedep);
4205 continue;
4206
4207 case D_FREEBLKS:
4208 wk->wk_state |= COMPLETE;
4209 if ((wk->wk_state & ALLCOMPLETE) != ALLCOMPLETE)
4210 continue;
4211
4212 case D_FREEFRAG:
4213 case D_DIRREM:
4214 add_to_worklist(wk);
4215 continue;
4216
4217 case D_NEWDIRBLK:
4218 free_newdirblk(WK_NEWDIRBLK(wk));
4219 continue;
4220
4221 default:
4222 panic("handle_written_inodeblock: Unknown type %s",
4223 TYPENAME(wk->wk_type));
4224
4225 }
4226 }
4227 if (filefree != NULL) {
4228 if (free_inodedep(inodedep) == 0)
4229 panic("handle_written_inodeblock: live inodedep");
4230 add_to_worklist(filefree);
4231 return (0);
4232 }
4233
4234
4235
4236
4237 if (free_inodedep(inodedep) || TAILQ_FIRST(&inodedep->id_inoupdt) == 0)
4238 return (0);
4239 return (hadchanges);
4240 }
4241
4242
4243
4244
4245
4246 STATIC void
4247 diradd_inode_written(dap, inodedep)
4248 struct diradd *dap;
4249 struct inodedep *inodedep;
4250 {
4251 struct pagedep *pagedep;
4252
4253 splassert(IPL_BIO);
4254
4255 dap->da_state |= COMPLETE;
4256 if ((dap->da_state & ALLCOMPLETE) == ALLCOMPLETE) {
4257 if (dap->da_state & DIRCHG)
4258 pagedep = dap->da_previous->dm_pagedep;
4259 else
4260 pagedep = dap->da_pagedep;
4261 LIST_REMOVE(dap, da_pdlist);
4262 LIST_INSERT_HEAD(&pagedep->pd_pendinghd, dap, da_pdlist);
4263 }
4264 WORKLIST_INSERT(&inodedep->id_pendinghd, &dap->da_list);
4265 }
4266
4267
4268
4269
4270 STATIC void
4271 handle_written_mkdir(mkdir, type)
4272 struct mkdir *mkdir;
4273 int type;
4274 {
4275 struct diradd *dap;
4276 struct pagedep *pagedep;
4277
4278 splassert(IPL_BIO);
4279
4280 if (mkdir->md_state != type)
4281 panic("handle_written_mkdir: bad type");
4282 dap = mkdir->md_diradd;
4283 dap->da_state &= ~type;
4284 if ((dap->da_state & (MKDIR_PARENT | MKDIR_BODY)) == 0)
4285 dap->da_state |= DEPCOMPLETE;
4286 if ((dap->da_state & ALLCOMPLETE) == ALLCOMPLETE) {
4287 if (dap->da_state & DIRCHG)
4288 pagedep = dap->da_previous->dm_pagedep;
4289 else
4290 pagedep = dap->da_pagedep;
4291 LIST_REMOVE(dap, da_pdlist);
4292 LIST_INSERT_HEAD(&pagedep->pd_pendinghd, dap, da_pdlist);
4293 }
4294 LIST_REMOVE(mkdir, md_mkdirs);
4295 WORKITEM_FREE(mkdir, D_MKDIR);
4296 }
4297
4298
4299
4300
4301
4302
4303
4304
4305 STATIC int
4306 handle_written_filepage(pagedep, bp)
4307 struct pagedep *pagedep;
4308 struct buf *bp;
4309 {
4310 struct dirrem *dirrem;
4311 struct diradd *dap, *nextdap;
4312 struct direct *ep;
4313 int i, chgs;
4314
4315 splassert(IPL_BIO);
4316
4317 if ((pagedep->pd_state & IOSTARTED) == 0)
4318 panic("handle_written_filepage: not started");
4319 pagedep->pd_state &= ~IOSTARTED;
4320
4321
4322
4323 while ((dirrem = LIST_FIRST(&pagedep->pd_dirremhd)) != NULL) {
4324 LIST_REMOVE(dirrem, dm_next);
4325 dirrem->dm_dirinum = pagedep->pd_ino;
4326 add_to_worklist(&dirrem->dm_list);
4327 }
4328
4329
4330
4331
4332
4333 if ((pagedep->pd_state & NEWBLOCK) == 0)
4334 while ((dap = LIST_FIRST(&pagedep->pd_pendinghd)) != NULL)
4335 free_diradd(dap);
4336
4337
4338
4339 for (chgs = 0, i = 0; i < DAHASHSZ; i++) {
4340 for (dap = LIST_FIRST(&pagedep->pd_diraddhd[i]); dap;
4341 dap = nextdap) {
4342 nextdap = LIST_NEXT(dap, da_pdlist);
4343 if (dap->da_state & ATTACHED)
4344 panic("handle_written_filepage: attached");
4345 ep = (struct direct *)
4346 ((char *)bp->b_data + dap->da_offset);
4347 ep->d_ino = dap->da_newinum;
4348 dap->da_state &= ~UNDONE;
4349 dap->da_state |= ATTACHED;
4350 chgs = 1;
4351
4352
4353
4354
4355
4356 if ((dap->da_state & ALLCOMPLETE) == ALLCOMPLETE) {
4357 LIST_REMOVE(dap, da_pdlist);
4358 LIST_INSERT_HEAD(&pagedep->pd_pendinghd, dap,
4359 da_pdlist);
4360 }
4361 }
4362 }
4363
4364
4365
4366
4367
4368 if (chgs) {
4369 if ((bp->b_flags & B_DELWRI) == 0)
4370 stat_dir_entry++;
4371 buf_dirty(bp);
4372 return (1);
4373 }
4374
4375
4376
4377
4378
4379
4380 if ((pagedep->pd_state & NEWBLOCK) == 0) {
4381 LIST_REMOVE(pagedep, pd_hash);
4382 WORKITEM_FREE(pagedep, D_PAGEDEP);
4383 }
4384 return (0);
4385 }
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404 void
4405 softdep_load_inodeblock(ip)
4406 struct inode *ip;
4407 {
4408 struct inodedep *inodedep;
4409
4410
4411
4412
4413 ip->i_effnlink = DIP(ip, nlink);
4414 ACQUIRE_LOCK(&lk);
4415 if (inodedep_lookup(ip->i_fs, ip->i_number, 0, &inodedep) == 0) {
4416 FREE_LOCK(&lk);
4417 return;
4418 }
4419 ip->i_effnlink -= inodedep->id_nlinkdelta;
4420 FREE_LOCK(&lk);
4421 }
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433 void
4434 softdep_update_inodeblock(ip, bp, waitfor)
4435 struct inode *ip;
4436 struct buf *bp;
4437 int waitfor;
4438 {
4439 struct inodedep *inodedep;
4440 struct worklist *wk;
4441 int error, gotit;
4442
4443
4444
4445
4446
4447
4448
4449
4450 ACQUIRE_LOCK(&lk);
4451 if (inodedep_lookup(ip->i_fs, ip->i_number, 0, &inodedep) == 0) {
4452 FREE_LOCK(&lk);
4453 if (ip->i_effnlink != DIP(ip, nlink))
4454 panic("softdep_update_inodeblock: bad link count");
4455 return;
4456 }
4457 if (inodedep->id_nlinkdelta != DIP(ip, nlink) - ip->i_effnlink) {
4458 FREE_LOCK(&lk);
4459 panic("softdep_update_inodeblock: bad delta");
4460 }
4461
4462
4463
4464
4465 inodedep->id_state &= ~COMPLETE;
4466 if ((inodedep->id_state & ONWORKLIST) == 0)
4467 WORKLIST_INSERT(&bp->b_dep, &inodedep->id_list);
4468
4469
4470
4471
4472
4473
4474 merge_inode_lists(inodedep);
4475 if (TAILQ_FIRST(&inodedep->id_inoupdt) != NULL)
4476 handle_allocdirect_partdone(TAILQ_FIRST(&inodedep->id_inoupdt));
4477
4478
4479
4480
4481
4482
4483 while ((wk = LIST_FIRST(&inodedep->id_inowait)) != NULL) {
4484 WORKLIST_REMOVE(wk);
4485 WORKLIST_INSERT(&inodedep->id_bufwait, wk);
4486 }
4487
4488
4489
4490
4491
4492
4493
4494 if ((inodedep->id_state & DEPCOMPLETE) != 0 || waitfor == 0) {
4495 FREE_LOCK(&lk);
4496 return;
4497 }
4498 bp = inodedep->id_buf;
4499 gotit = getdirtybuf(bp, MNT_WAIT);
4500 FREE_LOCK(&lk);
4501 if (gotit && (error = bwrite(bp)) != 0)
4502 softdep_error("softdep_update_inodeblock: bwrite", error);
4503 if ((inodedep->id_state & DEPCOMPLETE) == 0)
4504 panic("softdep_update_inodeblock: update failed");
4505 }
4506
4507
4508
4509
4510
4511
4512 STATIC void
4513 merge_inode_lists(inodedep)
4514 struct inodedep *inodedep;
4515 {
4516 struct allocdirect *listadp, *newadp;
4517
4518 splassert(IPL_BIO);
4519
4520 newadp = TAILQ_FIRST(&inodedep->id_newinoupdt);
4521 for (listadp = TAILQ_FIRST(&inodedep->id_inoupdt); listadp && newadp;) {
4522 if (listadp->ad_lbn < newadp->ad_lbn) {
4523 listadp = TAILQ_NEXT(listadp, ad_next);
4524 continue;
4525 }
4526 TAILQ_REMOVE(&inodedep->id_newinoupdt, newadp, ad_next);
4527 TAILQ_INSERT_BEFORE(listadp, newadp, ad_next);
4528 if (listadp->ad_lbn == newadp->ad_lbn) {
4529 allocdirect_merge(&inodedep->id_inoupdt, newadp,
4530 listadp);
4531 listadp = newadp;
4532 }
4533 newadp = TAILQ_FIRST(&inodedep->id_newinoupdt);
4534 }
4535 while ((newadp = TAILQ_FIRST(&inodedep->id_newinoupdt)) != NULL) {
4536 TAILQ_REMOVE(&inodedep->id_newinoupdt, newadp, ad_next);
4537 TAILQ_INSERT_TAIL(&inodedep->id_inoupdt, newadp, ad_next);
4538 }
4539 }
4540
4541
4542
4543
4544
4545 int
4546 softdep_fsync(vp)
4547 struct vnode *vp;
4548 {
4549 struct inodedep *inodedep;
4550 struct pagedep *pagedep;
4551 struct worklist *wk;
4552 struct diradd *dap;
4553 struct mount *mnt;
4554 struct vnode *pvp;
4555 struct inode *ip;
4556 struct inode *pip;
4557 struct buf *bp;
4558 struct fs *fs;
4559 struct proc *p = CURPROC;
4560 int error, flushparent;
4561 ino_t parentino;
4562 daddr64_t lbn;
4563
4564 ip = VTOI(vp);
4565 fs = ip->i_fs;
4566 ACQUIRE_LOCK(&lk);
4567 if (inodedep_lookup(fs, ip->i_number, 0, &inodedep) == 0) {
4568 FREE_LOCK(&lk);
4569 return (0);
4570 }
4571 if (LIST_FIRST(&inodedep->id_inowait) != NULL ||
4572 LIST_FIRST(&inodedep->id_bufwait) != NULL ||
4573 TAILQ_FIRST(&inodedep->id_inoupdt) != NULL ||
4574 TAILQ_FIRST(&inodedep->id_newinoupdt) != NULL) {
4575 FREE_LOCK(&lk);
4576 panic("softdep_fsync: pending ops");
4577 }
4578 for (error = 0, flushparent = 0; ; ) {
4579 if ((wk = LIST_FIRST(&inodedep->id_pendinghd)) == NULL)
4580 break;
4581 if (wk->wk_type != D_DIRADD) {
4582 FREE_LOCK(&lk);
4583 panic("softdep_fsync: Unexpected type %s",
4584 TYPENAME(wk->wk_type));
4585 }
4586 dap = WK_DIRADD(wk);
4587
4588
4589
4590
4591 if (dap->da_state & DIRCHG)
4592 pagedep = dap->da_previous->dm_pagedep;
4593 else
4594 pagedep = dap->da_pagedep;
4595 mnt = pagedep->pd_mnt;
4596 parentino = pagedep->pd_ino;
4597 lbn = pagedep->pd_lbn;
4598 if ((dap->da_state & (MKDIR_BODY | COMPLETE)) != COMPLETE) {
4599 FREE_LOCK(&lk);
4600 panic("softdep_fsync: dirty");
4601 }
4602 if ((dap->da_state & MKDIR_PARENT) ||
4603 (pagedep->pd_state & NEWBLOCK))
4604 flushparent = 1;
4605 else
4606 flushparent = 0;
4607
4608
4609
4610
4611
4612
4613
4614
4615 if (vp->v_flag & VXLOCK)
4616 break;
4617
4618
4619
4620
4621
4622
4623
4624 FREE_LOCK(&lk);
4625 VOP_UNLOCK(vp, 0, p);
4626 error = VFS_VGET(mnt, parentino, &pvp);
4627 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
4628 if (error != 0)
4629 return (error);
4630
4631
4632
4633
4634
4635
4636
4637
4638 pip = VTOI(pvp);
4639 if (flushparent) {
4640 error = UFS_UPDATE(pip, MNT_WAIT);
4641 if (error) {
4642 vput(pvp);
4643 return (error);
4644 }
4645 if (pagedep->pd_state & NEWBLOCK) {
4646 error = VOP_FSYNC(pvp, p->p_ucred, MNT_WAIT, p);
4647 if (error) {
4648 vput(pvp);
4649 return (error);
4650 }
4651 }
4652 }
4653
4654
4655
4656 error = bread(pvp, lbn, fs->fs_bsize, p->p_ucred, &bp);
4657 if (error == 0) {
4658 bp->b_bcount = blksize(fs, pip, lbn);
4659 error = bwrite(bp);
4660 } else
4661 brelse(bp);
4662 vput(pvp);
4663 if (error != 0)
4664 return (error);
4665 ACQUIRE_LOCK(&lk);
4666 if (inodedep_lookup(fs, ip->i_number, 0, &inodedep) == 0)
4667 break;
4668 }
4669 FREE_LOCK(&lk);
4670 return (0);
4671 }
4672
4673
4674
4675
4676
4677
4678 void
4679 softdep_fsync_mountdev(vp, waitfor)
4680 struct vnode *vp;
4681 int waitfor;
4682 {
4683 struct buf *bp, *nbp;
4684 struct worklist *wk;
4685
4686 if (!vn_isdisk(vp, NULL))
4687 panic("softdep_fsync_mountdev: vnode not a disk");
4688 ACQUIRE_LOCK(&lk);
4689 for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
4690 nbp = LIST_NEXT(bp, b_vnbufs);
4691
4692
4693
4694 if (bp->b_flags & B_BUSY)
4695 continue;
4696 bp->b_flags |= B_BUSY;
4697
4698 if ((bp->b_flags & B_DELWRI) == 0) {
4699 FREE_LOCK(&lk);
4700 panic("softdep_fsync_mountdev: not dirty");
4701 }
4702
4703
4704
4705
4706 if ((wk = LIST_FIRST(&bp->b_dep)) == NULL ||
4707 wk->wk_type != D_BMSAFEMAP) {
4708 bp->b_flags &= ~B_BUSY;
4709 continue;
4710 }
4711 bremfree(bp);
4712 FREE_LOCK(&lk);
4713 (void) bawrite(bp);
4714 ACQUIRE_LOCK(&lk);
4715
4716
4717
4718
4719 nbp = LIST_FIRST(&vp->v_dirtyblkhd);
4720 }
4721 if (waitfor == MNT_WAIT)
4722 drain_output(vp, 1);
4723 FREE_LOCK(&lk);
4724 }
4725
4726
4727
4728
4729
4730
4731
4732 int
4733 softdep_sync_metadata(ap)
4734 struct vop_fsync_args
4735
4736
4737
4738
4739 *ap;
4740 {
4741 struct vnode *vp = ap->a_vp;
4742 struct pagedep *pagedep;
4743 struct allocdirect *adp;
4744 struct allocindir *aip;
4745 struct buf *bp, *nbp;
4746 struct worklist *wk;
4747 int i, error, waitfor;
4748
4749
4750
4751
4752
4753 if (!vn_isdisk(vp, NULL)) {
4754 if (!DOINGSOFTDEP(vp))
4755 return (0);
4756 } else
4757 if (vp->v_specmountpoint == NULL ||
4758 (vp->v_specmountpoint->mnt_flag & MNT_SOFTDEP) == 0)
4759 return (0);
4760
4761
4762
4763 ACQUIRE_LOCK(&lk);
4764 if ((error = flush_inodedep_deps(VTOI(vp)->i_fs, VTOI(vp)->i_number))) {
4765 FREE_LOCK(&lk);
4766 return (error);
4767 }
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785 waitfor = MNT_NOWAIT;
4786 top:
4787
4788
4789
4790
4791 drain_output(vp, 1);
4792 bp = LIST_FIRST(&vp->v_dirtyblkhd);
4793 if (getdirtybuf(bp, MNT_WAIT) == 0) {
4794 FREE_LOCK(&lk);
4795 return (0);
4796 }
4797 loop:
4798
4799
4800
4801
4802 LIST_FOREACH(wk, &bp->b_dep, wk_list) {
4803 switch (wk->wk_type) {
4804
4805 case D_ALLOCDIRECT:
4806 adp = WK_ALLOCDIRECT(wk);
4807 if (adp->ad_state & DEPCOMPLETE)
4808 break;
4809 nbp = adp->ad_buf;
4810 if (getdirtybuf(nbp, waitfor) == 0)
4811 break;
4812 FREE_LOCK(&lk);
4813 if (waitfor == MNT_NOWAIT) {
4814 bawrite(nbp);
4815 } else if ((error = VOP_BWRITE(nbp)) != 0) {
4816 bawrite(bp);
4817 return (error);
4818 }
4819 ACQUIRE_LOCK(&lk);
4820 break;
4821
4822 case D_ALLOCINDIR:
4823 aip = WK_ALLOCINDIR(wk);
4824 if (aip->ai_state & DEPCOMPLETE)
4825 break;
4826 nbp = aip->ai_buf;
4827 if (getdirtybuf(nbp, waitfor) == 0)
4828 break;
4829 FREE_LOCK(&lk);
4830 if (waitfor == MNT_NOWAIT) {
4831 bawrite(nbp);
4832 } else if ((error = VOP_BWRITE(nbp)) != 0) {
4833 bawrite(bp);
4834 return (error);
4835 }
4836 ACQUIRE_LOCK(&lk);
4837 break;
4838
4839 case D_INDIRDEP:
4840 restart:
4841
4842 LIST_FOREACH(aip, &WK_INDIRDEP(wk)->ir_deplisthd, ai_next) {
4843 if (aip->ai_state & DEPCOMPLETE)
4844 continue;
4845 nbp = aip->ai_buf;
4846 if (getdirtybuf(nbp, MNT_WAIT) == 0)
4847 goto restart;
4848 FREE_LOCK(&lk);
4849 if ((error = VOP_BWRITE(nbp)) != 0) {
4850 bawrite(bp);
4851 return (error);
4852 }
4853 ACQUIRE_LOCK(&lk);
4854 goto restart;
4855 }
4856 break;
4857
4858 case D_INODEDEP:
4859 if ((error = flush_inodedep_deps(WK_INODEDEP(wk)->id_fs,
4860 WK_INODEDEP(wk)->id_ino)) != 0) {
4861 FREE_LOCK(&lk);
4862 bawrite(bp);
4863 return (error);
4864 }
4865 break;
4866
4867 case D_PAGEDEP:
4868
4869
4870
4871
4872
4873
4874
4875 pagedep = WK_PAGEDEP(wk);
4876 for (i = 0; i < DAHASHSZ; i++) {
4877 if (LIST_FIRST(&pagedep->pd_diraddhd[i]) == 0)
4878 continue;
4879 if ((error =
4880 flush_pagedep_deps(vp, pagedep->pd_mnt,
4881 &pagedep->pd_diraddhd[i]))) {
4882 FREE_LOCK(&lk);
4883 bawrite(bp);
4884 return (error);
4885 }
4886 }
4887 break;
4888
4889 case D_MKDIR:
4890
4891
4892
4893
4894
4895
4896
4897 nbp = WK_MKDIR(wk)->md_buf;
4898 if (getdirtybuf(nbp, waitfor) == 0)
4899 break;
4900 FREE_LOCK(&lk);
4901 if (waitfor == MNT_NOWAIT) {
4902 bawrite(nbp);
4903 } else if ((error = VOP_BWRITE(nbp)) != 0) {
4904 bawrite(bp);
4905 return (error);
4906 }
4907 ACQUIRE_LOCK(&lk);
4908 break;
4909
4910 case D_BMSAFEMAP:
4911
4912
4913
4914
4915
4916
4917
4918 nbp = WK_BMSAFEMAP(wk)->sm_buf;
4919 if (getdirtybuf(nbp, waitfor) == 0)
4920 break;
4921 FREE_LOCK(&lk);
4922 if (waitfor == MNT_NOWAIT) {
4923 bawrite(nbp);
4924 } else if ((error = VOP_BWRITE(nbp)) != 0) {
4925 bawrite(bp);
4926 return (error);
4927 }
4928 ACQUIRE_LOCK(&lk);
4929 break;
4930
4931 default:
4932 FREE_LOCK(&lk);
4933 panic("softdep_sync_metadata: Unknown type %s",
4934 TYPENAME(wk->wk_type));
4935
4936 }
4937 }
4938 nbp = LIST_NEXT(bp, b_vnbufs);
4939 getdirtybuf(nbp, MNT_WAIT);
4940 FREE_LOCK(&lk);
4941 bawrite(bp);
4942 ACQUIRE_LOCK(&lk);
4943 if (nbp != NULL) {
4944 bp = nbp;
4945 goto loop;
4946 }
4947
4948
4949
4950
4951 if (waitfor == MNT_NOWAIT) {
4952 waitfor = MNT_WAIT;
4953 FREE_LOCK(&lk);
4954 ACQUIRE_LOCK(&lk);
4955 goto top;
4956 }
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966 drain_output(vp, 1);
4967 if (LIST_FIRST(&vp->v_dirtyblkhd) == NULL) {
4968 FREE_LOCK(&lk);
4969 return (0);
4970 }
4971
4972 FREE_LOCK(&lk);
4973
4974
4975
4976
4977
4978
4979
4980 if (vn_isdisk(vp, NULL) &&
4981 vp->v_specmountpoint && !VOP_ISLOCKED(vp) &&
4982 (error = VFS_SYNC(vp->v_specmountpoint, MNT_WAIT, ap->a_cred,
4983 ap->a_p)) != 0)
4984 return (error);
4985 return (0);
4986 }
4987
4988
4989
4990
4991
4992 STATIC int
4993 flush_inodedep_deps(fs, ino)
4994 struct fs *fs;
4995 ino_t ino;
4996 {
4997 struct inodedep *inodedep;
4998 struct allocdirect *adp;
4999 int error, waitfor;
5000 struct buf *bp;
5001
5002 splassert(IPL_BIO);
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017 for (waitfor = MNT_NOWAIT; ; ) {
5018 FREE_LOCK(&lk);
5019 ACQUIRE_LOCK(&lk);
5020 if (inodedep_lookup(fs, ino, 0, &inodedep) == 0)
5021 return (0);
5022 TAILQ_FOREACH(adp, &inodedep->id_inoupdt, ad_next) {
5023 if (adp->ad_state & DEPCOMPLETE)
5024 continue;
5025 bp = adp->ad_buf;
5026 if (getdirtybuf(bp, waitfor) == 0) {
5027 if (waitfor == MNT_NOWAIT)
5028 continue;
5029 break;
5030 }
5031 FREE_LOCK(&lk);
5032 if (waitfor == MNT_NOWAIT) {
5033 bawrite(bp);
5034 } else if ((error = VOP_BWRITE(bp)) != 0) {
5035 ACQUIRE_LOCK(&lk);
5036 return (error);
5037 }
5038 ACQUIRE_LOCK(&lk);
5039 break;
5040 }
5041 if (adp != NULL)
5042 continue;
5043 TAILQ_FOREACH(adp, &inodedep->id_newinoupdt, ad_next) {
5044 if (adp->ad_state & DEPCOMPLETE)
5045 continue;
5046 bp = adp->ad_buf;
5047 if (getdirtybuf(bp, waitfor) == 0) {
5048 if (waitfor == MNT_NOWAIT)
5049 continue;
5050 break;
5051 }
5052 FREE_LOCK(&lk);
5053 if (waitfor == MNT_NOWAIT) {
5054 bawrite(bp);
5055 } else if ((error = VOP_BWRITE(bp)) != 0) {
5056 ACQUIRE_LOCK(&lk);
5057 return (error);
5058 }
5059 ACQUIRE_LOCK(&lk);
5060 break;
5061 }
5062 if (adp != NULL)
5063 continue;
5064
5065
5066
5067 if (waitfor == MNT_WAIT)
5068 break;
5069 waitfor = MNT_WAIT;
5070 }
5071
5072
5073
5074 if (inodedep_lookup(fs, ino, 0, &inodedep) != 0)
5075 (void) free_inodedep(inodedep);
5076 return (0);
5077 }
5078
5079
5080
5081
5082
5083 STATIC int
5084 flush_pagedep_deps(pvp, mp, diraddhdp)
5085 struct vnode *pvp;
5086 struct mount *mp;
5087 struct diraddhd *diraddhdp;
5088 {
5089 struct proc *p = CURPROC;
5090 struct worklist *wk;
5091 struct inodedep *inodedep;
5092 struct ufsmount *ump;
5093 struct diradd *dap;
5094 struct vnode *vp;
5095 int gotit, error = 0;
5096 struct buf *bp;
5097 ino_t inum;
5098
5099 splassert(IPL_BIO);
5100
5101 ump = VFSTOUFS(mp);
5102 while ((dap = LIST_FIRST(diraddhdp)) != NULL) {
5103
5104
5105
5106
5107 if (dap->da_state & MKDIR_PARENT) {
5108 FREE_LOCK(&lk);
5109 if ((error = UFS_UPDATE(VTOI(pvp), MNT_WAIT)))
5110 break;
5111 ACQUIRE_LOCK(&lk);
5112
5113
5114
5115 if (dap != LIST_FIRST(diraddhdp))
5116 continue;
5117 if (dap->da_state & MKDIR_PARENT) {
5118 FREE_LOCK(&lk);
5119 panic("flush_pagedep_deps: MKDIR_PARENT");
5120 }
5121 }
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134 inum = dap->da_newinum;
5135 if (dap->da_state & MKDIR_BODY) {
5136 FREE_LOCK(&lk);
5137 if ((error = VFS_VGET(mp, inum, &vp)) != 0)
5138 break;
5139 if ((error=VOP_FSYNC(vp, p->p_ucred, MNT_NOWAIT, p)) ||
5140 (error=VOP_FSYNC(vp, p->p_ucred, MNT_NOWAIT, p))) {
5141 vput(vp);
5142 break;
5143 }
5144 drain_output(vp, 0);
5145
5146
5147
5148
5149 for (;;) {
5150 error = 0;
5151 ACQUIRE_LOCK(&lk);
5152 bp = incore(vp, 0);
5153 if (bp == NULL) {
5154 FREE_LOCK(&lk);
5155 break;
5156 }
5157 LIST_FOREACH(wk, &bp->b_dep, wk_list)
5158 if (wk->wk_type == D_MKDIR)
5159 break;
5160 if (wk) {
5161 gotit = getdirtybuf(bp, MNT_WAIT);
5162 FREE_LOCK(&lk);
5163 if (gotit && (error = bwrite(bp)) != 0)
5164 break;
5165 } else
5166 FREE_LOCK(&lk);
5167 break;
5168 }
5169 vput(vp);
5170
5171 if (error)
5172 break;
5173 ACQUIRE_LOCK(&lk);
5174
5175
5176
5177 if (dap != LIST_FIRST(diraddhdp))
5178 continue;
5179 if (dap->da_state & MKDIR_BODY) {
5180 FREE_LOCK(&lk);
5181 panic("flush_pagedep_deps: MKDIR_BODY");
5182 }
5183 }
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194 if (inodedep_lookup(ump->um_fs, inum, 0, &inodedep) == 0) {
5195 FREE_LOCK(&lk);
5196 panic("flush_pagedep_deps: lost inode");
5197 }
5198
5199
5200
5201
5202 if ((inodedep->id_state & DEPCOMPLETE) == 0) {
5203 bp = inodedep->id_buf;
5204 gotit = getdirtybuf(bp, MNT_WAIT);
5205 FREE_LOCK(&lk);
5206 if (gotit && (error = bwrite(bp)) != 0)
5207 break;
5208 ACQUIRE_LOCK(&lk);
5209 if (dap != LIST_FIRST(diraddhdp))
5210 continue;
5211 }
5212
5213
5214
5215
5216 FREE_LOCK(&lk);
5217 if ((error = bread(ump->um_devvp,
5218 fsbtodb(ump->um_fs, ino_to_fsba(ump->um_fs, inum)),
5219 (int)ump->um_fs->fs_bsize, NOCRED, &bp)) != 0) {
5220 brelse(bp);
5221 break;
5222 }
5223 if ((error = bwrite(bp)) != 0)
5224 break;
5225 ACQUIRE_LOCK(&lk);
5226
5227
5228
5229
5230 if (dap == LIST_FIRST(diraddhdp)) {
5231 FREE_LOCK(&lk);
5232 panic("flush_pagedep_deps: flush failed");
5233 }
5234 }
5235 if (error)
5236 ACQUIRE_LOCK(&lk);
5237 return (error);
5238 }
5239
5240
5241
5242
5243
5244
5245
5246
5247 int
5248 softdep_slowdown(vp)
5249 struct vnode *vp;
5250 {
5251 int max_softdeps_hard;
5252
5253 max_softdeps_hard = max_softdeps * 11 / 10;
5254 if (num_dirrem < max_softdeps_hard / 2 &&
5255 num_inodedep < max_softdeps_hard)
5256 return (0);
5257 stat_sync_limit_hit += 1;
5258 return (1);
5259 }
5260
5261
5262
5263
5264
5265 STATIC int
5266 request_cleanup(resource, islocked)
5267 int resource;
5268 int islocked;
5269 {
5270 struct proc *p = CURPROC;
5271 int s;
5272
5273
5274
5275
5276 if (p == filesys_syncer || (p->p_flag & P_SOFTDEP))
5277 return (0);
5278
5279
5280
5281
5282
5283
5284
5285
5286 if (num_on_worklist > max_softdeps / 10) {
5287 atomic_setbits_int(&p->p_flag, P_SOFTDEP);
5288 if (islocked)
5289 FREE_LOCK(&lk);
5290 process_worklist_item(NULL, LK_NOWAIT);
5291 process_worklist_item(NULL, LK_NOWAIT);
5292 atomic_clearbits_int(&p->p_flag, P_SOFTDEP);
5293 stat_worklist_push += 2;
5294 if (islocked)
5295 ACQUIRE_LOCK(&lk);
5296 return(1);
5297 }
5298
5299
5300
5301
5302 if (speedup_syncer())
5303 return(0);
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314 switch (resource) {
5315
5316 case FLUSH_INODES:
5317 stat_ino_limit_push += 1;
5318 req_clear_inodedeps += 1;
5319 stat_countp = &stat_ino_limit_hit;
5320 break;
5321
5322 case FLUSH_REMOVE:
5323 stat_blk_limit_push += 1;
5324 req_clear_remove += 1;
5325 stat_countp = &stat_blk_limit_hit;
5326 break;
5327
5328 default:
5329 if (islocked)
5330 FREE_LOCK(&lk);
5331 panic("request_cleanup: unknown type");
5332 }
5333
5334
5335
5336
5337 if (islocked == 0)
5338 ACQUIRE_LOCK(&lk);
5339 proc_waiting += 1;
5340 if (!timeout_pending(&proc_waiting_timeout))
5341 timeout_add(&proc_waiting_timeout, tickdelay > 2 ? tickdelay : 2);
5342
5343 s = FREE_LOCK_INTERLOCKED(&lk);
5344 (void) tsleep((caddr_t)&proc_waiting, PPAUSE, "softupdate", 0);
5345 ACQUIRE_LOCK_INTERLOCKED(&lk, s);
5346 proc_waiting -= 1;
5347 if (islocked == 0)
5348 FREE_LOCK(&lk);
5349 return (1);
5350 }
5351
5352
5353
5354
5355
5356 void
5357 pause_timer(arg)
5358 void *arg;
5359 {
5360
5361 *stat_countp += 1;
5362 wakeup_one(&proc_waiting);
5363 if (proc_waiting > 0)
5364 timeout_add(&proc_waiting_timeout, tickdelay > 2 ? tickdelay : 2);
5365 }
5366
5367
5368
5369
5370
5371 STATIC void
5372 clear_remove(p)
5373 struct proc *p;
5374 {
5375 struct pagedep_hashhead *pagedephd;
5376 struct pagedep *pagedep;
5377 static int next = 0;
5378 struct mount *mp;
5379 struct vnode *vp;
5380 int error, cnt;
5381 ino_t ino;
5382
5383 ACQUIRE_LOCK(&lk);
5384 for (cnt = 0; cnt < pagedep_hash; cnt++) {
5385 pagedephd = &pagedep_hashtbl[next++];
5386 if (next >= pagedep_hash)
5387 next = 0;
5388 LIST_FOREACH(pagedep, pagedephd, pd_hash) {
5389 if (LIST_FIRST(&pagedep->pd_dirremhd) == NULL)
5390 continue;
5391 mp = pagedep->pd_mnt;
5392 ino = pagedep->pd_ino;
5393 #if 0
5394 if (vn_start_write(NULL, &mp, V_NOWAIT) != 0)
5395 continue;
5396 #endif
5397 FREE_LOCK(&lk);
5398 if ((error = VFS_VGET(mp, ino, &vp)) != 0) {
5399 softdep_error("clear_remove: vget", error);
5400 #if 0
5401 vn_finished_write(mp);
5402 #endif
5403 return;
5404 }
5405 if ((error = VOP_FSYNC(vp, p->p_ucred, MNT_NOWAIT, p)))
5406 softdep_error("clear_remove: fsync", error);
5407 drain_output(vp, 0);
5408 vput(vp);
5409 #if 0
5410 vn_finished_write(mp);
5411 #endif
5412 return;
5413 }
5414 }
5415 FREE_LOCK(&lk);
5416 }
5417
5418
5419
5420
5421
5422 STATIC void
5423 clear_inodedeps(p)
5424 struct proc *p;
5425 {
5426 struct inodedep_hashhead *inodedephd;
5427 struct inodedep *inodedep;
5428 static int next = 0;
5429 struct mount *mp;
5430 struct vnode *vp;
5431 struct fs *fs;
5432 int error, cnt;
5433 ino_t firstino, lastino, ino;
5434
5435 ACQUIRE_LOCK(&lk);
5436
5437
5438
5439
5440
5441 for (cnt = 0; cnt < inodedep_hash; cnt++) {
5442 inodedephd = &inodedep_hashtbl[next++];
5443 if (next >= inodedep_hash)
5444 next = 0;
5445 if ((inodedep = LIST_FIRST(inodedephd)) != NULL)
5446 break;
5447 }
5448 if (inodedep == NULL) {
5449 FREE_LOCK(&lk);
5450 return;
5451 }
5452
5453
5454
5455 fs = inodedep->id_fs;
5456 CIRCLEQ_FOREACH(mp, &mountlist, mnt_list)
5457 if ((mp->mnt_flag & MNT_SOFTDEP) && fs == VFSTOUFS(mp)->um_fs)
5458 break;
5459
5460
5461
5462 firstino = inodedep->id_ino & ~(INOPB(fs) - 1);
5463 for (lastino = firstino + INOPB(fs) - 1; lastino > firstino; lastino--)
5464 if (inodedep_lookup(fs, lastino, 0, &inodedep) != 0)
5465 break;
5466
5467
5468
5469
5470
5471 for (ino = firstino; ino <= lastino; ino++) {
5472 if (inodedep_lookup(fs, ino, 0, &inodedep) == 0)
5473 continue;
5474 FREE_LOCK(&lk);
5475 #if 0
5476 if (vn_start_write(NULL, &mp, V_NOWAIT) != 0)
5477 continue;
5478 #endif
5479 if ((error = VFS_VGET(mp, ino, &vp)) != 0) {
5480 softdep_error("clear_inodedeps: vget", error);
5481 #if 0
5482 vn_finished_write(mp);
5483 #endif
5484 return;
5485 }
5486 if (ino == lastino) {
5487 if ((error = VOP_FSYNC(vp, p->p_ucred, MNT_WAIT, p)))
5488 softdep_error("clear_inodedeps: fsync1", error);
5489 } else {
5490 if ((error = VOP_FSYNC(vp, p->p_ucred, MNT_NOWAIT, p)))
5491 softdep_error("clear_inodedeps: fsync2", error);
5492 drain_output(vp, 0);
5493 }
5494 vput(vp);
5495 #if 0
5496 vn_finished_write(mp);
5497 #endif
5498 ACQUIRE_LOCK(&lk);
5499 }
5500 FREE_LOCK(&lk);
5501 }
5502
5503
5504
5505
5506
5507
5508 int
5509 softdep_count_dependencies(bp, wantcount, islocked)
5510 struct buf *bp;
5511 int wantcount;
5512 int islocked;
5513 {
5514 struct worklist *wk;
5515 struct inodedep *inodedep;
5516 struct indirdep *indirdep;
5517 struct allocindir *aip;
5518 struct pagedep *pagedep;
5519 struct diradd *dap;
5520 int i, retval;
5521
5522 retval = 0;
5523 if (!islocked)
5524 ACQUIRE_LOCK(&lk);
5525 LIST_FOREACH(wk, &bp->b_dep, wk_list) {
5526 switch (wk->wk_type) {
5527
5528 case D_INODEDEP:
5529 inodedep = WK_INODEDEP(wk);
5530 if ((inodedep->id_state & DEPCOMPLETE) == 0) {
5531
5532 retval += 1;
5533 if (!wantcount)
5534 goto out;
5535 }
5536 if (TAILQ_FIRST(&inodedep->id_inoupdt)) {
5537
5538 retval += 1;
5539 if (!wantcount)
5540 goto out;
5541 }
5542 continue;
5543
5544 case D_INDIRDEP:
5545 indirdep = WK_INDIRDEP(wk);
5546
5547 LIST_FOREACH(aip, &indirdep->ir_deplisthd, ai_next) {
5548
5549 retval += 1;
5550 if (!wantcount)
5551 goto out;
5552 }
5553 continue;
5554
5555 case D_PAGEDEP:
5556 pagedep = WK_PAGEDEP(wk);
5557 for (i = 0; i < DAHASHSZ; i++) {
5558
5559 LIST_FOREACH(dap, &pagedep->pd_diraddhd[i], da_pdlist) {
5560
5561 retval += 1;
5562 if (!wantcount)
5563 goto out;
5564 }
5565 }
5566 continue;
5567
5568 case D_BMSAFEMAP:
5569 case D_ALLOCDIRECT:
5570 case D_ALLOCINDIR:
5571 case D_MKDIR:
5572
5573 continue;
5574
5575 default:
5576 if (!islocked)
5577 FREE_LOCK(&lk);
5578 panic("softdep_check_for_rollback: Unexpected type %s",
5579 TYPENAME(wk->wk_type));
5580
5581 }
5582 }
5583 out:
5584 if (!islocked)
5585 FREE_LOCK(&lk);
5586 return retval;
5587 }
5588
5589
5590
5591
5592
5593
5594 STATIC int
5595 getdirtybuf(bp, waitfor)
5596 struct buf *bp;
5597 int waitfor;
5598 {
5599 int s;
5600
5601 if (bp == NULL)
5602 return (0);
5603
5604 splassert(IPL_BIO);
5605
5606 for (;;) {
5607 if ((bp->b_flags & B_BUSY) == 0)
5608 break;
5609 if (waitfor != MNT_WAIT)
5610 return (0);
5611 bp->b_flags |= B_WANTED;
5612 s = FREE_LOCK_INTERLOCKED(&lk);
5613 tsleep((caddr_t)bp, PRIBIO + 1, "sdsdty", 0);
5614 ACQUIRE_LOCK_INTERLOCKED(&lk, s);
5615 }
5616 if ((bp->b_flags & B_DELWRI) == 0)
5617 return (0);
5618 bremfree(bp);
5619 bp->b_flags |= B_BUSY;
5620 return (1);
5621 }
5622
5623
5624
5625
5626
5627 STATIC void
5628 drain_output(vp, islocked)
5629 struct vnode *vp;
5630 int islocked;
5631 {
5632 int s;
5633
5634 if (!islocked)
5635 ACQUIRE_LOCK(&lk);
5636
5637 splassert(IPL_BIO);
5638
5639 while (vp->v_numoutput) {
5640 vp->v_bioflag |= VBIOWAIT;
5641 s = FREE_LOCK_INTERLOCKED(&lk);
5642 tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "drain_output", 0);
5643 ACQUIRE_LOCK_INTERLOCKED(&lk, s);
5644 }
5645 if (!islocked)
5646 FREE_LOCK(&lk);
5647 }
5648
5649
5650
5651
5652
5653
5654 void
5655 softdep_deallocate_dependencies(bp)
5656 struct buf *bp;
5657 {
5658
5659 if ((bp->b_flags & B_ERROR) == 0)
5660 panic("softdep_deallocate_dependencies: dangling deps");
5661 softdep_error(bp->b_vp->v_mount->mnt_stat.f_mntonname, bp->b_error);
5662 panic("softdep_deallocate_dependencies: unrecovered I/O error");
5663 }
5664
5665
5666
5667
5668 void
5669 softdep_error(func, error)
5670 char *func;
5671 int error;
5672 {
5673
5674
5675 printf("%s: got error %d while accessing filesystem\n", func, error);
5676 }
5677
5678 #ifdef DDB
5679 #include <machine/db_machdep.h>
5680 #include <ddb/db_interface.h>
5681 #include <ddb/db_output.h>
5682
5683 void
5684 softdep_print(struct buf *bp, int full, int (*pr)(const char *, ...))
5685 {
5686 struct worklist *wk;
5687
5688 (*pr)(" deps:\n");
5689 LIST_FOREACH(wk, &bp->b_dep, wk_list)
5690 worklist_print(wk, full, pr);
5691 }
5692
5693 void
5694 worklist_print(struct worklist *wk, int full, int (*pr)(const char *, ...))
5695 {
5696 struct pagedep *pagedep;
5697 struct inodedep *inodedep;
5698 struct newblk *newblk;
5699 struct bmsafemap *bmsafemap;
5700 struct allocdirect *adp;
5701 struct indirdep *indirdep;
5702 struct allocindir *aip;
5703 struct freefrag *freefrag;
5704 struct freeblks *freeblks;
5705 struct freefile *freefile;
5706 struct diradd *dap;
5707 struct mkdir *mkdir;
5708 struct dirrem *dirrem;
5709 struct newdirblk *newdirblk;
5710 char prefix[33];
5711 int i;
5712
5713 for (prefix[i = 2 * MIN(16, full)] = '\0'; i--; prefix[i] = ' ')
5714 ;
5715
5716 (*pr)("%s%s(%p) state %b\n%s", prefix, TYPENAME(wk->wk_type), wk,
5717 wk->wk_state, DEP_BITS, prefix);
5718 switch (wk->wk_type) {
5719 case D_PAGEDEP:
5720 pagedep = WK_PAGEDEP(wk);
5721 (*pr)("mount %p ino %u lbn %lld\n", pagedep->pd_mnt,
5722 pagedep->pd_ino, pagedep->pd_lbn);
5723 break;
5724 case D_INODEDEP:
5725 inodedep = WK_INODEDEP(wk);
5726 (*pr)("fs %p ino %u nlinkdelta %u dino %p\n"
5727 "%s bp %p savsz %lld\n", inodedep->id_fs,
5728 inodedep->id_ino, inodedep->id_nlinkdelta,
5729 inodedep->id_un.idu_savedino1,
5730 prefix, inodedep->id_buf, inodedep->id_savedsize);
5731 break;
5732 case D_NEWBLK:
5733 newblk = WK_NEWBLK(wk);
5734 (*pr)("fs %p newblk %d state %d bmsafemap %p\n",
5735 newblk->nb_fs, newblk->nb_newblkno, newblk->nb_state,
5736 newblk->nb_bmsafemap);
5737 break;
5738 case D_BMSAFEMAP:
5739 bmsafemap = WK_BMSAFEMAP(wk);
5740 (*pr)("buf %p\n", bmsafemap->sm_buf);
5741 break;
5742 case D_ALLOCDIRECT:
5743 adp = WK_ALLOCDIRECT(wk);
5744 (*pr)("lbn %lld newlbk %d oldblk %d newsize %lu olsize %lu\n"
5745 "%s bp %p inodedep %p freefrag %p\n", adp->ad_lbn,
5746 adp->ad_newblkno, adp->ad_oldblkno, adp->ad_newsize,
5747 adp->ad_oldsize,
5748 prefix, adp->ad_buf, adp->ad_inodedep, adp->ad_freefrag);
5749 break;
5750 case D_INDIRDEP:
5751 indirdep = WK_INDIRDEP(wk);
5752 (*pr)("savedata %p savebp %p\n", indirdep->ir_saveddata,
5753 indirdep->ir_savebp);
5754 break;
5755 case D_ALLOCINDIR:
5756 aip = WK_ALLOCINDIR(wk);
5757 (*pr)("off %d newblk %d oldblk %d freefrag %p\n"
5758 "%s indirdep %p buf %p\n", aip->ai_offset,
5759 aip->ai_newblkno, aip->ai_oldblkno, aip->ai_freefrag,
5760 prefix, aip->ai_indirdep, aip->ai_buf);
5761 break;
5762 case D_FREEFRAG:
5763 freefrag = WK_FREEFRAG(wk);
5764 (*pr)("vnode %p mp %p blkno %d fsize %ld ino %u\n",
5765 freefrag->ff_devvp, freefrag->ff_mnt, freefrag->ff_blkno,
5766 freefrag->ff_fragsize, freefrag->ff_inum);
5767 break;
5768 case D_FREEBLKS:
5769 freeblks = WK_FREEBLKS(wk);
5770 (*pr)("previno %u devvp %p mp %p oldsz %lld newsz %lld\n"
5771 "%s chkcnt %d uid %d\n", freeblks->fb_previousinum,
5772 freeblks->fb_devvp, freeblks->fb_mnt, freeblks->fb_oldsize,
5773 freeblks->fb_newsize,
5774 prefix, freeblks->fb_chkcnt, freeblks->fb_uid);
5775 break;
5776 case D_FREEFILE:
5777 freefile = WK_FREEFILE(wk);
5778 (*pr)("mode %x oldino %u vnode %p mp %p\n", freefile->fx_mode,
5779 freefile->fx_oldinum, freefile->fx_devvp, freefile->fx_mnt);
5780 break;
5781 case D_DIRADD:
5782 dap = WK_DIRADD(wk);
5783 (*pr)("off %ld ino %u da_un %p\n", dap->da_offset,
5784 dap->da_newinum, dap->da_un.dau_previous);
5785 break;
5786 case D_MKDIR:
5787 mkdir = WK_MKDIR(wk);
5788 (*pr)("diradd %p bp %p\n", mkdir->md_diradd, mkdir->md_buf);
5789 break;
5790 case D_DIRREM:
5791 dirrem = WK_DIRREM(wk);
5792 (*pr)("mp %p ino %u dm_un %p\n", dirrem->dm_mnt,
5793 dirrem->dm_oldinum, dirrem->dm_un.dmu_pagedep);
5794 break;
5795 case D_NEWDIRBLK:
5796 newdirblk = WK_NEWDIRBLK(wk);
5797 (*pr)("pagedep %p\n", newdirblk->db_pagedep);
5798 break;
5799 }
5800 }
5801 #endif