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