xref: /original-bsd/sys/ufs/lfs/lfs_subr.c (revision b3c06cab)
1 /*
2  * Copyright (c) 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)lfs_subr.c	8.4 (Berkeley) 05/08/95
8  */
9 
10 #include <sys/param.h>
11 #include <sys/namei.h>
12 #include <sys/vnode.h>
13 #include <sys/buf.h>
14 #include <sys/mount.h>
15 #include <sys/malloc.h>
16 #include <sys/proc.h>
17 
18 #include <ufs/ufs/quota.h>
19 #include <ufs/ufs/inode.h>
20 #include <ufs/lfs/lfs.h>
21 #include <ufs/lfs/lfs_extern.h>
22 
23 /*
24  * Return buffer with the contents of block "offset" from the beginning of
25  * directory "ip".  If "res" is non-zero, fill it in with a pointer to the
26  * remaining space in the directory.
27  */
28 int
29 lfs_blkatoff(ap)
30 	struct vop_blkatoff_args /* {
31 		struct vnode *a_vp;
32 		off_t a_offset;
33 		char **a_res;
34 		struct buf **a_bpp;
35 	} */ *ap;
36 {
37 	register struct lfs *fs;
38 	struct inode *ip;
39 	struct buf *bp;
40 	ufs_daddr_t lbn;
41 	int bsize, error;
42 
43 	ip = VTOI(ap->a_vp);
44 	fs = ip->i_lfs;
45 	lbn = lblkno(fs, ap->a_offset);
46 	bsize = blksize(fs, ip, lbn);
47 
48 	*ap->a_bpp = NULL;
49 	if (error = bread(ap->a_vp, lbn, bsize, NOCRED, &bp)) {
50 		brelse(bp);
51 		return (error);
52 	}
53 	if (ap->a_res)
54 		*ap->a_res = (char *)bp->b_data + blkoff(fs, ap->a_offset);
55 	*ap->a_bpp = bp;
56 	return (0);
57 }
58 
59 
60 /*
61  * lfs_seglock --
62  *	Single thread the segment writer.
63  */
64 void
65 lfs_seglock(fs, flags)
66 	struct lfs *fs;
67 	unsigned long flags;
68 {
69 	struct segment *sp;
70 	int s;
71 
72 	if (fs->lfs_seglock)
73 		if (fs->lfs_lockpid == curproc->p_pid) {
74 			++fs->lfs_seglock;
75 			fs->lfs_sp->seg_flags |= flags;
76 			return;
77 		} else while (fs->lfs_seglock)
78 			(void)tsleep(&fs->lfs_seglock, PRIBIO + 1,
79 			    "lfs seglock", 0);
80 
81 	fs->lfs_seglock = 1;
82 	fs->lfs_lockpid = curproc->p_pid;
83 
84 	sp = fs->lfs_sp = malloc(sizeof(struct segment), M_SEGMENT, M_WAITOK);
85 	sp->bpp = malloc(((LFS_SUMMARY_SIZE - sizeof(SEGSUM)) /
86 	    sizeof(ufs_daddr_t) + 1) * sizeof(struct buf *),
87 	    M_SEGMENT, M_WAITOK);
88 	sp->seg_flags = flags;
89 	sp->vp = NULL;
90 	(void) lfs_initseg(fs);
91 
92 	/*
93 	 * Keep a cumulative count of the outstanding I/O operations.  If the
94 	 * disk drive catches up with us it could go to zero before we finish,
95 	 * so we artificially increment it by one until we've scheduled all of
96 	 * the writes we intend to do.
97 	 */
98 	s = splbio();
99 	++fs->lfs_iocount;
100 	splx(s);
101 }
102 /*
103  * lfs_segunlock --
104  *	Single thread the segment writer.
105  */
106 void
107 lfs_segunlock(fs)
108 	struct lfs *fs;
109 {
110 	struct segment *sp;
111 	unsigned long sync, ckp;
112 	int s;
113 
114 	if (fs->lfs_seglock == 1) {
115 
116 		sp = fs->lfs_sp;
117 		sync = sp->seg_flags & SEGM_SYNC;
118 		ckp = sp->seg_flags & SEGM_CKP;
119 		if (sp->bpp != sp->cbpp) {
120 			/* Free allocated segment summary */
121 			fs->lfs_offset -= LFS_SUMMARY_SIZE / DEV_BSIZE;
122 			brelvp(*sp->bpp);
123 			free((*sp->bpp)->b_data, M_SEGMENT);
124 			free(*sp->bpp, M_SEGMENT);
125 		} else
126 			printf ("unlock to 0 with no summary");
127 		free(sp->bpp, M_SEGMENT);
128 		free(sp, M_SEGMENT);
129 
130 		/*
131 		 * If the I/O count is non-zero, sleep until it reaches zero.
132 		 * At the moment, the user's process hangs around so we can
133 		 * sleep.
134 		 */
135 		s = splbio();
136 		--fs->lfs_iocount;
137 		/*
138 		 * We let checkpoints happen asynchronously.  That means
139 		 * that during recovery, we have to roll forward between
140 		 * the two segments described by the first and second
141 		 * superblocks to make sure that the checkpoint described
142 		 * by a superblock completed.
143 		 */
144 		if (sync && fs->lfs_iocount)
145 		    (void)tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs vflush", 0);
146 		splx(s);
147 		if (ckp) {
148 			fs->lfs_nactive = 0;
149 			lfs_writesuper(fs);
150 		}
151 		--fs->lfs_seglock;
152 		fs->lfs_lockpid = 0;
153 		wakeup(&fs->lfs_seglock);
154 	} else if (fs->lfs_seglock == 0) {
155 		panic ("Seglock not held");
156 	} else {
157 		--fs->lfs_seglock;
158 	}
159 }
160