Commit | Line | Data |
---|---|---|
da7c5cc6 KM |
1 | /* |
2 | * Copyright (c) 1982 Regents of the University of California. | |
3 | * All rights reserved. The Berkeley software License Agreement | |
4 | * specifies the terms and conditions for redistribution. | |
5 | * | |
86b729dd | 6 | * @(#)ufs_vfsops.c 6.13 (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 | |
21 | smount() | |
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; | |
715baff1 KM |
37 | ndp->ni_nameiop = LOOKUP | NOCACHE | FOLLOW; |
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 */ |
61 | struct fs * | |
62 | mountfs(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; |
98 | found: | |
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; | |
142 | iunlock(ip); | |
143 | } | |
144 | return (fs); | |
145 | out: | |
1c281610 MK |
146 | if (error == 0) |
147 | error = EIO; | |
71e4e98b SL |
148 | if (ip) |
149 | iput(ip); | |
150 | if (mp) | |
151 | mp->m_bufp = 0; | |
152 | if (bp) | |
153 | brelse(bp); | |
154 | if (tp) | |
155 | brelse(tp); | |
86b729dd MK |
156 | if (needclose) { |
157 | (*bdevsw[major(dev)].d_close)(dev, ronly? FREAD : FREAD|FWRITE); | |
158 | binval(dev); | |
159 | } | |
1c281610 | 160 | u.u_error = error; |
71e4e98b SL |
161 | return (0); |
162 | } | |
163 | ||
164 | umount() | |
165 | { | |
166 | struct a { | |
167 | char *fspec; | |
715baff1 | 168 | } *uap = (struct a *)u.u_ap; |
71e4e98b | 169 | |
715baff1 | 170 | u.u_error = unmount1(uap->fspec, 0); |
71e4e98b SL |
171 | } |
172 | ||
715baff1 KM |
173 | unmount1(fname, forcibly) |
174 | caddr_t fname; | |
71e4e98b SL |
175 | int forcibly; |
176 | { | |
177 | dev_t dev; | |
178 | register struct mount *mp; | |
179 | int stillopen, flag, error; | |
180 | register struct inode *ip; | |
181 | register struct fs *fs; | |
182 | ||
715baff1 | 183 | error = getmdev(&dev, fname); |
71e4e98b SL |
184 | if (error) |
185 | return (error); | |
186 | for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) | |
187 | if (mp->m_bufp != NULL && dev == mp->m_dev) | |
188 | goto found; | |
189 | return (EINVAL); | |
190 | found: | |
191 | xumount(dev); /* remove unused sticky files from text table */ | |
f93197fc | 192 | nchinval(dev); /* flush the name cache */ |
71e4e98b SL |
193 | update(); |
194 | #ifdef QUOTA | |
195 | if ((stillopen = iflush(dev, mp->m_qinod)) < 0 && !forcibly) | |
196 | #else | |
197 | if ((stillopen = iflush(dev)) < 0 && !forcibly) | |
198 | #endif | |
199 | return (EBUSY); | |
200 | if (stillopen < 0) | |
201 | return (EBUSY); /* XXX */ | |
202 | #ifdef QUOTA | |
203 | closedq(mp); | |
204 | /* | |
205 | * Here we have to iflush again to get rid of the quota inode. | |
206 | * A drag, but it would be ugly to cheat, & this doesn't happen often | |
207 | */ | |
208 | (void)iflush(dev, (struct inode *)NULL); | |
209 | #endif | |
210 | ip = mp->m_inodp; | |
211 | ip->i_flag &= ~IMOUNT; | |
212 | irele(ip); | |
213 | fs = mp->m_bufp->b_un.b_fs; | |
214 | wmemfree((caddr_t)fs->fs_csp[0], (int)fs->fs_cssize); | |
215 | flag = !fs->fs_ronly; | |
216 | brelse(mp->m_bufp); | |
217 | mp->m_bufp = 0; | |
218 | mp->m_dev = 0; | |
219 | mpurge(mp - &mount[0]); | |
220 | if (!stillopen) { | |
221 | (*bdevsw[major(dev)].d_close)(dev, flag); | |
222 | binval(dev); | |
223 | } | |
224 | return (0); | |
225 | } | |
226 | ||
227 | sbupdate(mp) | |
228 | struct mount *mp; | |
229 | { | |
230 | register struct fs *fs = mp->m_bufp->b_un.b_fs; | |
231 | register struct buf *bp; | |
232 | int blks; | |
233 | caddr_t space; | |
234 | int i, size; | |
235 | ||
236 | bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize); | |
237 | bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); | |
238 | bwrite(bp); | |
239 | blks = howmany(fs->fs_cssize, fs->fs_fsize); | |
240 | space = (caddr_t)fs->fs_csp[0]; | |
241 | for (i = 0; i < blks; i += fs->fs_frag) { | |
242 | size = fs->fs_bsize; | |
243 | if (i + fs->fs_frag > blks) | |
244 | size = (blks - i) * fs->fs_fsize; | |
245 | bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size); | |
246 | bcopy(space, bp->b_un.b_addr, (u_int)size); | |
247 | space += size; | |
248 | bwrite(bp); | |
249 | } | |
250 | } | |
251 | ||
252 | /* | |
253 | * Common code for mount and umount. | |
254 | * Check that the user's argument is a reasonable | |
255 | * thing on which to mount, and return the device number if so. | |
256 | */ | |
715baff1 KM |
257 | getmdev(pdev, fname) |
258 | caddr_t fname; | |
71e4e98b SL |
259 | dev_t *pdev; |
260 | { | |
261 | dev_t dev; | |
262 | register struct inode *ip; | |
715baff1 | 263 | register struct nameidata *ndp = &u.u_nd; |
71e4e98b SL |
264 | |
265 | if (!suser()) | |
266 | return (u.u_error); | |
715baff1 KM |
267 | ndp->ni_nameiop = LOOKUP | FOLLOW; |
268 | ndp->ni_segflg = UIO_USERSPACE; | |
269 | ndp->ni_dirp = fname; | |
270 | ip = namei(ndp); | |
6d07f4cd KM |
271 | if (ip == NULL) { |
272 | if (u.u_error == ENOENT) | |
273 | return (ENODEV); /* needs translation */ | |
71e4e98b | 274 | return (u.u_error); |
6d07f4cd | 275 | } |
e95cdf5c MK |
276 | if ((ip->i_mode&IFMT) != IFBLK) { |
277 | iput(ip); | |
71e4e98b | 278 | return (ENOTBLK); |
e95cdf5c | 279 | } |
71e4e98b | 280 | dev = (dev_t)ip->i_rdev; |
e95cdf5c | 281 | iput(ip); |
71e4e98b SL |
282 | if (major(dev) >= nblkdev) |
283 | return (ENXIO); | |
71e4e98b SL |
284 | *pdev = dev; |
285 | return (0); | |
286 | } |