Commit | Line | Data |
---|---|---|
984263bc MD |
1 | /* |
2 | * Copyright (c) 1999, 2000 Boris Popov | |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * 3. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
15 | * This product includes software developed by Boris Popov. | |
16 | * 4. Neither the name of the author nor the names of any co-contributors | |
17 | * may be used to endorse or promote products derived from this software | |
18 | * without specific prior written permission. | |
19 | * | |
20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
30 | * SUCH DAMAGE. | |
31 | * | |
32 | * $FreeBSD: src/sys/nwfs/nwfs_vfsops.c,v 1.6.2.6 2001/10/25 19:18:54 dillon Exp $ | |
978400d3 | 33 | * $DragonFly: src/sys/vfs/nwfs/nwfs_vfsops.c,v 1.30 2008/01/06 16:55:53 swildner Exp $ |
984263bc MD |
34 | */ |
35 | #include "opt_ncp.h" | |
36 | #ifndef NCP | |
37 | #error "NWFS requires NCP protocol" | |
38 | #endif | |
39 | ||
40 | #include <sys/param.h> | |
41 | #include <sys/systm.h> | |
42 | #include <sys/proc.h> | |
43 | #include <sys/kernel.h> | |
44 | #include <sys/sysctl.h> | |
45 | #include <sys/vnode.h> | |
46 | #include <sys/mount.h> | |
47 | #include <sys/stat.h> | |
48 | #include <sys/malloc.h> | |
49 | #include <sys/buf.h> | |
50 | ||
d2438d69 MD |
51 | #include <netproto/ncp/ncp.h> |
52 | #include <netproto/ncp/ncp_conn.h> | |
53 | #include <netproto/ncp/ncp_subr.h> | |
54 | #include <netproto/ncp/ncp_ncp.h> | |
55 | #include <netproto/ncp/ncp_nls.h> | |
984263bc | 56 | |
1f2de5d4 MD |
57 | #include "nwfs.h" |
58 | #include "nwfs_node.h" | |
59 | #include "nwfs_subr.h" | |
984263bc | 60 | |
66a1ddf5 | 61 | extern struct vop_ops nwfs_vnode_vops; |
0961aa92 | 62 | |
984263bc MD |
63 | int nwfs_debuglevel = 0; |
64 | ||
65 | static int nwfs_version = NWFS_VERSION; | |
66 | ||
67 | SYSCTL_DECL(_vfs_nwfs); | |
68 | SYSCTL_NODE(_vfs, OID_AUTO, nwfs, CTLFLAG_RW, 0, "Netware file system"); | |
69 | SYSCTL_INT(_vfs_nwfs, OID_AUTO, version, CTLFLAG_RD, &nwfs_version, 0, ""); | |
70 | SYSCTL_INT(_vfs_nwfs, OID_AUTO, debuglevel, CTLFLAG_RW, &nwfs_debuglevel, 0, ""); | |
71 | ||
acde96db | 72 | static int nwfs_mount(struct mount *, char *, caddr_t, struct ucred *); |
984263bc | 73 | static int nwfs_root(struct mount *, struct vnode **); |
acde96db | 74 | static int nwfs_statfs(struct mount *, struct statfs *, struct ucred *); |
87de5057 | 75 | static int nwfs_sync(struct mount *, int); |
acde96db | 76 | static int nwfs_unmount(struct mount *, int); |
984263bc MD |
77 | static int nwfs_init(struct vfsconf *vfsp); |
78 | static int nwfs_uninit(struct vfsconf *vfsp); | |
79 | ||
80 | static struct vfsops nwfs_vfsops = { | |
43c45e8f HP |
81 | .vfs_mount = nwfs_mount, |
82 | .vfs_unmount = nwfs_unmount, | |
83 | .vfs_root = nwfs_root, | |
84 | .vfs_statfs = nwfs_statfs, | |
85 | .vfs_sync = nwfs_sync, | |
86 | .vfs_init = nwfs_init, | |
87 | .vfs_uninit = nwfs_uninit | |
984263bc MD |
88 | }; |
89 | ||
90 | ||
91 | VFS_SET(nwfs_vfsops, nwfs, VFCF_NETWORK); | |
92 | ||
93 | int nwfs_pbuf_freecnt = -1; /* start out unlimited */ | |
94 | static int nwfsid = 1; | |
95 | ||
96 | static int | |
97 | nwfs_initnls(struct nwmount *nmp) { | |
98 | char *pc, *pe; | |
99 | int error = 0; | |
100 | #define COPY_TABLE(t,d) { \ | |
101 | if (t) { \ | |
102 | error = copyin((t), pc, 256); \ | |
103 | if (error) break; \ | |
104 | } else \ | |
105 | bcopy(d, pc, 256); \ | |
106 | (t) = pc; pc += 256; \ | |
107 | } | |
108 | ||
109 | nmp->m.nls.opt |= NWHP_NLS | NWHP_DOS; | |
110 | if ((nmp->m.flags & NWFS_MOUNT_HAVE_NLS) == 0) { | |
111 | nmp->m.nls.to_lower = ncp_defnls.to_lower; | |
112 | nmp->m.nls.to_upper = ncp_defnls.to_upper; | |
113 | nmp->m.nls.n2u = ncp_defnls.n2u; | |
114 | nmp->m.nls.u2n = ncp_defnls.u2n; | |
115 | return 0; | |
116 | } | |
117 | MALLOC(pe, char *, 256 * 4, M_NWFSDATA, M_WAITOK); | |
118 | pc = pe; | |
119 | do { | |
120 | COPY_TABLE(nmp->m.nls.to_lower, ncp_defnls.to_lower); | |
121 | COPY_TABLE(nmp->m.nls.to_upper, ncp_defnls.to_upper); | |
122 | COPY_TABLE(nmp->m.nls.n2u, ncp_defnls.n2u); | |
123 | COPY_TABLE(nmp->m.nls.u2n, ncp_defnls.u2n); | |
124 | } while(0); | |
125 | if (error) { | |
efda3bd0 | 126 | kfree(pe, M_NWFSDATA); |
984263bc MD |
127 | return error; |
128 | } | |
129 | return 0; | |
130 | } | |
131 | /* | |
132 | * mp - path - addr in user space of mount point (ie /usr or whatever) | |
133 | * data - addr in user space of mount params | |
134 | */ | |
a9bb80e0 | 135 | static int |
acde96db | 136 | nwfs_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred) |
984263bc MD |
137 | { |
138 | struct nwfs_args args; /* will hold data from mount request */ | |
984263bc MD |
139 | int error; |
140 | struct nwmount *nmp = NULL; | |
141 | struct ncp_conn *conn = NULL; | |
142 | struct ncp_handle *handle = NULL; | |
143 | struct vnode *vp; | |
144 | char *pc,*pe; | |
145 | ||
146 | if (data == NULL) { | |
147 | nwfs_printf("missing data argument\n"); | |
148 | return 1; | |
149 | } | |
150 | if (mp->mnt_flag & MNT_UPDATE) { | |
151 | nwfs_printf("MNT_UPDATE not implemented"); | |
152 | return (EOPNOTSUPP); | |
153 | } | |
154 | error = copyin(data, (caddr_t)&args, sizeof(struct nwfs_args)); | |
155 | if (error) | |
156 | return (error); | |
157 | if (args.version != NWFS_VERSION) { | |
158 | nwfs_printf("mount version mismatch: kernel=%d, mount=%d\n",NWFS_VERSION,args.version); | |
159 | return (1); | |
160 | } | |
acde96db | 161 | error = ncp_conn_getbyref(args.connRef,curthread,cred,NCPM_EXECUTE,&conn); |
984263bc | 162 | if (error) { |
3f625015 | 163 | nwfs_printf("invalid connection reference %d\n",args.connRef); |
984263bc MD |
164 | return (error); |
165 | } | |
166 | error = ncp_conn_gethandle(conn, NULL, &handle); | |
167 | if (error) { | |
168 | nwfs_printf("can't get connection handle\n"); | |
169 | return (error); | |
170 | } | |
acde96db | 171 | ncp_conn_unlock(conn,curthread); /* we keep the ref */ |
984263bc MD |
172 | mp->mnt_stat.f_iosize = conn->buffer_size; |
173 | /* We must malloc our own mount info */ | |
dc1fd4b3 | 174 | MALLOC(nmp,struct nwmount *,sizeof(struct nwmount),M_NWFSDATA, M_WAITOK|M_USE_RESERVE|M_ZERO); |
984263bc MD |
175 | mp->mnt_data = (qaddr_t)nmp; |
176 | nmp->connh = handle; | |
177 | nmp->n_root = NULL; | |
178 | nmp->n_id = nwfsid++; | |
179 | nmp->m = args; | |
180 | nmp->m.file_mode = (nmp->m.file_mode & | |
181 | (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG; | |
182 | nmp->m.dir_mode = (nmp->m.dir_mode & | |
183 | (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFDIR; | |
184 | if ((error = nwfs_initnls(nmp)) != 0) goto bad; | |
984263bc MD |
185 | pc = mp->mnt_stat.f_mntfromname; |
186 | pe = pc+sizeof(mp->mnt_stat.f_mntfromname); | |
187 | bzero(pc, MNAMELEN); | |
188 | *(pc++) = '/'; | |
189 | pc = index(strncpy(pc, conn->li.server, pe-pc-2),0); | |
190 | if (pc < pe-1) { | |
191 | *(pc++) = ':'; | |
192 | pc=index(strncpy(pc, conn->li.user, pe-pc-2),0); | |
193 | if (pc < pe-1) { | |
194 | *(pc++) = '/'; | |
195 | strncpy(pc, nmp->m.mounted_vol, pe-pc-2); | |
196 | } | |
197 | } | |
198 | /* protect against invalid mount points */ | |
199 | nmp->m.mount_point[sizeof(nmp->m.mount_point)-1] = '\0'; | |
0961aa92 | 200 | |
66a1ddf5 | 201 | vfs_add_vnodeops(mp, &nwfs_vnode_vops, &mp->mnt_vn_norm_ops); |
0961aa92 | 202 | |
984263bc MD |
203 | vfs_getnewfsid(mp); |
204 | error = nwfs_root(mp, &vp); | |
205 | if (error) | |
206 | goto bad; | |
207 | /* | |
208 | * Lose the lock but keep the ref. | |
209 | */ | |
a11aaa81 | 210 | vn_unlock(vp); |
3c37c940 | 211 | NCPVODEBUG("rootvp.vrefcnt=%d\n",vp->v_sysref.refcnt); |
984263bc MD |
212 | return error; |
213 | bad: | |
214 | if (nmp) | |
efda3bd0 | 215 | kfree(nmp, M_NWFSDATA); |
984263bc MD |
216 | if (handle) |
217 | ncp_conn_puthandle(handle, NULL, 0); | |
218 | return error; | |
219 | } | |
220 | ||
221 | /* Unmount the filesystem described by mp. */ | |
222 | static int | |
acde96db | 223 | nwfs_unmount(struct mount *mp, int mntflags) |
984263bc MD |
224 | { |
225 | struct nwmount *nmp = VFSTONWFS(mp); | |
226 | struct ncp_conn *conn; | |
227 | int error, flags; | |
228 | ||
229 | NCPVODEBUG("nwfs_unmount: flags=%04x\n",mntflags); | |
230 | flags = 0; | |
231 | if (mntflags & MNT_FORCE) | |
232 | flags |= FORCECLOSE; | |
233 | /* There is 1 extra root vnode reference from nwfs_mount(). */ | |
234 | error = vflush(mp, 1, flags); | |
235 | if (error) | |
236 | return (error); | |
237 | conn = NWFSTOCONN(nmp); | |
238 | ncp_conn_puthandle(nmp->connh,NULL,0); | |
acde96db | 239 | if (ncp_conn_lock(conn, curthread, proc0.p_ucred, NCPM_WRITE | NCPM_EXECUTE) == 0) { |
984263bc | 240 | if(ncp_disconnect(conn)) |
acde96db | 241 | ncp_conn_unlock(conn, curthread); |
984263bc MD |
242 | } |
243 | mp->mnt_data = (qaddr_t)0; | |
244 | if (nmp->m.flags & NWFS_MOUNT_HAVE_NLS) | |
efda3bd0 MD |
245 | kfree(nmp->m.nls.to_lower, M_NWFSDATA); |
246 | kfree(nmp, M_NWFSDATA); | |
984263bc MD |
247 | mp->mnt_flag &= ~MNT_LOCAL; |
248 | return (error); | |
249 | } | |
250 | ||
251 | /* Return locked vnode to root of a filesystem */ | |
252 | static int | |
a9bb80e0 CP |
253 | nwfs_root(struct mount *mp, struct vnode **vpp) |
254 | { | |
984263bc MD |
255 | struct vnode *vp; |
256 | struct nwmount *nmp; | |
257 | struct nwnode *np; | |
258 | struct ncp_conn *conn; | |
259 | struct nw_entry_info fattr; | |
dadab5e9 MD |
260 | struct thread *td = curthread; /* XXX */ |
261 | struct ucred *cred; | |
984263bc MD |
262 | int error, nsf, opt; |
263 | u_char vol; | |
264 | ||
dadab5e9 MD |
265 | KKASSERT(td->td_proc); |
266 | cred = td->td_proc->p_ucred; | |
267 | ||
984263bc MD |
268 | nmp = VFSTONWFS(mp); |
269 | conn = NWFSTOCONN(nmp); | |
270 | if (nmp->n_root) { | |
271 | *vpp = NWTOV(nmp->n_root); | |
87de5057 | 272 | while (vget(*vpp, LK_EXCLUSIVE) != 0) /* XXX */ |
984263bc MD |
273 | ; |
274 | return 0; | |
275 | } | |
276 | error = ncp_lookup_volume(conn, nmp->m.mounted_vol, &vol, | |
dadab5e9 | 277 | &nmp->n_rootent.f_id, td, cred); |
984263bc MD |
278 | if (error) |
279 | return ENOENT; | |
280 | nmp->n_volume = vol; | |
dadab5e9 | 281 | error = ncp_get_namespaces(conn, vol, &nsf, td, cred); |
984263bc MD |
282 | if (error) |
283 | return ENOENT; | |
284 | if (nsf & NW_NSB_OS2) { | |
285 | NCPVODEBUG("volume %s has os2 namespace\n",nmp->m.mounted_vol); | |
286 | if ((nmp->m.flags & NWFS_MOUNT_NO_OS2) == 0) { | |
287 | nmp->name_space = NW_NS_OS2; | |
288 | nmp->m.nls.opt &= ~NWHP_DOS; | |
289 | } | |
290 | } | |
291 | opt = nmp->m.nls.opt; | |
292 | nsf = opt & (NWHP_UPPER | NWHP_LOWER); | |
293 | if (opt & NWHP_DOS) { | |
294 | if (nsf == (NWHP_UPPER | NWHP_LOWER)) { | |
295 | nmp->m.nls.opt &= ~(NWHP_LOWER | NWHP_UPPER); | |
296 | } else if (nsf == 0) { | |
297 | nmp->m.nls.opt |= NWHP_LOWER; | |
298 | } | |
299 | } else { | |
300 | if (nsf == (NWHP_UPPER | NWHP_LOWER)) { | |
301 | nmp->m.nls.opt &= ~(NWHP_LOWER | NWHP_UPPER); | |
302 | } | |
303 | } | |
304 | if (nmp->m.root_path[0]) { | |
305 | nmp->m.root_path[0]--; | |
306 | error = ncp_obtain_info(nmp, nmp->n_rootent.f_id, | |
dadab5e9 | 307 | -nmp->m.root_path[0], nmp->m.root_path, &fattr, td, cred); |
984263bc MD |
308 | if (error) { |
309 | NCPFATAL("Invalid root path specified\n"); | |
310 | return ENOENT; | |
311 | } | |
312 | nmp->n_rootent.f_parent = fattr.dirEntNum; | |
313 | nmp->m.root_path[0]++; | |
314 | error = ncp_obtain_info(nmp, nmp->n_rootent.f_id, | |
dadab5e9 | 315 | -nmp->m.root_path[0], nmp->m.root_path, &fattr, td, cred); |
984263bc MD |
316 | if (error) { |
317 | NCPFATAL("Invalid root path specified\n"); | |
318 | return ENOENT; | |
319 | } | |
320 | nmp->n_rootent.f_id = fattr.dirEntNum; | |
321 | } else { | |
322 | error = ncp_obtain_info(nmp, nmp->n_rootent.f_id, | |
dadab5e9 | 323 | 0, NULL, &fattr, td, cred); |
984263bc MD |
324 | if (error) { |
325 | NCPFATAL("Can't obtain volume info\n"); | |
326 | return ENOENT; | |
327 | } | |
328 | fattr.nameLen = strlen(strcpy(fattr.entryName, NWFS_ROOTVOL)); | |
329 | nmp->n_rootent.f_parent = nmp->n_rootent.f_id; | |
330 | } | |
331 | error = nwfs_nget(mp, nmp->n_rootent, &fattr, NULL, &vp); | |
332 | if (error) | |
333 | return (error); | |
334 | vp->v_flag |= VROOT; | |
335 | np = VTONW(vp); | |
336 | if (nmp->m.root_path[0] == 0) | |
337 | np->n_flag |= NVOLUME; | |
338 | nmp->n_root = np; | |
87de5057 | 339 | /* error = VOP_GETATTR(vp, &vattr); |
984263bc MD |
340 | if (error) { |
341 | vput(vp); | |
342 | NCPFATAL("Can't get root directory entry\n"); | |
343 | return error; | |
344 | }*/ | |
345 | *vpp = vp; | |
346 | return (0); | |
347 | } | |
348 | ||
984263bc MD |
349 | /*ARGSUSED*/ |
350 | int | |
351 | nwfs_init(struct vfsconf *vfsp) | |
352 | { | |
353 | #ifndef SMP | |
354 | int name[2]; | |
973c11b9 MD |
355 | int ncpu, error; |
356 | size_t olen, plen; | |
984263bc MD |
357 | |
358 | name[0] = CTL_HW; | |
359 | name[1] = HW_NCPU; | |
41c20dac | 360 | error = kernel_sysctl(name, 2, &ncpu, &olen, NULL, 0, &plen); |
984263bc | 361 | if (error == 0 && ncpu > 1) |
086c1d7e | 362 | kprintf("warning: nwfs module compiled without SMP support."); |
984263bc MD |
363 | #endif |
364 | nwfs_hash_init(); | |
365 | nwfs_pbuf_freecnt = nswbuf / 2 + 1; | |
366 | NCPVODEBUG("always happy to load!\n"); | |
367 | return (0); | |
368 | } | |
369 | ||
370 | /*ARGSUSED*/ | |
371 | int | |
372 | nwfs_uninit(struct vfsconf *vfsp) | |
373 | { | |
374 | ||
375 | nwfs_hash_free(); | |
376 | NCPVODEBUG("unloaded\n"); | |
377 | return (0); | |
378 | } | |
379 | ||
380 | /* | |
381 | * nwfs_statfs call | |
382 | */ | |
383 | int | |
acde96db | 384 | nwfs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred) |
984263bc MD |
385 | { |
386 | struct nwmount *nmp = VFSTONWFS(mp); | |
387 | int error = 0, secsize; | |
388 | struct nwnode *np = nmp->n_root; | |
389 | struct ncp_volume_info vi; | |
390 | ||
391 | if (np == NULL) return EINVAL; | |
acde96db MD |
392 | error = ncp_get_volume_info_with_number(NWFSTOCONN(nmp), nmp->n_volume, |
393 | &vi, curthread, cred); | |
984263bc MD |
394 | if (error) return error; |
395 | secsize = 512; /* XXX how to get real value ??? */ | |
396 | sbp->f_spare2=0; /* placeholder */ | |
397 | /* fundamental file system block size */ | |
398 | sbp->f_bsize = vi.sectors_per_block*secsize; | |
399 | /* optimal transfer block size */ | |
400 | sbp->f_iosize = NWFSTOCONN(nmp)->buffer_size; | |
401 | /* total data blocks in file system */ | |
402 | sbp->f_blocks= vi.total_blocks; | |
403 | /* free blocks in fs */ | |
404 | sbp->f_bfree = vi.free_blocks + vi.purgeable_blocks; | |
405 | /* free blocks avail to non-superuser */ | |
406 | sbp->f_bavail= vi.free_blocks+vi.purgeable_blocks; | |
407 | /* total file nodes in file system */ | |
408 | sbp->f_files = vi.total_dir_entries; | |
409 | /* free file nodes in fs */ | |
410 | sbp->f_ffree = vi.available_dir_entries; | |
411 | sbp->f_flags = 0; /* copy of mount exported flags */ | |
412 | if (sbp != &mp->mnt_stat) { | |
413 | sbp->f_fsid = mp->mnt_stat.f_fsid; /* file system id */ | |
414 | sbp->f_owner = mp->mnt_stat.f_owner; /* user that mounted the filesystem */ | |
415 | sbp->f_type = mp->mnt_vfc->vfc_typenum; /* type of filesystem */ | |
984263bc MD |
416 | bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); |
417 | } | |
418 | strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN); | |
419 | return 0; | |
420 | } | |
421 | ||
422 | /* | |
423 | * Flush out the buffer cache | |
424 | */ | |
425 | /* ARGSUSED */ | |
426 | static int | |
87de5057 | 427 | nwfs_sync(struct mount *mp, int waitfor) |
984263bc MD |
428 | { |
429 | struct vnode *vp; | |
430 | int error, allerror = 0; | |
431 | /* | |
432 | * Force stale buffer cache information to be flushed. | |
433 | */ | |
434 | loop: | |
435 | for (vp = TAILQ_FIRST(&mp->mnt_nvnodelist); | |
436 | vp != NULL; | |
437 | vp = TAILQ_NEXT(vp, v_nmntvnodes)) { | |
438 | /* | |
439 | * If the vnode that we are about to sync is no longer | |
440 | * associated with this mount point, start over. | |
441 | */ | |
442 | if (vp->v_mount != mp) | |
443 | goto loop; | |
a11aaa81 | 444 | if (vn_islocked(vp) || RB_EMPTY(&vp->v_rbdirty_tree) || |
984263bc MD |
445 | waitfor == MNT_LAZY) |
446 | continue; | |
87de5057 | 447 | if (vget(vp, LK_EXCLUSIVE)) |
984263bc | 448 | goto loop; |
5fd012e0 | 449 | /* XXX vp may not be retained */ |
87de5057 | 450 | error = VOP_FSYNC(vp, waitfor); |
984263bc MD |
451 | if (error) |
452 | allerror = error; | |
453 | vput(vp); | |
454 | } | |
455 | return (allerror); | |
456 | } |