FreeBSD/Linux Kernel Cross Reference
sys/fs/nwfs/nwfs_io.c
1 /*-
2 * Copyright (c) 1999 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 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD$
27 *
28 */
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/bio.h>
33 #include <sys/buf.h>
34 #include <sys/mount.h>
35 #include <sys/namei.h>
36 #include <sys/vnode.h>
37 #include <sys/dirent.h>
38 #include <sys/sysctl.h>
39
40 #include <vm/vm.h>
41 #include <vm/vm_param.h>
42 #include <vm/vm_page.h>
43 #include <vm/vm_extern.h>
44 #include <vm/vm_object.h>
45 #include <vm/vm_pager.h>
46 #include <vm/vnode_pager.h>
47
48 #include <netncp/ncp.h>
49 #include <netncp/ncp_conn.h>
50 #include <netncp/ncp_subr.h>
51 #include <netncp/ncp_ncp.h>
52
53 #include <fs/nwfs/nwfs.h>
54 #include <fs/nwfs/nwfs_node.h>
55 #include <fs/nwfs/nwfs_subr.h>
56
57 static int nwfs_fastlookup = 1;
58
59 SYSCTL_DECL(_vfs_nwfs);
60 SYSCTL_INT(_vfs_nwfs, OID_AUTO, fastlookup, CTLFLAG_RW, &nwfs_fastlookup, 0, "");
61
62
63 extern int nwfs_pbuf_freecnt;
64
65 #define DE_SIZE (sizeof(struct dirent))
66 #define NWFS_RWCACHE
67
68 static int
69 nwfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred) {
70 struct nwmount *nmp = VTONWFS(vp);
71 int error, count, i;
72 struct dirent dp;
73 struct nwnode *np = VTONW(vp);
74 struct nw_entry_info fattr;
75 struct vnode *newvp;
76 struct componentname cn;
77 ncpfid fid;
78
79 np = VTONW(vp);
80 NCPVNDEBUG("dirname='%s'\n",np->n_name);
81 if (uio->uio_resid < DE_SIZE || (uio->uio_offset < 0))
82 return (EINVAL);
83 error = 0;
84 count = 0;
85 i = uio->uio_offset / DE_SIZE; /* offset in directory */
86 if (i == 0) {
87 error = ncp_initsearch(vp, uio->uio_td, cred);
88 if (error) {
89 NCPVNDEBUG("cannot initialize search, error=%d",error);
90 return( error );
91 }
92 }
93
94 for (; uio->uio_resid >= DE_SIZE; i++) {
95 bzero((char *) &dp, DE_SIZE);
96 dp.d_reclen = DE_SIZE;
97 switch (i) {
98 case 0: /* `.' */
99 case 1: /* `..' */
100 dp.d_fileno = (i == 0) ? np->n_fid.f_id : np->n_parent.f_id;
101 if (!dp.d_fileno) dp.d_fileno = NWFS_ROOT_INO;
102 dp.d_namlen = i + 1;
103 dp.d_name[0] = '.';
104 dp.d_name[1] = '.';
105 dp.d_name[i + 1] = '\0';
106 dp.d_type = DT_DIR;
107 break;
108 default:
109 error = ncp_search_for_file_or_subdir(nmp, &np->n_seq, &fattr, uio->uio_td, cred);
110 if (error && error < 0x80) break;
111 dp.d_fileno = fattr.dirEntNum;
112 dp.d_type = (fattr.attributes & aDIR) ? DT_DIR : DT_REG;
113 dp.d_namlen = fattr.nameLen;
114 bcopy(fattr.entryName, dp.d_name, dp.d_namlen);
115 dp.d_name[dp.d_namlen] = '\0';
116 #if 0
117 if (error && eofflag) {
118 /* *eofflag = 1;*/
119 break;
120 }
121 #endif
122 break;
123 }
124 if (nwfs_fastlookup && !error && i > 1) {
125 fid.f_id = fattr.dirEntNum;
126 fid.f_parent = np->n_fid.f_id;
127 error = nwfs_nget(vp->v_mount, fid, &fattr, vp, &newvp);
128 if (!error) {
129 VTONW(newvp)->n_ctime = VTONW(newvp)->n_vattr.va_ctime.tv_sec;
130 cn.cn_nameptr = dp.d_name;
131 cn.cn_namelen = dp.d_namlen;
132 cache_enter(vp, newvp, &cn);
133 vput(newvp);
134 } else
135 error = 0;
136 }
137 if (error >= 0x80) {
138 error = 0;
139 break;
140 }
141 if ((error = uiomove(&dp, DE_SIZE, uio)))
142 break;
143 }
144
145 uio->uio_offset = i * DE_SIZE;
146 return (error);
147 }
148
149 int
150 nwfs_readvnode(struct vnode *vp, struct uio *uiop, struct ucred *cred) {
151 struct nwmount *nmp = VFSTONWFS(vp->v_mount);
152 struct nwnode *np = VTONW(vp);
153 struct thread *td;
154 struct vattr vattr;
155 int error, biosize;
156
157 if (vp->v_type != VREG && vp->v_type != VDIR) {
158 printf("%s: vn types other than VREG or VDIR are unsupported !\n",__func__);
159 return EIO;
160 }
161 if (uiop->uio_resid == 0) return 0;
162 if (uiop->uio_offset < 0) return EINVAL;
163 /* if (uiop->uio_offset + uiop->uio_resid > nmp->nm_maxfilesize)
164 return (EFBIG);*/
165 td = uiop->uio_td;
166 if (vp->v_type == VDIR) {
167 error = nwfs_readvdir(vp, uiop, cred);
168 return error;
169 }
170 biosize = NWFSTOCONN(nmp)->buffer_size;
171 if (np->n_flag & NMODIFIED) {
172 nwfs_attr_cacheremove(vp);
173 error = VOP_GETATTR(vp, &vattr, cred);
174 if (error) return (error);
175 np->n_mtime = vattr.va_mtime.tv_sec;
176 } else {
177 error = VOP_GETATTR(vp, &vattr, cred);
178 if (error) return (error);
179 if (np->n_mtime != vattr.va_mtime.tv_sec) {
180 error = nwfs_vinvalbuf(vp, td);
181 if (error) return (error);
182 np->n_mtime = vattr.va_mtime.tv_sec;
183 }
184 }
185 error = ncp_read(NWFSTOCONN(nmp), &np->n_fh, uiop, cred);
186 return (error);
187 }
188
189 int
190 nwfs_writevnode(vp, uiop, cred, ioflag)
191 struct vnode *vp;
192 struct uio *uiop;
193 struct ucred *cred;
194 int ioflag;
195 {
196 struct nwmount *nmp = VTONWFS(vp);
197 struct nwnode *np = VTONW(vp);
198 struct thread *td;
199 /* struct vattr vattr;*/
200 int error = 0;
201
202 if (vp->v_type != VREG) {
203 printf("%s: vn types other than VREG unsupported !\n",__func__);
204 return EIO;
205 }
206 NCPVNDEBUG("ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid);
207 if (uiop->uio_offset < 0) return EINVAL;
208 /* if (uiop->uio_offset + uiop->uio_resid > nmp->nm_maxfilesize)
209 return (EFBIG);*/
210 td = uiop->uio_td;
211 if (ioflag & (IO_APPEND | IO_SYNC)) {
212 if (np->n_flag & NMODIFIED) {
213 nwfs_attr_cacheremove(vp);
214 error = nwfs_vinvalbuf(vp, td);
215 if (error) return (error);
216 }
217 if (ioflag & IO_APPEND) {
218 /* We can relay only on local information about file size,
219 * because until file is closed NetWare will not return
220 * the correct size. */
221 #ifdef notyet
222 nwfs_attr_cacheremove(vp);
223 error = VOP_GETATTR(vp, &vattr, cred);
224 if (error) return (error);
225 #endif
226 uiop->uio_offset = np->n_size;
227 }
228 }
229 if (uiop->uio_resid == 0) return 0;
230
231 if (vn_rlimit_fsize(vp, uiop, td))
232 return (EFBIG);
233
234 error = ncp_write(NWFSTOCONN(nmp), &np->n_fh, uiop, cred);
235 NCPVNDEBUG("after: ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid);
236 if (!error) {
237 if (uiop->uio_offset > np->n_size) {
238 np->n_vattr.va_size = np->n_size = uiop->uio_offset;
239 vnode_pager_setsize(vp, np->n_size);
240 }
241 }
242 return (error);
243 }
244
245 /*
246 * Do an I/O operation to/from a cache block.
247 */
248 int
249 nwfs_doio(vp, bp, cr, td)
250 struct vnode *vp;
251 struct buf *bp;
252 struct ucred *cr;
253 struct thread *td;
254 {
255 struct uio *uiop;
256 struct nwnode *np;
257 struct nwmount *nmp;
258 int error = 0;
259 struct uio uio;
260 struct iovec io;
261
262 np = VTONW(vp);
263 nmp = VFSTONWFS(vp->v_mount);
264 uiop = &uio;
265 uiop->uio_iov = &io;
266 uiop->uio_iovcnt = 1;
267 uiop->uio_segflg = UIO_SYSSPACE;
268 uiop->uio_td = td;
269 if (bp->b_iocmd == BIO_READ) {
270 io.iov_len = uiop->uio_resid = bp->b_bcount;
271 io.iov_base = bp->b_data;
272 uiop->uio_rw = UIO_READ;
273 switch (vp->v_type) {
274 case VREG:
275 uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE;
276 error = ncp_read(NWFSTOCONN(nmp), &np->n_fh, uiop, cr);
277 if (error)
278 break;
279 if (uiop->uio_resid) {
280 int left = uiop->uio_resid;
281 int nread = bp->b_bcount - left;
282 if (left > 0)
283 bzero((char *)bp->b_data + nread, left);
284 }
285 break;
286 /* case VDIR:
287 nfsstats.readdir_bios++;
288 uiop->uio_offset = ((u_quad_t)bp->b_lblkno) * NFS_DIRBLKSIZ;
289 if (nmp->nm_flag & NFSMNT_RDIRPLUS) {
290 error = nfs_readdirplusrpc(vp, uiop, cr);
291 if (error == NFSERR_NOTSUPP)
292 nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
293 }
294 if ((nmp->nm_flag & NFSMNT_RDIRPLUS) == 0)
295 error = nfs_readdirrpc(vp, uiop, cr);
296 if (error == 0 && uiop->uio_resid == bp->b_bcount)
297 bp->b_flags |= B_INVAL;
298 break;
299 */
300 default:
301 printf("nwfs_doio: type %x unexpected\n",vp->v_type);
302 break;
303 };
304 if (error) {
305 bp->b_ioflags |= BIO_ERROR;
306 bp->b_error = error;
307 }
308 } else { /* write */
309 if (((bp->b_blkno * DEV_BSIZE) + bp->b_dirtyend) > np->n_size)
310 bp->b_dirtyend = np->n_size - (bp->b_blkno * DEV_BSIZE);
311
312 if (bp->b_dirtyend > bp->b_dirtyoff) {
313 io.iov_len = uiop->uio_resid = bp->b_dirtyend - bp->b_dirtyoff;
314 uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff;
315 io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
316 uiop->uio_rw = UIO_WRITE;
317 error = ncp_write(NWFSTOCONN(nmp), &np->n_fh, uiop, cr);
318
319 /*
320 * For an interrupted write, the buffer is still valid
321 * and the write hasn't been pushed to the server yet,
322 * so we can't set BIO_ERROR and report the interruption
323 * by setting B_EINTR. For the B_ASYNC case, B_EINTR
324 * is not relevant, so the rpc attempt is essentially
325 * a noop. For the case of a V3 write rpc not being
326 * committed to stable storage, the block is still
327 * dirty and requires either a commit rpc or another
328 * write rpc with iomode == NFSV3WRITE_FILESYNC before
329 * the block is reused. This is indicated by setting
330 * the B_DELWRI and B_NEEDCOMMIT flags.
331 */
332 if (error == EINTR
333 || (!error && (bp->b_flags & B_NEEDCOMMIT))) {
334 int s;
335
336 s = splbio();
337 bp->b_flags &= ~(B_INVAL|B_NOCACHE);
338 if ((bp->b_flags & B_ASYNC) == 0)
339 bp->b_flags |= B_EINTR;
340 if ((bp->b_flags & B_PAGING) == 0) {
341 bdirty(bp);
342 bp->b_flags &= ~B_DONE;
343 }
344 if ((bp->b_flags & B_ASYNC) == 0)
345 bp->b_flags |= B_EINTR;
346 splx(s);
347 } else {
348 if (error) {
349 bp->b_ioflags |= BIO_ERROR;
350 bp->b_error /*= np->n_error */= error;
351 /* np->n_flag |= NWRITEERR;*/
352 }
353 bp->b_dirtyoff = bp->b_dirtyend = 0;
354 }
355 } else {
356 bp->b_resid = 0;
357 bufdone(bp);
358 return (0);
359 }
360 }
361 bp->b_resid = uiop->uio_resid;
362 bufdone(bp);
363 return (error);
364 }
365
366 /*
367 * Vnode op for VM getpages.
368 * Wish wish .... get rid from multiple IO routines
369 */
370 int
371 nwfs_getpages(ap)
372 struct vop_getpages_args /* {
373 struct vnode *a_vp;
374 vm_page_t *a_m;
375 int a_count;
376 int a_reqpage;
377 vm_ooffset_t a_offset;
378 } */ *ap;
379 {
380 #ifndef NWFS_RWCACHE
381 return vop_stdgetpages(ap);(ap->a_vp, ap->a_m, ap->a_count,
382 #else
383 int i, error, nextoff, size, toff, npages, count;
384 struct uio uio;
385 struct iovec iov;
386 vm_offset_t kva;
387 struct buf *bp;
388 struct vnode *vp;
389 struct thread *td;
390 struct ucred *cred;
391 struct nwmount *nmp;
392 struct nwnode *np;
393 vm_object_t object;
394 vm_page_t *pages;
395
396 vp = ap->a_vp;
397 td = curthread; /* XXX */
398 cred = td->td_ucred; /* XXX */
399 np = VTONW(vp);
400 nmp = VFSTONWFS(vp->v_mount);
401 pages = ap->a_m;
402 count = ap->a_count;
403
404 if ((object = vp->v_object) == NULL) {
405 printf("nwfs_getpages: called with non-merged cache vnode??\n");
406 return VM_PAGER_ERROR;
407 }
408
409 bp = getpbuf(&nwfs_pbuf_freecnt);
410 npages = btoc(count);
411 kva = (vm_offset_t) bp->b_data;
412 pmap_qenter(kva, pages, npages);
413
414 iov.iov_base = (caddr_t) kva;
415 iov.iov_len = count;
416 uio.uio_iov = &iov;
417 uio.uio_iovcnt = 1;
418 uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
419 uio.uio_resid = count;
420 uio.uio_segflg = UIO_SYSSPACE;
421 uio.uio_rw = UIO_READ;
422 uio.uio_td = td;
423
424 error = ncp_read(NWFSTOCONN(nmp), &np->n_fh, &uio,cred);
425 pmap_qremove(kva, npages);
426
427 relpbuf(bp, &nwfs_pbuf_freecnt);
428
429 VM_OBJECT_LOCK(object);
430 if (error && (uio.uio_resid == count)) {
431 printf("nwfs_getpages: error %d\n",error);
432 for (i = 0; i < npages; i++) {
433 if (ap->a_reqpage != i) {
434 vm_page_lock(pages[i]);
435 vm_page_free(pages[i]);
436 vm_page_unlock(pages[i]);
437 }
438 }
439 VM_OBJECT_UNLOCK(object);
440 return VM_PAGER_ERROR;
441 }
442
443 size = count - uio.uio_resid;
444
445 for (i = 0, toff = 0; i < npages; i++, toff = nextoff) {
446 vm_page_t m;
447 nextoff = toff + PAGE_SIZE;
448 m = pages[i];
449
450 if (nextoff <= size) {
451 m->valid = VM_PAGE_BITS_ALL;
452 KASSERT(m->dirty == 0,
453 ("nwfs_getpages: page %p is dirty", m));
454 } else {
455 int nvalid = ((size + DEV_BSIZE - 1) - toff) & ~(DEV_BSIZE - 1);
456 vm_page_set_valid(m, 0, nvalid);
457 KASSERT((m->dirty & vm_page_bits(0, nvalid)) == 0,
458 ("nwfs_getpages: page %p is dirty", m));
459 }
460
461 if (i != ap->a_reqpage)
462 vm_page_readahead_finish(m);
463 }
464 VM_OBJECT_UNLOCK(object);
465 return 0;
466 #endif /* NWFS_RWCACHE */
467 }
468
469 /*
470 * Vnode op for VM putpages.
471 * possible bug: all IO done in sync mode
472 * Note that vop_close always invalidate pages before close, so it's
473 * not necessary to open vnode.
474 */
475 int
476 nwfs_putpages(ap)
477 struct vop_putpages_args /* {
478 struct vnode *a_vp;
479 vm_page_t *a_m;
480 int a_count;
481 int a_sync;
482 int *a_rtvals;
483 vm_ooffset_t a_offset;
484 } */ *ap;
485 {
486 int error;
487 struct vnode *vp = ap->a_vp;
488 struct thread *td;
489 struct ucred *cred;
490
491 #ifndef NWFS_RWCACHE
492 td = curthread; /* XXX */
493 cred = td->td_ucred; /* XXX */
494 VOP_OPEN(vp, FWRITE, cred, td, NULL);
495 error = vop_stdputpages(ap);
496 VOP_CLOSE(vp, FWRITE, cred, td);
497 return error;
498 #else
499 struct uio uio;
500 struct iovec iov;
501 vm_offset_t kva;
502 struct buf *bp;
503 int i, npages, count;
504 int *rtvals;
505 struct nwmount *nmp;
506 struct nwnode *np;
507 vm_page_t *pages;
508
509 td = curthread; /* XXX */
510 cred = td->td_ucred; /* XXX */
511 /* VOP_OPEN(vp, FWRITE, cred, td, NULL);*/
512 np = VTONW(vp);
513 nmp = VFSTONWFS(vp->v_mount);
514 pages = ap->a_m;
515 count = ap->a_count;
516 rtvals = ap->a_rtvals;
517 npages = btoc(count);
518
519 for (i = 0; i < npages; i++) {
520 rtvals[i] = VM_PAGER_ERROR;
521 }
522
523 bp = getpbuf(&nwfs_pbuf_freecnt);
524 kva = (vm_offset_t) bp->b_data;
525 pmap_qenter(kva, pages, npages);
526
527 iov.iov_base = (caddr_t) kva;
528 iov.iov_len = count;
529 uio.uio_iov = &iov;
530 uio.uio_iovcnt = 1;
531 uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
532 uio.uio_resid = count;
533 uio.uio_segflg = UIO_SYSSPACE;
534 uio.uio_rw = UIO_WRITE;
535 uio.uio_td = td;
536 NCPVNDEBUG("ofs=%d,resid=%d\n",(int)uio.uio_offset, uio.uio_resid);
537
538 error = ncp_write(NWFSTOCONN(nmp), &np->n_fh, &uio, cred);
539 /* VOP_CLOSE(vp, FWRITE, cred, td);*/
540 NCPVNDEBUG("paged write done: %d\n", error);
541
542 pmap_qremove(kva, npages);
543 relpbuf(bp, &nwfs_pbuf_freecnt);
544
545 if (!error)
546 vnode_pager_undirty_pages(pages, rtvals, count - uio.uio_resid);
547 return rtvals[0];
548 #endif /* NWFS_RWCACHE */
549 }
550 /*
551 * Flush and invalidate all dirty buffers. If another process is already
552 * doing the flush, just wait for completion.
553 */
554 int
555 nwfs_vinvalbuf(vp, td)
556 struct vnode *vp;
557 struct thread *td;
558 {
559 struct nwnode *np = VTONW(vp);
560 /* struct nwmount *nmp = VTONWFS(vp);*/
561 int error = 0;
562
563 if (vp->v_iflag & VI_DOOMED)
564 return (0);
565
566 while (np->n_flag & NFLUSHINPROG) {
567 np->n_flag |= NFLUSHWANT;
568 error = tsleep(&np->n_flag, PRIBIO + 2, "nwfsvinv", 2 * hz);
569 error = ncp_chkintr(NWFSTOCONN(VTONWFS(vp)), td);
570 if (error == EINTR)
571 return EINTR;
572 }
573 np->n_flag |= NFLUSHINPROG;
574
575 if (vp->v_bufobj.bo_object != NULL) {
576 VM_OBJECT_LOCK(vp->v_bufobj.bo_object);
577 vm_object_page_clean(vp->v_bufobj.bo_object, 0, 0, OBJPC_SYNC);
578 VM_OBJECT_UNLOCK(vp->v_bufobj.bo_object);
579 }
580
581 error = vinvalbuf(vp, V_SAVE, PCATCH, 0);
582 while (error) {
583 if (error == ERESTART || error == EINTR) {
584 np->n_flag &= ~NFLUSHINPROG;
585 if (np->n_flag & NFLUSHWANT) {
586 np->n_flag &= ~NFLUSHWANT;
587 wakeup(&np->n_flag);
588 }
589 return EINTR;
590 }
591 error = vinvalbuf(vp, V_SAVE, PCATCH, 0);
592 }
593 np->n_flag &= ~(NMODIFIED | NFLUSHINPROG);
594 if (np->n_flag & NFLUSHWANT) {
595 np->n_flag &= ~NFLUSHWANT;
596 wakeup(&np->n_flag);
597 }
598 return (error);
599 }
Cache object: 30341464f1c04a5595d4a446717bdd9c
|