check ip before dereferencing (can only happen when called to mount root)
[unix-history] / usr / src / sys / ufs / ffs / ffs_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 *
110a7775 6 * @(#)ffs_vfsops.c 7.4 (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"
ec67a3ce
MK
20#include "ioctl.h"
21#include "disklabel.h"
22#include "stat.h"
609e7cfa
MK
23#include "ioctl.h"
24#include "disklabel.h"
25#include "stat.h"
71e4e98b
SL
26
27smount()
28{
29 register struct a {
30 char *fspec;
31 char *freg;
32 int ronly;
715baff1 33 } *uap = (struct a *)u.u_ap;
71e4e98b
SL
34 dev_t dev;
35 register struct inode *ip;
36 register struct fs *fs;
715baff1 37 register struct nameidata *ndp = &u.u_nd;
76335100 38 u_int len;
71e4e98b 39
715baff1 40 u.u_error = getmdev(&dev, uap->fspec);
71e4e98b
SL
41 if (u.u_error)
42 return;
c2f29eff 43 ndp->ni_nameiop = LOOKUP | FOLLOW;
715baff1
KM
44 ndp->ni_segflg = UIO_USERSPACE;
45 ndp->ni_dirp = (caddr_t)uap->freg;
46 ip = namei(ndp);
71e4e98b
SL
47 if (ip == NULL)
48 return;
6d07f4cd 49 if (ip->i_count != 1) {
71e4e98b
SL
50 iput(ip);
51 u.u_error = EBUSY;
52 return;
53 }
6d07f4cd
KM
54 if ((ip->i_mode&IFMT) != IFDIR) {
55 iput(ip);
56 u.u_error = ENOTDIR;
57 return;
58 }
71e4e98b
SL
59 fs = mountfs(dev, uap->ronly, ip);
60 if (fs == 0)
61 return;
76335100 62 (void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len);
32af08ce 63 bzero(fs->fs_fsmnt + len, sizeof (fs->fs_fsmnt) - len);
71e4e98b
SL
64}
65
71e4e98b
SL
66/* this routine has races if running twice */
67struct fs *
68mountfs(dev, ronly, ip)
69 dev_t dev;
70 int ronly;
71 struct inode *ip;
72{
73 register struct mount *mp = 0;
74 struct buf *tp = 0;
75 register struct buf *bp = 0;
76 register struct fs *fs;
ec67a3ce
MK
77 struct partinfo dpart;
78 int havepart = 0, blks;
71e4e98b
SL
79 caddr_t space;
80 int i, size;
1c281610 81 register error;
6d07f4cd 82 int needclose = 0;
71e4e98b 83
1c281610 84 error =
ec67a3ce
MK
85 (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE,
86 S_IFBLK);
1c281610 87 if (error)
71e4e98b 88 goto out;
6d07f4cd 89 needclose = 1;
609e7cfa
MK
90 if ((*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART,
91 (caddr_t)&dpart, FREAD) == 0) {
92 havepart = 1;
93 size = dpart.disklab->d_secsize;
94 } else
95 size = DEV_BSIZE;
ec67a3ce
MK
96#ifdef SECSIZE
97 /*
98 * If possible, determine hardware sector size
99 * and adjust fsbtodb to correspond.
100 */
101#endif SECSIZE
102 if ((*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART,
103 (caddr_t)&dpart, FREAD) == 0) {
104 havepart = 1;
105 size = dpart.disklab->d_secsize;
106#ifdef SECSIZE
107 if (size < MINSECSIZE) {
108 error = EINVAL;
109 goto out;
110 }
111#endif SECSIZE
112 } else
113 size = DEV_BSIZE;
114#ifdef SECSIZE
115 tp = bread(dev, (daddr_t)(SBOFF / size), SBSIZE, size);
116#else SECSIZE
71e4e98b 117 tp = bread(dev, SBLOCK, SBSIZE);
ec67a3ce 118#endif SECSIZE
71e4e98b
SL
119 if (tp->b_flags & B_ERROR)
120 goto out;
121 for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
122 if (mp->m_bufp != 0 && dev == mp->m_dev) {
123 mp = 0;
1c281610 124 error = EBUSY;
71e4e98b
SL
125 goto out;
126 }
127 for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
128 if (mp->m_bufp == 0)
129 goto found;
130 mp = 0;
1c281610 131 error = EMFILE; /* needs translation */
71e4e98b
SL
132 goto out;
133found:
134 mp->m_bufp = tp; /* just to reserve this slot */
135 mp->m_dev = NODEV;
136 fs = tp->b_un.b_fs;
ec67a3ce
MK
137 if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE ||
138 fs->fs_bsize < sizeof(struct fs)) {
1c281610
MK
139 error = EINVAL; /* also needs translation */
140 goto out;
141 }
71e4e98b
SL
142 bp = geteblk((int)fs->fs_sbsize);
143 mp->m_bufp = bp;
144 bcopy((caddr_t)tp->b_un.b_addr, (caddr_t)bp->b_un.b_addr,
145 (u_int)fs->fs_sbsize);
146 brelse(tp);
147 tp = 0;
148 fs = bp->b_un.b_fs;
71e4e98b
SL
149 fs->fs_ronly = (ronly != 0);
150 if (ronly == 0)
151 fs->fs_fmod = 1;
609e7cfa
MK
152 if (havepart) {
153 dpart.part->p_fstype = FS_BSDFFS;
154 dpart.part->p_fsize = fs->fs_fsize;
155 dpart.part->p_frag = fs->fs_frag;
156 fs->fs_dbsize = size;
157 }
ec67a3ce
MK
158#ifdef SECSIZE
159 /*
160 * If we have a disk label, force per-partition
161 * filesystem information to be correct
162 * and set correct current fsbtodb shift.
163 */
164#endif SECSIZE
165 if (havepart) {
166 dpart.part->p_fstype = FS_BSDFFS;
167 dpart.part->p_fsize = fs->fs_fsize;
168 dpart.part->p_frag = fs->fs_frag;
169#ifdef SECSIZE
170#ifdef tahoe
171 /*
172 * Save the original fsbtodb shift to restore on updates.
173 * (Console doesn't understand fsbtodb changes.)
174 */
175 fs->fs_sparecon[0] = fs->fs_fsbtodb;
176#endif
177 i = fs->fs_fsize / size;
178 for (fs->fs_fsbtodb = 0; i > 1; i >>= 1)
179 fs->fs_fsbtodb++;
180#endif SECSIZE
181 fs->fs_dbsize = size;
182 }
71e4e98b
SL
183 blks = howmany(fs->fs_cssize, fs->fs_fsize);
184 space = wmemall(vmemall, (int)fs->fs_cssize);
1c281610
MK
185 if (space == 0) {
186 error = ENOMEM;
71e4e98b 187 goto out;
1c281610 188 }
71e4e98b
SL
189 for (i = 0; i < blks; i += fs->fs_frag) {
190 size = fs->fs_bsize;
191 if (i + fs->fs_frag > blks)
192 size = (blks - i) * fs->fs_fsize;
ec67a3ce
MK
193#ifdef SECSIZE
194 tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size,
195 fs->fs_dbsize);
196#else SECSIZE
71e4e98b 197 tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size);
ec67a3ce 198#endif SECSIZE
71e4e98b
SL
199 if (tp->b_flags&B_ERROR) {
200 wmemfree(space, (int)fs->fs_cssize);
201 goto out;
202 }
203 bcopy((caddr_t)tp->b_un.b_addr, space, (u_int)size);
60f9c9e3 204 fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space;
71e4e98b
SL
205 space += size;
206 brelse(tp);
207 tp = 0;
208 }
209 mp->m_inodp = ip;
210 mp->m_dev = dev;
211 if (ip) {
212 ip->i_flag |= IMOUNT;
c2f29eff 213 cacheinval(ip);
71e4e98b
SL
214 iunlock(ip);
215 }
94354803
KM
216 /* Sanity checks for old file systems. XXX */
217 fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */
218 fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */
ec67a3ce 219
609e7cfa 220
71e4e98b
SL
221 return (fs);
222out:
1c281610
MK
223 if (error == 0)
224 error = EIO;
110a7775 225 if (needclose && ip)
ec67a3ce
MK
226 (void) closei((dev_t)ip->i_rdev, IFBLK,
227 ronly? FREAD : FREAD|FWRITE);
609e7cfa
MK
228 if (needclose)
229 (void) closei((dev_t)ip->i_rdev, IFBLK,
230 ronly? FREAD : FREAD|FWRITE);
71e4e98b
SL
231 if (ip)
232 iput(ip);
233 if (mp)
234 mp->m_bufp = 0;
235 if (bp)
236 brelse(bp);
237 if (tp)
238 brelse(tp);
1c281610 239 u.u_error = error;
71e4e98b
SL
240 return (0);
241}
242
243umount()
244{
245 struct a {
246 char *fspec;
715baff1 247 } *uap = (struct a *)u.u_ap;
71e4e98b 248
715baff1 249 u.u_error = unmount1(uap->fspec, 0);
71e4e98b
SL
250}
251
715baff1
KM
252unmount1(fname, forcibly)
253 caddr_t fname;
71e4e98b
SL
254 int forcibly;
255{
256 dev_t dev;
257 register struct mount *mp;
ec67a3ce 258 int error;
71e4e98b
SL
259 register struct inode *ip;
260 register struct fs *fs;
261
609e7cfa 262 forcibly = 0; /* XXX */
ec67a3ce 263 forcibly = 0; /* XXX */
715baff1 264 error = getmdev(&dev, fname);
71e4e98b
SL
265 if (error)
266 return (error);
267 for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++)
268 if (mp->m_bufp != NULL && dev == mp->m_dev)
269 goto found;
270 return (EINVAL);
271found:
272 xumount(dev); /* remove unused sticky files from text table */
f93197fc 273 nchinval(dev); /* flush the name cache */
71e4e98b
SL
274 update();
275#ifdef QUOTA
ec67a3ce 276 if ((error = iflush(dev, mp->m_qinod)) && !forcibly)
71e4e98b 277#else
ec67a3ce 278 if ((error = iflush(dev)) && !forcibly)
71e4e98b 279#endif
ec67a3ce 280 return (error);
71e4e98b
SL
281#ifdef QUOTA
282 closedq(mp);
283 /*
284 * Here we have to iflush again to get rid of the quota inode.
ec67a3ce 285 * A drag, but it would be ugly to cheat, & this doesn't happen often.
71e4e98b
SL
286 */
287 (void)iflush(dev, (struct inode *)NULL);
288#endif
289 ip = mp->m_inodp;
290 ip->i_flag &= ~IMOUNT;
71e4e98b
SL
291 fs = mp->m_bufp->b_un.b_fs;
292 wmemfree((caddr_t)fs->fs_csp[0], (int)fs->fs_cssize);
71e4e98b
SL
293 brelse(mp->m_bufp);
294 mp->m_bufp = 0;
295 mp->m_dev = 0;
296 mpurge(mp - &mount[0]);
ec67a3ce
MK
297 error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE);
298 irele(ip);
299 return (error);
71e4e98b
SL
300}
301
302sbupdate(mp)
303 struct mount *mp;
304{
305 register struct fs *fs = mp->m_bufp->b_un.b_fs;
306 register struct buf *bp;
307 int blks;
308 caddr_t space;
309 int i, size;
310
ec67a3ce
MK
311#ifdef SECSIZE
312 bp = getblk(mp->m_dev, (daddr_t)fsbtodb(fs, SBOFF / fs->fs_fsize),
313 (int)fs->fs_sbsize, fs->fs_dbsize);
314#else SECSIZE
71e4e98b 315 bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize);
ec67a3ce 316#endif SECSIZE
71e4e98b 317 bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize);
ec67a3ce
MK
318#ifdef SECSIZE
319#ifdef tahoe
320 /* restore standard fsbtodb shift */
321 bp->b_un.b_fs->fs_fsbtodb = fs->fs_sparecon[0];
322 bp->b_un.b_fs->fs_sparecon[0] = 0;
323#endif
324#endif SECSIZE
71e4e98b
SL
325 bwrite(bp);
326 blks = howmany(fs->fs_cssize, fs->fs_fsize);
327 space = (caddr_t)fs->fs_csp[0];
328 for (i = 0; i < blks; i += fs->fs_frag) {
329 size = fs->fs_bsize;
330 if (i + fs->fs_frag > blks)
331 size = (blks - i) * fs->fs_fsize;
ec67a3ce
MK
332#ifdef SECSIZE
333 bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size,
334 fs->fs_dbsize);
335#else SECSIZE
71e4e98b 336 bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size);
ec67a3ce 337#endif SECSIZE
71e4e98b
SL
338 bcopy(space, bp->b_un.b_addr, (u_int)size);
339 space += size;
340 bwrite(bp);
341 }
342}
343
344/*
345 * Common code for mount and umount.
346 * Check that the user's argument is a reasonable
347 * thing on which to mount, and return the device number if so.
348 */
715baff1
KM
349getmdev(pdev, fname)
350 caddr_t fname;
71e4e98b
SL
351 dev_t *pdev;
352{
353 dev_t dev;
354 register struct inode *ip;
715baff1 355 register struct nameidata *ndp = &u.u_nd;
71e4e98b
SL
356
357 if (!suser())
358 return (u.u_error);
715baff1
KM
359 ndp->ni_nameiop = LOOKUP | FOLLOW;
360 ndp->ni_segflg = UIO_USERSPACE;
361 ndp->ni_dirp = fname;
362 ip = namei(ndp);
6d07f4cd
KM
363 if (ip == NULL) {
364 if (u.u_error == ENOENT)
365 return (ENODEV); /* needs translation */
71e4e98b 366 return (u.u_error);
6d07f4cd 367 }
e95cdf5c
MK
368 if ((ip->i_mode&IFMT) != IFBLK) {
369 iput(ip);
71e4e98b 370 return (ENOTBLK);
e95cdf5c 371 }
71e4e98b 372 dev = (dev_t)ip->i_rdev;
e95cdf5c 373 iput(ip);
71e4e98b
SL
374 if (major(dev) >= nblkdev)
375 return (ENXIO);
71e4e98b
SL
376 *pdev = dev;
377 return (0);
378}