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