STATIC	struct freefrag *newfreefrag __P((struct inode *, ufs_daddr_t, long)); STATIC	void allocdirect_merge __P((struct allocdirectlst *, struct allocdirect *, struct allocdirect *)); STATIC	struct bmsafemap *bmsafemap_lookup __P((struct buf *)); STATIC	int newblk_lookup __P((struct fs *, ufs_daddr_t, int, struct newblk **)); STATIC	int inodedep_lookup __P((struct fs *, ino_t, int, struct inodedep **)); STATIC	int pagedep_lookup __P((struct inode *, ufs_lbn_t, int, struct pagedep **)); STATIC	void pause_timer __P((void *)); STATIC	int request_cleanup __P((int, int)); STATIC	int process_worklist_item __P((struct mount *, int)); STATIC	void add_to_worklist __P((struct worklist *));   void softdep_disk_io_initiation __P((struct buf *)); void softdep_disk_write_complete __P((struct buf *)); void softdep_deallocate_dependencies __P((struct buf *)); void softdep_move_dependencies __P((struct buf *, struct buf *)); int softdep_count_dependencies __P((struct buf *bp, int, int));  struct bio_ops bioops = { softdep_disk_io_initiation,		 softdep_disk_write_complete,		 softdep_deallocate_dependencies,	 softdep_move_dependencies,		 softdep_count_dependencies,		 };   #ifndef  DEBUG STATIC struct lockit { int	lkt_spl; } lk = { 0 }; #define ACQUIRE_LOCK(lk)		(lk)->lkt_spl = splbio() #define FREE_LOCK(lk)			splx((lk)->lkt_spl) #define ACQUIRE_LOCK_INTERLOCKED(lk,s)	(lk)->lkt_spl = (s) #define FREE_LOCK_INTERLOCKED(lk)	((lk)->lkt_spl)  #else  STATIC struct lockit { int	lkt_spl; pid_t	lkt_held; int     lkt_line; } lk = { 0, -1 }; STATIC int lockcnt;  STATIC	void acquire_lock __P((struct lockit *, int)); STATIC	void free_lock __P((struct lockit *, int)); STATIC	void acquire_lock_interlocked __P((struct lockit *, int, int)); STATIC	int free_lock_interlocked __P((struct lockit *, int));  #define ACQUIRE_LOCK(lk)		acquire_lock(lk, __LINE__) #define FREE_LOCK(lk)			free_lock(lk, __LINE__) #define ACQUIRE_LOCK_INTERLOCKED(lk,s)	acquire_lock_interlocked(lk, (s), __LINE__) #define FREE_LOCK_INTERLOCKED(lk)	free_lock_interlocked(lk, __LINE__)  STATIC void acquire_lock(lk, line) struct lockit *lk; int line; { pid_t holder; int original_line;  if (lk->lkt_held != -1) { holder = lk->lkt_held; original_line = lk->lkt_line; FREE_LOCK(lk); if (holder == CURPROC->p_pid) panic("softdep_lock: locking against myself, acquired at line %d, relocked at line %d", original_line, line); else panic("softdep_lock: lock held by %d, acquired at line %d, relocked at line %d", holder, original_line, line); } lk->lkt_spl = splbio(); lk->lkt_held = CURPROC->p_pid; lk->lkt_line = line; lockcnt++; }  STATIC void free_lock(lk, line) struct lockit *lk; int line; {  if (lk->lkt_held == -1) panic("softdep_unlock: lock not held at line %d", line); lk->lkt_held = -1; splx(lk->lkt_spl); }  STATIC void acquire_lock_interlocked(lk, s, line) struct lockit *lk; int s; int line; { pid_t holder; int original_line;  if (lk->lkt_held != -1) { holder = lk->lkt_held; original_line = lk->lkt_line; FREE_LOCK_INTERLOCKED(lk); if (holder == CURPROC->p_pid) panic("softdep_lock: locking against myself, acquired at line %d, relocked at line %d", original_line, line); else panic("softdep_lock: lock held by %d, acquired at line %d, relocked at line %d", holder, original_line, line); } lk->lkt_held = CURPROC->p_pid; lk->lkt_line = line; lk->lkt_spl = s; lockcnt++; }  STATIC int free_lock_interlocked(lk, line) struct lockit *lk; int line; {  if (lk->lkt_held == -1) panic("softdep_unlock_interlocked: lock not held at line %d", line); lk->lkt_held = -1;  return (lk->lkt_spl); } #endif    struct sema { int	value; pid_t	holder; char	*name; int	prio; int	timo; }; STATIC	void sema_init __P((struct sema *, char *, int, int)); STATIC	int sema_get __P((struct sema *, struct lockit *)); STATIC	void sema_release __P((struct sema *));  STATIC void sema_init(semap, name, prio, timo) struct sema *semap; char *name; int prio, timo; {  semap->holder = -1; semap->value = 0; semap->name = name; semap->prio = prio; semap->timo = timo; }  STATIC int sema_get(semap, interlock) struct sema *semap; struct lockit *interlock; { int s;  if (semap->value++ > 0) { if (interlock != NULL) s = FREE_LOCK_INTERLOCKED(interlock); tsleep((caddr_t)semap, semap->prio, semap->name, semap->timo); if (interlock != NULL) { ACQUIRE_LOCK_INTERLOCKED(interlock, s); FREE_LOCK(interlock); } return (0); } semap->holder = CURPROC->p_pid; if (interlock != NULL) FREE_LOCK(interlock); return (1); }  STATIC void sema_release(semap) struct sema *semap; {  if (semap->value <= 0 || semap->holder != CURPROC->p_pid) { #ifdef DEBUG if (lk.lkt_held != -1) FREE_LOCK(&lk); #endif panic("sema_release: not held"); } if (--semap->value > 0) { semap->value = 0; wakeup(semap); } semap->holder = -1; }   #ifndef  DEBUG #define WORKLIST_INSERT(head, item) do {	\ (item)->wk_state |= ONWORKLIST;		\ LIST_INSERT_HEAD(head, item, wk_list);	\ } while (0) #define WORKLIST_REMOVE(item) do {		\ (item)->wk_state &= ~ONWORKLIST;	\ LIST_REMOVE(item, wk_list);		\ } while (0) #define WORKITEM_FREE(item, type) FREE(item, DtoM(type))  #else  STATIC	void worklist_insert __P((struct workhead *, struct worklist *)); STATIC	void worklist_remove __P((struct worklist *)); STATIC	void workitem_free __P((struct worklist *, int));  #define WORKLIST_INSERT(head, item) worklist_insert(head, item) #define WORKLIST_REMOVE(item) worklist_remove(item) #define WORKITEM_FREE(item, type) workitem_free((struct worklist *)item, type)  STATIC void worklist_insert(head, item) struct workhead *head; struct worklist *item; {  if (lk.lkt_held == -1) panic("worklist_insert: lock not held"); if (item->wk_state & ONWORKLIST) { FREE_LOCK(&lk); panic("worklist_insert: already on list"); } item->wk_state |= ONWORKLIST; LIST_INSERT_HEAD(head, item, wk_list); }  STATIC void worklist_remove(item) struct worklist *item; {  if (lk.lkt_held == -1) panic("worklist_remove: lock not held"); if ((item->wk_state & ONWORKLIST) == 0) { FREE_LOCK(&lk); panic("worklist_remove: not on list"); } item->wk_state &= ~ONWORKLIST; LIST_REMOVE(item, wk_list); }  STATIC void workitem_free(item, type) struct worklist *item; int type; {  if (item->wk_state & ONWORKLIST) { if (lk.lkt_held != -1) FREE_LOCK(&lk); panic("workitem_free: still on list"); } if (item->wk_type != type) { if (lk.lkt_held != -1) FREE_LOCK(&lk); panic("workitem_free: type mismatch"); } FREE(item, DtoM(type)); } #endif    STATIC struct workhead softdep_workitem_pending; STATIC int num_on_worklist;	 STATIC int softdep_worklist_busy;  STATIC int softdep_worklist_req;  STATIC int max_softdeps;	 STATIC int tickdelay = 2;	 STATIC int proc_waiting;	 STATIC int *stat_countp;	 STATIC struct timeout proc_waiting_timeout; STATIC struct proc *filesys_syncer;  STATIC int req_clear_inodedeps;	 #define FLUSH_INODES	1 STATIC int req_clear_remove;	 #define FLUSH_REMOVE	2  STATIC int stat_worklist_push;	 STATIC int stat_blk_limit_push;	 STATIC int stat_ino_limit_push;	 STATIC int stat_blk_limit_hit;	 STATIC int stat_ino_limit_hit;	 STATIC int stat_sync_limit_hit;	 STATIC int stat_indir_blk_ptrs;	 STATIC int stat_inode_bitmap;	 STATIC int stat_direct_blk_ptrs; STATIC int stat_dir_entry;	 #ifdef DEBUG #include <uvm/uvm_extern.h> #include <sys/sysctl.h> struct ctldebug debug20 = { "max_softdeps", &max_softdeps }; struct ctldebug debug21 = { "tickdelay", &tickdelay }; struct ctldebug debug22 = { "worklist_push", &stat_worklist_push }; struct ctldebug debug23 = { "blk_limit_push", &stat_blk_limit_push }; struct ctldebug debug24 = { "ino_limit_push", &stat_ino_limit_push }; struct ctldebug debug25 = { "blk_limit_hit", &stat_blk_limit_hit }; struct ctldebug debug26 = { "ino_limit_hit", &stat_ino_limit_hit }; struct ctldebug debug27 = { "sync_limit_hit", &stat_sync_limit_hit }; struct ctldebug debug28 = { "indir_blk_ptrs", &stat_indir_blk_ptrs }; struct ctldebug debug29 = { "inode_bitmap", &stat_inode_bitmap }; struct ctldebug debug30 = { "direct_blk_ptrs", &stat_direct_blk_ptrs }; struct ctldebug debug31 = { "dir_entry", &stat_dir_entry }; #endif    STATIC void add_to_worklist(wk) struct worklist *wk; { static struct worklist *worklist_tail;  if (wk->wk_state & ONWORKLIST) { #ifdef DEBUG if (lk.lkt_held != -1) FREE_LOCK(&lk); #endif panic("add_to_worklist: already on list"); } wk->wk_state |= ONWORKLIST; if (LIST_FIRST(&softdep_workitem_pending) == NULL) LIST_INSERT_HEAD(&softdep_workitem_pending, wk, wk_list); else LIST_INSERT_AFTER(worklist_tail, wk, wk_list); worklist_tail = wk; num_on_worklist += 1; }   int softdep_process_worklist(matchmnt) struct mount *matchmnt; { struct proc *p = CURPROC; int matchcnt, loopcount; struct timeval starttime;   filesys_syncer = syncerproc; matchcnt = 0;   if (matchmnt == NULL) { if (softdep_worklist_busy < 0) return(-1); softdep_worklist_busy += 1; }   if (req_clear_inodedeps) { clear_inodedeps(p); req_clear_inodedeps -= 1; wakeup_one(&proc_waiting); } if (req_clear_remove) { clear_remove(p); req_clear_remove -= 1; wakeup_one(&proc_waiting); } loopcount = 1; starttime = time; while (num_on_worklist > 0) { matchcnt += process_worklist_item(matchmnt, 0);   if (softdep_worklist_req && matchmnt == NULL) { matchcnt = -1; break; }   if (req_clear_inodedeps) { clear_inodedeps(p); req_clear_inodedeps -= 1; wakeup_one(&proc_waiting); } if (req_clear_remove) { clear_remove(p); req_clear_remove -= 1; wakeup_one(&proc_waiting); }  #if 0 if (loopcount++ % 128 == 0) bwillwrite(); #endif  { struct timeval diff;  timersub(&time, &starttime, &diff); if (diff.tv_sec != 0 && matchmnt == NULL) { matchcnt = -1; break; } } } if (matchmnt == NULL) { softdep_worklist_busy -= 1; if (softdep_worklist_req && softdep_worklist_busy == 0) wakeup(&softdep_worklist_req); } return (matchcnt); }   STATIC int process_worklist_item(matchmnt, flags) struct mount *matchmnt; int flags; { struct worklist *wk; struct dirrem *dirrem; struct mount *mp; struct vnode *vp; int matchcnt = 0;  ACQUIRE_LOCK(&lk);  LIST_FOREACH(wk, &softdep_workitem_pending, wk_list) { if ((flags & LK_NOWAIT) == 0 || wk->wk_type != D_DIRREM) break; dirrem = WK_DIRREM(wk); vp = ufs_ihashlookup(VFSTOUFS(dirrem->dm_mnt)->um_dev, dirrem->dm_oldinum); if (vp == NULL || !VOP_ISLOCKED(vp)) break; } if (wk == 0) { FREE_LOCK(&lk); return (0); } WORKLIST_REMOVE(wk); num_on_worklist -= 1; FREE_LOCK(&lk); switch (wk->wk_type) {  case D_DIRREM:  mp = WK_DIRREM(wk)->dm_mnt; #if 0 if (vn_write_suspend_wait(NULL, mp, V_NOWAIT)) panic("%s: dirrem on suspended filesystem", "process_worklist_item"); #endif if (mp == matchmnt) matchcnt += 1; handle_workitem_remove(WK_DIRREM(wk)); break;  case D_FREEBLKS:  mp = WK_FREEBLKS(wk)->fb_mnt; #if 0 if (vn_write_suspend_wait(NULL, mp, V_NOWAIT)) panic("%s: freeblks on suspended filesystem", "process_worklist_item"); #endif if (mp == matchmnt) matchcnt += 1; handle_workitem_freeblocks(WK_FREEBLKS(wk)); break;  case D_FREEFRAG:  mp = WK_FREEFRAG(wk)->ff_mnt; #if 0 if (vn_write_suspend_wait(NULL, mp, V_NOWAIT)) panic("%s: freefrag on suspended filesystem", "process_worklist_item"); #endif if (mp == matchmnt) matchcnt += 1; handle_workitem_freefrag(WK_FREEFRAG(wk)); break;  case D_FREEFILE:  mp = WK_FREEFILE(wk)->fx_mnt; #if 0 if (vn_write_suspend_wait(NULL, mp, V_NOWAIT)) panic("%s: freefile on suspended filesystem", "process_worklist_item"); #endif if (mp == matchmnt) matchcnt += 1; handle_workitem_freefile(WK_FREEFILE(wk)); break;  default: panic("%s_process_worklist: Unknown type %s", "softdep", TYPENAME(wk->wk_type));  } return (matchcnt); }   void softdep_move_dependencies(oldbp, newbp) struct buf *oldbp; struct buf *newbp; { struct worklist *wk, *wktail;  if (LIST_FIRST(&newbp->b_dep) != NULL) panic("softdep_move_dependencies: need merge code"); wktail = 0; ACQUIRE_LOCK(&lk); while ((wk = LIST_FIRST(&oldbp->b_dep)) != NULL) { LIST_REMOVE(wk, wk_list); if (wktail == 0) LIST_INSERT_HEAD(&newbp->b_dep, wk, wk_list); else LIST_INSERT_AFTER(wktail, wk, wk_list); wktail = wk; } FREE_LOCK(&lk); }   int softdep_flushworklist(oldmnt, countp, p) struct mount *oldmnt; int *countp; struct proc *p; { struct vnode *devvp; int count, error = 0;   while (softdep_worklist_busy) { softdep_worklist_req += 1; tsleep(&softdep_worklist_req, PRIBIO, "softflush", 0); softdep_worklist_req -= 1; } softdep_worklist_busy = -1;  *countp = 0; devvp = VFSTOUFS(oldmnt)->um_devvp; while ((count = softdep_process_worklist(oldmnt)) > 0) { *countp += count; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); error = VOP_FSYNC(devvp, p->p_ucred, MNT_WAIT, p); VOP_UNLOCK(devvp, 0, p); if (error) break; } softdep_worklist_busy = 0; if (softdep_worklist_req) wakeup(&softdep_worklist_req); return (error); }   int softdep_flushfiles(oldmnt, flags, p) struct mount *oldmnt; int flags; struct proc *p; { int error, count, loopcnt;   for (loopcnt = 10; loopcnt > 0; loopcnt--) {  if ((error = ffs_flushfiles(oldmnt, flags, p)) != 0) break; if ((error = softdep_flushworklist(oldmnt, &count, p)) != 0 || count == 0) break; }  if (loopcnt == 0) { if (oldmnt->mnt_flag & MNT_UNMOUNT) panic("softdep_flushfiles: looping"); error = EBUSY; } return (error); }   #define DEPALLOC	0x0001	 #define NODELAY         0x0002     LIST_HEAD(pagedep_hashhead, pagedep) *pagedep_hashtbl; u_long	pagedep_hash;		 #define	PAGEDEP_HASH(mp, inum, lbn) \ (&pagedep_hashtbl[((((register_t)(mp)) >> 13) + (inum) + (lbn)) & \ pagedep_hash]) STATIC struct sema pagedep_in_progress;   STATIC int pagedep_lookup(ip, lbn, flags, pagedeppp) struct inode *ip; ufs_lbn_t lbn; int flags; struct pagedep **pagedeppp; { struct pagedep *pagedep; struct pagedep_hashhead *pagedephd; struct mount *mp; int i;  #ifdef DEBUG if (lk.lkt_held == -1) panic("pagedep_lookup: lock not held"); #endif mp = ITOV(ip)->v_mount; pagedephd = PAGEDEP_HASH(mp, ip->i_number, lbn); top: LIST_FOREACH(pagedep, pagedephd, pd_hash) if (ip->i_number == pagedep->pd_ino && lbn == pagedep->pd_lbn && mp == pagedep->pd_mnt) break; if (pagedep) { *pagedeppp = pagedep; return (1); } if ((flags & DEPALLOC) == 0) { *pagedeppp = NULL; return (0); } if (sema_get(&pagedep_in_progress, &lk) == 0) { ACQUIRE_LOCK(&lk); goto top; } MALLOC(pagedep, struct pagedep *, sizeof(struct pagedep), M_PAGEDEP, M_SOFTDEP_FLAGS); bzero(pagedep, sizeof(struct pagedep)); pagedep->pd_list.wk_type = D_PAGEDEP; pagedep->pd_mnt = mp; pagedep->pd_ino = ip->i_number; pagedep->pd_lbn = lbn; LIST_INIT(&pagedep->pd_dirremhd); LIST_INIT(&pagedep->pd_pendinghd); for (i = 0; i < DAHASHSZ; i++) LIST_INIT(&pagedep->pd_diraddhd[i]); ACQUIRE_LOCK(&lk); LIST_INSERT_HEAD(pagedephd, pagedep, pd_hash); sema_release(&pagedep_in_progress); *pagedeppp = pagedep; return (0); }   LIST_HEAD(inodedep_hashhead, inodedep) *inodedep_hashtbl; STATIC u_long	inodedep_hash;	 STATIC long	num_inodedep;	 #define	INODEDEP_HASH(fs, inum) \ (&inodedep_hashtbl[((((register_t)(fs)) >> 13) + (inum)) & inodedep_hash]) STATIC struct sema inodedep_in_progress;   STATIC int inodedep_lookup(fs, inum, flags, inodedeppp) struct fs *fs; ino_t inum; int flags; struct inodedep **inodedeppp; { struct inodedep *inodedep; struct inodedep_hashhead *inodedephd; int firsttry;  #ifdef DEBUG if (lk.lkt_held == -1) panic("inodedep_lookup: lock not held"); #endif firsttry = 1; inodedephd = INODEDEP_HASH(fs, inum); top: LIST_FOREACH(inodedep, inodedephd, id_hash) if (inum == inodedep->id_ino && fs == inodedep->id_fs) break; if (inodedep) { *inodedeppp = inodedep; return (1); } if ((flags & DEPALLOC) == 0) { *inodedeppp = NULL; return (0); }  if (num_inodedep > max_softdeps && firsttry && (flags & NODELAY) == 0 && request_cleanup(FLUSH_INODES, 1)) { firsttry = 0; goto top; } if (sema_get(&inodedep_in_progress, &lk) == 0) { ACQUIRE_LOCK(&lk); goto top; } num_inodedep += 1; MALLOC(inodedep, struct inodedep *, sizeof(struct inodedep), M_INODEDEP, M_SOFTDEP_FLAGS); inodedep->id_list.wk_type = D_INODEDEP; inodedep->id_fs = fs; inodedep->id_ino = inum; inodedep->id_state = ALLCOMPLETE; inodedep->id_nlinkdelta = 0; inodedep->id_savedino = NULL; inodedep->id_savedsize = -1; inodedep->id_buf = NULL; LIST_INIT(&inodedep->id_pendinghd); LIST_INIT(&inodedep->id_inowait); LIST_INIT(&inodedep->id_bufwait); TAILQ_INIT(&inodedep->id_inoupdt); TAILQ_INIT(&inodedep->id_newinoupdt); ACQUIRE_LOCK(&lk); LIST_INSERT_HEAD(inodedephd, inodedep, id_hash); sema_release(&inodedep_in_progress); *inodedeppp = inodedep; return (0); }   LIST_HEAD(newblk_hashhead, newblk) *newblk_hashtbl; u_long	newblk_hash;		 #define	NEWBLK_HASH(fs, inum) \ (&newblk_hashtbl[((((register_t)(fs)) >> 13) + (inum)) & newblk_hash]) STATIC struct sema newblk_in_progress;   STATIC int newblk_lookup(fs, newblkno, flags, newblkpp) struct fs *fs; ufs_daddr_t newblkno; int flags; struct newblk **newblkpp; { struct newblk *newblk; struct newblk_hashhead *newblkhd;  newblkhd = NEWBLK_HASH(fs, newblkno); top: LIST_FOREACH(newblk, newblkhd, nb_hash) if (newblkno == newblk->nb_newblkno && fs == newblk->nb_fs) break; if (newblk) { *newblkpp = newblk; return (1); } if ((flags & DEPALLOC) == 0) { *newblkpp = NULL; return (0); } if (sema_get(&newblk_in_progress, 0) == 0) goto top; MALLOC(newblk, struct newblk *, sizeof(struct newblk), M_NEWBLK, M_SOFTDEP_FLAGS); newblk->nb_state = 0; newblk->nb_fs = fs; newblk->nb_newblkno = newblkno; LIST_INSERT_HEAD(newblkhd, newblk, nb_hash); sema_release(&newblk_in_progress); *newblkpp = newblk; return (0); }   void softdep_initialize() {  LIST_INIT(&mkdirlisthd); LIST_INIT(&softdep_workitem_pending); #ifdef KMEMSTATS max_softdeps = min (desiredvnodes * 8, kmemstats[M_INODEDEP].ks_limit / (2 * sizeof(struct inodedep))); #else max_softdeps = desiredvnodes * 4; #endif pagedep_hashtbl = hashinit(desiredvnodes / 5, M_PAGEDEP, M_WAITOK, &pagedep_hash); sema_init(&pagedep_in_progress, "pagedep", PRIBIO, 0); inodedep_hashtbl = hashinit(desiredvnodes, M_INODEDEP, M_WAITOK, &inodedep_hash); sema_init(&inodedep_in_progress, "inodedep", PRIBIO, 0); newblk_hashtbl = hashinit(64, M_NEWBLK, M_WAITOK, &newblk_hash); sema_init(&newblk_in_progress, "newblk", PRIBIO, 0); timeout_set(&proc_waiting_timeout, pause_timer, 0); }   int softdep_mount(devvp, mp, fs, cred) struct vnode *devvp; struct mount *mp; struct fs *fs; struct ucred *cred; { struct csum cstotal; struct cg *cgp; struct buf *bp; int error, cyl;   if ((fs->fs_flags & FS_UNCLEAN) == 0) return (0); bzero(&cstotal, sizeof cstotal); for (cyl = 0; cyl < fs->fs_ncg; cyl++) { if ((error = bread(devvp, fsbtodb(fs, cgtod(fs, cyl)), fs->fs_cgsize, cred, &bp)) != 0) { brelse(bp); return (error); } cgp = (struct cg *)bp->b_data; cstotal.cs_nffree += cgp->cg_cs.cs_nffree; cstotal.cs_nbfree += cgp->cg_cs.cs_nbfree; cstotal.cs_nifree += cgp->cg_cs.cs_nifree; cstotal.cs_ndir += cgp->cg_cs.cs_ndir; fs->fs_cs(fs, cyl) = cgp->cg_cs; brelse(bp); } #ifdef DEBUG if (bcmp(&cstotal, &fs->fs_cstotal, sizeof cstotal)) printf("ffs_mountfs: superblock updated for soft updates\n"); #endif bcopy(&cstotal, &fs->fs_cstotal, sizeof cstotal); return (0); }     void softdep_setup_inomapdep(bp, ip, newinum) struct buf *bp;		 struct inode *ip;	 ino_t newinum;		 { struct inodedep *inodedep; struct bmsafemap *bmsafemap;   ACQUIRE_LOCK(&lk); if (inodedep_lookup(ip->i_fs, newinum, DEPALLOC | NODELAY, &inodedep) != 0) { FREE_LOCK(&lk); panic("softdep_setup_inomapdep: found inode"); } inodedep->id_buf = bp; inodedep->id_state &= ~DEPCOMPLETE; bmsafemap = bmsafemap_lookup(bp); LIST_INSERT_HEAD(&bmsafemap->sm_inodedephd, inodedep, id_deps); FREE_LOCK(&lk); }   void softdep_setup_blkmapdep(bp, fs, newblkno) struct buf *bp;		 struct fs *fs;		 ufs_daddr_t newblkno;	 { struct newblk *newblk; struct bmsafemap *bmsafemap;   if (newblk_lookup(fs, newblkno, DEPALLOC, &newblk) != 0) panic("softdep_setup_blkmapdep: found block"); ACQUIRE_LOCK(&lk); newblk->nb_bmsafemap = bmsafemap = bmsafemap_lookup(bp); LIST_INSERT_HEAD(&bmsafemap->sm_newblkhd, newblk, nb_deps); FREE_LOCK(&lk); }   STATIC struct bmsafemap * bmsafemap_lookup(bp) struct buf *bp; { struct bmsafemap *bmsafemap; struct worklist *wk;  #ifdef DEBUG if (lk.lkt_held == -1) panic("bmsafemap_lookup: lock not held"); #endif LIST_FOREACH(wk, &bp->b_dep, wk_list) if (wk->wk_type == D_BMSAFEMAP) return (WK_BMSAFEMAP(wk)); FREE_LOCK(&lk); MALLOC(bmsafemap, struct bmsafemap *, sizeof(struct bmsafemap), M_BMSAFEMAP, M_SOFTDEP_FLAGS); bmsafemap->sm_list.wk_type = D_BMSAFEMAP; bmsafemap->sm_list.wk_state = 0; bmsafemap->sm_buf = bp; LIST_INIT(&bmsafemap->sm_allocdirecthd); LIST_INIT(&bmsafemap->sm_allocindirhd); LIST_INIT(&bmsafemap->sm_inodedephd); LIST_INIT(&bmsafemap->sm_newblkhd); ACQUIRE_LOCK(&lk); WORKLIST_INSERT(&bp->b_dep, &bmsafemap->sm_list); return (bmsafemap); }   void softdep_setup_allocdirect(ip, lbn, newblkno, oldblkno, newsize, oldsize, bp) struct inode *ip;	 ufs_lbn_t lbn;		 ufs_daddr_t newblkno;	 ufs_daddr_t oldblkno;	 long newsize;		 long oldsize;		 struct buf *bp;		 { struct allocdirect *adp, *oldadp; struct allocdirectlst *adphead; struct bmsafemap *bmsafemap; struct inodedep *inodedep; struct pagedep *pagedep; struct newblk *newblk;  MALLOC(adp, struct allocdirect *, sizeof(struct allocdirect), M_ALLOCDIRECT, M_SOFTDEP_FLAGS); bzero(adp, sizeof(struct allocdirect)); adp->ad_list.wk_type = D_ALLOCDIRECT; adp->ad_lbn = lbn; adp->ad_newblkno = newblkno; adp->ad_oldblkno = oldblkno; adp->ad_newsize = newsize; adp->ad_oldsize = oldsize; adp->ad_state = ATTACHED; if (newblkno == oldblkno) adp->ad_freefrag = NULL; else adp->ad_freefrag = newfreefrag(ip, oldblkno, oldsize);  if (newblk_lookup(ip->i_fs, newblkno, 0, &newblk) == 0) panic("softdep_setup_allocdirect: lost block");  ACQUIRE_LOCK(&lk); inodedep_lookup(ip->i_fs, ip->i_number, DEPALLOC | NODELAY, &inodedep); adp->ad_inodedep = inodedep;  if (newblk->nb_state == DEPCOMPLETE) { adp->ad_state |= DEPCOMPLETE; adp->ad_buf = NULL; } else { bmsafemap = newblk->nb_bmsafemap; adp->ad_buf = bmsafemap->sm_buf; LIST_REMOVE(newblk, nb_deps); LIST_INSERT_HEAD(&bmsafemap->sm_allocdirecthd, adp, ad_deps); } LIST_REMOVE(newblk, nb_hash); FREE(newblk, M_NEWBLK);  if (bp == NULL) {  panic("softdep_setup_allocdirect: Bonk art in the head\n"); } WORKLIST_INSERT(&bp->b_dep, &adp->ad_list); if (lbn >= NDADDR) {  if (oldblkno != 0) { FREE_LOCK(&lk); panic("softdep_setup_allocdirect: non-zero indir"); } } else {  if ((ip->i_ffs_mode & IFMT) == IFDIR && pagedep_lookup(ip, lbn, DEPALLOC, &pagedep) == 0) WORKLIST_INSERT(&bp->b_dep, &pagedep->pd_list); }  adphead = &inodedep->id_newinoupdt; oldadp = TAILQ_LAST(adphead, allocdirectlst); if (oldadp == NULL || oldadp->ad_lbn <= lbn) {  TAILQ_INSERT_TAIL(adphead, adp, ad_next); if (oldadp != NULL && oldadp->ad_lbn == lbn) allocdirect_merge(adphead, adp, oldadp); FREE_LOCK(&lk); return; } TAILQ_FOREACH(oldadp, adphead, ad_next) { if (oldadp->ad_lbn >= lbn) break; } if (oldadp == NULL) { FREE_LOCK(&lk); panic("softdep_setup_allocdirect: lost entry"); }  TAILQ_INSERT_BEFORE(oldadp, adp, ad_next); if (oldadp->ad_lbn == lbn) allocdirect_merge(adphead, adp, oldadp); FREE_LOCK(&lk); }   STATIC void allocdirect_merge(adphead, newadp, oldadp) struct allocdirectlst *adphead;	 struct allocdirect *newadp;	 struct allocdirect *oldadp;	 { struct freefrag *freefrag;  #ifdef DEBUG if (lk.lkt_held == -1) panic("allocdirect_merge: lock not held"); #endif if (newadp->ad_oldblkno != oldadp->ad_newblkno || newadp->ad_oldsize != oldadp->ad_newsize || newadp->ad_lbn >= NDADDR) { FREE_LOCK(&lk); panic("allocdirect_check: old %d != new %d || lbn %ld >= %d", newadp->ad_oldblkno, oldadp->ad_newblkno, newadp->ad_lbn, NDADDR); } newadp->ad_oldblkno = oldadp->ad_oldblkno; newadp->ad_oldsize = oldadp->ad_oldsize;  if (oldadp->ad_freefrag != NULL || oldadp->ad_oldblkno == 0) { freefrag = newadp->ad_freefrag; newadp->ad_freefrag = oldadp->ad_freefrag; oldadp->ad_freefrag = freefrag; } free_allocdirect(adphead, oldadp, 0); }   STATIC struct freefrag *
newfreefrag(ip, blkno, size)	struct inode *ip;	ufs_daddr_t blkno;	long size;{	struct freefrag *freefrag;	struct fs *fs;	if (blkno == 0)		return (NULL);	fs = ip->i_fs;	if (fragnum(fs, blkno) + numfrags(fs, size) > fs->fs_frag)		panic("newfreefrag: frag size");	MALLOC(freefrag, struct freefrag *, sizeof(struct freefrag),		M_FREEFRAG, M_SOFTDEP_FLAGS);	freefrag->ff_list.wk_type = D_FREEFRAG;	freefrag->ff_state = ip->i_ffs_uid & ~ONWORKLIST; /* XXX - used below */	freefrag->ff_inum = ip->i_number;	freefrag->ff_mnt = ITOV(ip)->v_mount;	freefrag->ff_devvp = ip->i_devvp;	freefrag->ff_blkno = blkno;	freefrag->ff_fragsize = size;	return (freefrag);}