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
lfs_blkatoff(ap)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
lfs_seglock(fs,flags)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
lfs_segunlock(fs)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