iget must lock old inode before dqrele()
[unix-history] / usr / src / sys / ufs / ffs / ufs_vfsops.c
CommitLineData
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
15smount()
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 */
51struct fs *
52mountfs(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;
85found:
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);
132out:
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
147umount()
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
156unmount1(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);
173found:
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
210sbupdate(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
240getmdev(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}