Follow same protocol as `unlink' to prevent potential race condition.
[unix-history] / usr / src / sys / ufs / lfs / lfs_vfsops.c
CommitLineData
1c281610 1/* lfs_vfsops.c 6.4 84/06/26 */
71e4e98b
SL
2
3#include "../h/param.h"
4#include "../h/systm.h"
5#include "../h/dir.h"
6#include "../h/user.h"
7#include "../h/inode.h"
8#include "../h/proc.h"
9#include "../h/fs.h"
10#include "../h/buf.h"
11#include "../h/mount.h"
12#include "../h/file.h"
13#include "../h/nami.h"
14#include "../h/conf.h"
15
16smount()
17{
18 register struct a {
19 char *fspec;
20 char *freg;
21 int ronly;
22 } *uap;
23 dev_t dev;
24 register struct inode *ip;
25 register struct fs *fs;
26 register char *cp;
27
28 uap = (struct a *)u.u_ap;
29 u.u_error = getmdev(&dev);
30 if (u.u_error)
31 return;
32 u.u_dirp = (caddr_t)uap->freg;
f93197fc 33 ip = namei(uchar, LOOKUP | NOCACHE, 1);
71e4e98b
SL
34 if (ip == NULL)
35 return;
36 if (ip->i_count!=1 || (ip->i_mode&IFMT) != IFDIR) {
37 iput(ip);
38 u.u_error = EBUSY;
39 return;
40 }
41 fs = mountfs(dev, uap->ronly, ip);
42 if (fs == 0)
43 return;
44 u.u_dirp = uap->freg;
45 for (cp = fs->fs_fsmnt; cp < &fs->fs_fsmnt[sizeof(fs->fs_fsmnt) - 2]; )
46 if ((*cp++ = uchar()) == 0)
47 u.u_dirp--; /* get 0 again */
48 *cp = 0;
49}
50
71e4e98b
SL
51/* this routine has races if running twice */
52struct fs *
53mountfs(dev, ronly, ip)
54 dev_t dev;
55 int ronly;
56 struct inode *ip;
57{
58 register struct mount *mp = 0;
59 struct buf *tp = 0;
60 register struct buf *bp = 0;
61 register struct fs *fs;
62 int blks;
63 caddr_t space;
64 int i, size;
1c281610 65 register error;
71e4e98b 66
1c281610 67 error =
71e4e98b 68 (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE);
1c281610 69 if (error)
71e4e98b 70 goto out;
71e4e98b
SL
71 tp = bread(dev, SBLOCK, SBSIZE);
72 if (tp->b_flags & B_ERROR)
73 goto out;
74 for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
75 if (mp->m_bufp != 0 && dev == mp->m_dev) {
76 mp = 0;
1c281610 77 error = EBUSY;
71e4e98b
SL
78 goto out;
79 }
80 for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
81 if (mp->m_bufp == 0)
82 goto found;
83 mp = 0;
1c281610 84 error = EMFILE; /* needs translation */
71e4e98b
SL
85 goto out;
86found:
87 mp->m_bufp = tp; /* just to reserve this slot */
88 mp->m_dev = NODEV;
89 fs = tp->b_un.b_fs;
1c281610
MK
90 if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE
91 || fs->fs_bsize < sizeof(struct fs)) {
92 error = EINVAL; /* also needs translation */
93 goto out;
94 }
71e4e98b
SL
95 bp = geteblk((int)fs->fs_sbsize);
96 mp->m_bufp = bp;
97 bcopy((caddr_t)tp->b_un.b_addr, (caddr_t)bp->b_un.b_addr,
98 (u_int)fs->fs_sbsize);
99 brelse(tp);
100 tp = 0;
101 fs = bp->b_un.b_fs;
71e4e98b
SL
102 fs->fs_ronly = (ronly != 0);
103 if (ronly == 0)
104 fs->fs_fmod = 1;
105 blks = howmany(fs->fs_cssize, fs->fs_fsize);
106 space = wmemall(vmemall, (int)fs->fs_cssize);
1c281610
MK
107 if (space == 0) {
108 error = ENOMEM;
71e4e98b 109 goto out;
1c281610 110 }
71e4e98b
SL
111 for (i = 0; i < blks; i += fs->fs_frag) {
112 size = fs->fs_bsize;
113 if (i + fs->fs_frag > blks)
114 size = (blks - i) * fs->fs_fsize;
115 tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size);
116 if (tp->b_flags&B_ERROR) {
117 wmemfree(space, (int)fs->fs_cssize);
118 goto out;
119 }
120 bcopy((caddr_t)tp->b_un.b_addr, space, (u_int)size);
121 fs->fs_csp[i / fs->fs_frag] = (struct csum *)space;
122 space += size;
123 brelse(tp);
124 tp = 0;
125 }
126 mp->m_inodp = ip;
127 mp->m_dev = dev;
128 if (ip) {
129 ip->i_flag |= IMOUNT;
130 iunlock(ip);
131 }
132 return (fs);
133out:
1c281610
MK
134 if (error == 0)
135 error = EIO;
71e4e98b
SL
136 if (ip)
137 iput(ip);
138 if (mp)
139 mp->m_bufp = 0;
140 if (bp)
141 brelse(bp);
142 if (tp)
143 brelse(tp);
1c281610 144 u.u_error = error;
71e4e98b
SL
145 return (0);
146}
147
148umount()
149{
150 struct a {
151 char *fspec;
152 };
153
154 u.u_error = unmount1(0);
155}
156
157unmount1(forcibly)
158 int forcibly;
159{
160 dev_t dev;
161 register struct mount *mp;
162 int stillopen, flag, error;
163 register struct inode *ip;
164 register struct fs *fs;
165
166 error = getmdev(&dev);
167 if (error)
168 return (error);
169 for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
170 if (mp->m_bufp != NULL && dev == mp->m_dev)
171 goto found;
172 return (EINVAL);
173found:
174 xumount(dev); /* remove unused sticky files from text table */
f93197fc 175 nchinval(dev); /* flush the name cache */
71e4e98b
SL
176 update();
177#ifdef QUOTA
178 if ((stillopen = iflush(dev, mp->m_qinod)) < 0 && !forcibly)
179#else
180 if ((stillopen = iflush(dev)) < 0 && !forcibly)
181#endif
182 return (EBUSY);
183 if (stillopen < 0)
184 return (EBUSY); /* XXX */
185#ifdef QUOTA
186 closedq(mp);
187 /*
188 * Here we have to iflush again to get rid of the quota inode.
189 * A drag, but it would be ugly to cheat, & this doesn't happen often
190 */
191 (void)iflush(dev, (struct inode *)NULL);
192#endif
193 ip = mp->m_inodp;
194 ip->i_flag &= ~IMOUNT;
195 irele(ip);
196 fs = mp->m_bufp->b_un.b_fs;
197 wmemfree((caddr_t)fs->fs_csp[0], (int)fs->fs_cssize);
198 flag = !fs->fs_ronly;
199 brelse(mp->m_bufp);
200 mp->m_bufp = 0;
201 mp->m_dev = 0;
202 mpurge(mp - &mount[0]);
203 if (!stillopen) {
204 (*bdevsw[major(dev)].d_close)(dev, flag);
205 binval(dev);
206 }
207 return (0);
208}
209
210sbupdate(mp)
211 struct mount *mp;
212{
213 register struct fs *fs = mp->m_bufp->b_un.b_fs;
214 register struct buf *bp;
215 int blks;
216 caddr_t space;
217 int i, size;
218
219 bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize);
220 bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
221 bwrite(bp);
222 blks = howmany(fs->fs_cssize, fs->fs_fsize);
223 space = (caddr_t)fs->fs_csp[0];
224 for (i = 0; i < blks; i += fs->fs_frag) {
225 size = fs->fs_bsize;
226 if (i + fs->fs_frag > blks)
227 size = (blks - i) * fs->fs_fsize;
228 bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size);
229 bcopy(space, bp->b_un.b_addr, (u_int)size);
230 space += size;
231 bwrite(bp);
232 }
233}
234
235/*
236 * Common code for mount and umount.
237 * Check that the user's argument is a reasonable
238 * thing on which to mount, and return the device number if so.
239 */
240getmdev(pdev)
241 dev_t *pdev;
242{
243 dev_t dev;
244 register struct inode *ip;
245
246 if (!suser())
247 return (u.u_error);
248 ip = namei(uchar, LOOKUP, 1);
249 if (ip == NULL)
250 return (u.u_error);
e95cdf5c
MK
251 if ((ip->i_mode&IFMT) != IFBLK) {
252 iput(ip);
71e4e98b 253 return (ENOTBLK);
e95cdf5c 254 }
71e4e98b 255 dev = (dev_t)ip->i_rdev;
e95cdf5c 256 iput(ip);
71e4e98b
SL
257 if (major(dev) >= nblkdev)
258 return (ENXIO);
71e4e98b
SL
259 *pdev = dev;
260 return (0);
261}