Commit | Line | Data |
---|---|---|
76335100 | 1 | /* ufs_vfsops.c 6.6 84/07/08 */ |
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" | |
71e4e98b SL |
13 | #include "../h/conf.h" |
14 | ||
15 | smount() | |
16 | { | |
17 | register struct a { | |
18 | char *fspec; | |
19 | char *freg; | |
20 | int ronly; | |
715baff1 | 21 | } *uap = (struct a *)u.u_ap; |
71e4e98b SL |
22 | dev_t dev; |
23 | register struct inode *ip; | |
24 | register struct fs *fs; | |
25 | register char *cp; | |
715baff1 | 26 | register struct nameidata *ndp = &u.u_nd; |
76335100 | 27 | u_int len; |
71e4e98b | 28 | |
715baff1 | 29 | u.u_error = getmdev(&dev, uap->fspec); |
71e4e98b SL |
30 | if (u.u_error) |
31 | return; | |
715baff1 KM |
32 | ndp->ni_nameiop = LOOKUP | NOCACHE | FOLLOW; |
33 | ndp->ni_segflg = UIO_USERSPACE; | |
34 | ndp->ni_dirp = (caddr_t)uap->freg; | |
35 | ip = namei(ndp); | |
71e4e98b SL |
36 | if (ip == NULL) |
37 | return; | |
38 | if (ip->i_count!=1 || (ip->i_mode&IFMT) != IFDIR) { | |
39 | iput(ip); | |
40 | u.u_error = EBUSY; | |
41 | return; | |
42 | } | |
43 | fs = mountfs(dev, uap->ronly, ip); | |
44 | if (fs == 0) | |
45 | return; | |
76335100 KM |
46 | (void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len); |
47 | bzero(fs->fs_fsmnt, sizeof (fs->fs_fsmnt) - len); | |
71e4e98b SL |
48 | } |
49 | ||
71e4e98b SL |
50 | /* this routine has races if running twice */ |
51 | struct fs * | |
52 | mountfs(dev, ronly, ip) | |
53 | dev_t dev; | |
54 | int ronly; | |
55 | struct inode *ip; | |
56 | { | |
57 | register struct mount *mp = 0; | |
58 | struct buf *tp = 0; | |
59 | register struct buf *bp = 0; | |
60 | register struct fs *fs; | |
61 | int blks; | |
62 | caddr_t space; | |
63 | int i, size; | |
1c281610 | 64 | register error; |
71e4e98b | 65 | |
1c281610 | 66 | error = |
71e4e98b | 67 | (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE); |
1c281610 | 68 | if (error) |
71e4e98b | 69 | goto out; |
71e4e98b SL |
70 | tp = bread(dev, SBLOCK, SBSIZE); |
71 | if (tp->b_flags & B_ERROR) | |
72 | goto out; | |
73 | for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) | |
74 | if (mp->m_bufp != 0 && dev == mp->m_dev) { | |
75 | mp = 0; | |
1c281610 | 76 | error = EBUSY; |
71e4e98b SL |
77 | goto out; |
78 | } | |
79 | for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) | |
80 | if (mp->m_bufp == 0) | |
81 | goto found; | |
82 | mp = 0; | |
1c281610 | 83 | error = EMFILE; /* needs translation */ |
71e4e98b SL |
84 | goto out; |
85 | found: | |
86 | mp->m_bufp = tp; /* just to reserve this slot */ | |
87 | mp->m_dev = NODEV; | |
88 | fs = tp->b_un.b_fs; | |
1c281610 MK |
89 | if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE |
90 | || fs->fs_bsize < sizeof(struct fs)) { | |
91 | error = EINVAL; /* also needs translation */ | |
92 | goto out; | |
93 | } | |
71e4e98b SL |
94 | bp = geteblk((int)fs->fs_sbsize); |
95 | mp->m_bufp = bp; | |
96 | bcopy((caddr_t)tp->b_un.b_addr, (caddr_t)bp->b_un.b_addr, | |
97 | (u_int)fs->fs_sbsize); | |
98 | brelse(tp); | |
99 | tp = 0; | |
100 | fs = bp->b_un.b_fs; | |
71e4e98b SL |
101 | fs->fs_ronly = (ronly != 0); |
102 | if (ronly == 0) | |
103 | fs->fs_fmod = 1; | |
104 | blks = howmany(fs->fs_cssize, fs->fs_fsize); | |
105 | space = wmemall(vmemall, (int)fs->fs_cssize); | |
1c281610 MK |
106 | if (space == 0) { |
107 | error = ENOMEM; | |
71e4e98b | 108 | goto out; |
1c281610 | 109 | } |
71e4e98b SL |
110 | for (i = 0; i < blks; i += fs->fs_frag) { |
111 | size = fs->fs_bsize; | |
112 | if (i + fs->fs_frag > blks) | |
113 | size = (blks - i) * fs->fs_fsize; | |
114 | tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size); | |
115 | if (tp->b_flags&B_ERROR) { | |
116 | wmemfree(space, (int)fs->fs_cssize); | |
117 | goto out; | |
118 | } | |
119 | bcopy((caddr_t)tp->b_un.b_addr, space, (u_int)size); | |
120 | fs->fs_csp[i / fs->fs_frag] = (struct csum *)space; | |
121 | space += size; | |
122 | brelse(tp); | |
123 | tp = 0; | |
124 | } | |
125 | mp->m_inodp = ip; | |
126 | mp->m_dev = dev; | |
127 | if (ip) { | |
128 | ip->i_flag |= IMOUNT; | |
129 | iunlock(ip); | |
130 | } | |
131 | return (fs); | |
132 | out: | |
1c281610 MK |
133 | if (error == 0) |
134 | error = EIO; | |
71e4e98b SL |
135 | if (ip) |
136 | iput(ip); | |
137 | if (mp) | |
138 | mp->m_bufp = 0; | |
139 | if (bp) | |
140 | brelse(bp); | |
141 | if (tp) | |
142 | brelse(tp); | |
1c281610 | 143 | u.u_error = error; |
71e4e98b SL |
144 | return (0); |
145 | } | |
146 | ||
147 | umount() | |
148 | { | |
149 | struct a { | |
150 | char *fspec; | |
715baff1 | 151 | } *uap = (struct a *)u.u_ap; |
71e4e98b | 152 | |
715baff1 | 153 | u.u_error = unmount1(uap->fspec, 0); |
71e4e98b SL |
154 | } |
155 | ||
715baff1 KM |
156 | unmount1(fname, forcibly) |
157 | caddr_t fname; | |
71e4e98b SL |
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 | ||
715baff1 | 166 | error = getmdev(&dev, fname); |
71e4e98b SL |
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); | |
173 | found: | |
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 | ||
210 | sbupdate(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 | */ | |
715baff1 KM |
240 | getmdev(pdev, fname) |
241 | caddr_t fname; | |
71e4e98b SL |
242 | dev_t *pdev; |
243 | { | |
244 | dev_t dev; | |
245 | register struct inode *ip; | |
715baff1 | 246 | register struct nameidata *ndp = &u.u_nd; |
71e4e98b SL |
247 | |
248 | if (!suser()) | |
249 | return (u.u_error); | |
715baff1 KM |
250 | ndp->ni_nameiop = LOOKUP | FOLLOW; |
251 | ndp->ni_segflg = UIO_USERSPACE; | |
252 | ndp->ni_dirp = fname; | |
253 | ip = namei(ndp); | |
71e4e98b SL |
254 | if (ip == NULL) |
255 | return (u.u_error); | |
e95cdf5c MK |
256 | if ((ip->i_mode&IFMT) != IFBLK) { |
257 | iput(ip); | |
71e4e98b | 258 | return (ENOTBLK); |
e95cdf5c | 259 | } |
71e4e98b | 260 | dev = (dev_t)ip->i_rdev; |
e95cdf5c | 261 | iput(ip); |
71e4e98b SL |
262 | if (major(dev) >= nblkdev) |
263 | return (ENXIO); | |
71e4e98b SL |
264 | *pdev = dev; |
265 | return (0); | |
266 | } |