AMD64 - Refactor uio_resid and size_t assumptions.
[dragonfly.git] / sys / vfs / smbfs / smbfs_io.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 2000-2001, 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/fs/smbfs/smbfs_io.c,v 1.3.2.3 2003/01/17 08:20:26 tjr Exp $
1787385d 33 * $DragonFly: src/sys/vfs/smbfs/smbfs_io.c,v 1.29 2007/08/28 01:04:33 dillon Exp $
984263bc
MD
34 *
35 */
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/resourcevar.h> /* defines plimit structure in proc struct */
39#include <sys/kernel.h>
40#include <sys/proc.h>
41#include <sys/fcntl.h>
42#include <sys/mount.h>
43#include <sys/namei.h>
44#include <sys/vnode.h>
45#include <sys/dirent.h>
46#include <sys/signalvar.h>
47#include <sys/sysctl.h>
48
f303230d
JS
49#include <machine/limits.h>
50
984263bc
MD
51#include <vm/vm.h>
52#include <vm/vm_page.h>
53#include <vm/vm_extern.h>
54#include <vm/vm_object.h>
55#include <vm/vm_pager.h>
56#include <vm/vnode_pager.h>
99dd49c5 57
d2438d69
MD
58#include <netproto/smb/smb.h>
59#include <netproto/smb/smb_conn.h>
60#include <netproto/smb/smb_subr.h>
984263bc 61
1f2de5d4
MD
62#include "smbfs.h"
63#include "smbfs_node.h"
64#include "smbfs_subr.h"
984263bc
MD
65
66#include <sys/buf.h>
67
165dba55
DR
68#include <sys/thread2.h>
69
984263bc
MD
70/*#define SMBFS_RWGENERIC*/
71
72extern int smbfs_pbuf_freecnt;
73
74static int smbfs_fastlookup = 1;
75
984263bc
MD
76SYSCTL_DECL(_vfs_smbfs);
77SYSCTL_INT(_vfs_smbfs, OID_AUTO, fastlookup, CTLFLAG_RW, &smbfs_fastlookup, 0, "");
78
984263bc
MD
79static int
80smbfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred)
81{
984263bc
MD
82 struct smb_cred scred;
83 struct smbfs_fctx *ctx;
84 struct vnode *newvp;
9e758ef5 85 struct smbnode *np;
e54488bb 86 int error, offset, retval;
984263bc
MD
87
88 np = VTOSMB(vp);
89 SMBVDEBUG("dirname='%s'\n", np->n_name);
dadab5e9 90 smb_makescred(&scred, uio->uio_td, cred);
f303230d 91
e54488bb 92 if (uio->uio_offset < 0 || uio->uio_offset > INT_MAX)
f303230d
JS
93 return(EINVAL);
94
95 error = 0;
f303230d
JS
96 offset = uio->uio_offset;
97
98 if (uio->uio_resid > 0 && offset < 1) {
99 if (vop_write_dirent(&error, uio, np->n_ino, DT_DIR, 1, "."))
100 goto done;
984263bc 101 if (error)
f303230d 102 goto done;
0de0bb7c 103 ++offset;
984263bc 104 }
f303230d
JS
105
106 if (uio->uio_resid > 0 && offset < 2) {
107 if (vop_write_dirent(&error, uio,
108 np->n_parent ? VTOSMB(np->n_parent)->n_ino : 2,
109 DT_DIR, 2, ".."))
110 goto done;
111 if (error)
112 goto done;
0de0bb7c 113 ++offset;
f303230d
JS
114 }
115
116 if (uio->uio_resid == 0)
117 goto done;
118
984263bc
MD
119 if (offset != np->n_dirofs || np->n_dirseq == NULL) {
120 SMBVDEBUG("Reopening search %ld:%ld\n", offset, np->n_dirofs);
121 if (np->n_dirseq) {
122 smbfs_findclose(np->n_dirseq, &scred);
123 np->n_dirseq = NULL;
124 }
125 np->n_dirofs = 2;
126 error = smbfs_findopen(np, "*", 1,
127 SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
128 &scred, &ctx);
129 if (error) {
130 SMBVDEBUG("can not open search, error = %d", error);
131 return error;
132 }
133 np->n_dirseq = ctx;
0de0bb7c 134 } else {
984263bc 135 ctx = np->n_dirseq;
0de0bb7c 136 }
984263bc 137 while (np->n_dirofs < offset) {
0de0bb7c
MD
138 error = smbfs_findnext(ctx, offset - np->n_dirofs, &scred);
139 ++np->n_dirofs;
984263bc
MD
140 if (error) {
141 smbfs_findclose(np->n_dirseq, &scred);
142 np->n_dirseq = NULL;
143 return error == ENOENT ? 0 : error;
144 }
145 }
146 error = 0;
0de0bb7c 147 while (uio->uio_resid > 0 && !error) {
01f31ab3
JS
148 /*
149 * Overestimate the size of a record a bit, doesn't really
150 * hurt to be wrong here.
151 */
152 error = smbfs_findnext(ctx, uio->uio_resid / _DIRENT_RECLEN(255) + 1, &scred);
984263bc
MD
153 if (error)
154 break;
155 np->n_dirofs++;
0de0bb7c 156 ++offset;
f303230d
JS
157
158 retval = vop_write_dirent(&error, uio, ctx->f_attr.fa_ino,
159 (ctx->f_attr.fa_attr & SMB_FA_DIR) ? DT_DIR : DT_REG,
160 ctx->f_nmlen, ctx->f_name);
161 if (retval)
162 break;
163 if (smbfs_fastlookup && !error) {
984263bc
MD
164 error = smbfs_nget(vp->v_mount, vp, ctx->f_name,
165 ctx->f_nmlen, &ctx->f_attr, &newvp);
fad57d0e 166 if (!error)
984263bc 167 vput(newvp);
984263bc 168 }
984263bc
MD
169 }
170 if (error == ENOENT)
171 error = 0;
f303230d 172done:
0de0bb7c 173 uio->uio_offset = offset;
984263bc
MD
174 return error;
175}
176
177int
178smbfs_readvnode(struct vnode *vp, struct uio *uiop, struct ucred *cred)
179{
dadab5e9 180 struct thread *td;
984263bc
MD
181 struct smbmount *smp = VFSTOSMBFS(vp->v_mount);
182 struct smbnode *np = VTOSMB(vp);
984263bc
MD
183 struct vattr vattr;
184 struct smb_cred scred;
185 int error, lks;
186
187 /*
188 * Protect against method which is not supported for now
189 */
190 if (uiop->uio_segflg == UIO_NOCOPY)
191 return EOPNOTSUPP;
192
193 if (vp->v_type != VREG && vp->v_type != VDIR) {
194 SMBFSERR("vn types other than VREG or VDIR are unsupported !\n");
195 return EIO;
196 }
197 if (uiop->uio_resid == 0)
198 return 0;
199 if (uiop->uio_offset < 0)
200 return EINVAL;
dadab5e9 201 td = uiop->uio_td;
984263bc 202 if (vp->v_type == VDIR) {
dadab5e9 203 lks = LK_EXCLUSIVE;/*lockstatus(&vp->v_lock, td);*/
984263bc 204 if (lks == LK_SHARED)
ca466bae 205 vn_lock(vp, LK_UPGRADE | LK_RETRY);
984263bc
MD
206 error = smbfs_readvdir(vp, uiop, cred);
207 if (lks == LK_SHARED)
ca466bae 208 vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
984263bc
MD
209 return error;
210 }
211
212/* biosize = SSTOCN(smp->sm_share)->sc_txmax;*/
213 if (np->n_flag & NMODIFIED) {
214 smbfs_attr_cacheremove(vp);
87de5057 215 error = VOP_GETATTR(vp, &vattr);
984263bc
MD
216 if (error)
217 return error;
218 np->n_mtime.tv_sec = vattr.va_mtime.tv_sec;
219 } else {
87de5057 220 error = VOP_GETATTR(vp, &vattr);
984263bc
MD
221 if (error)
222 return error;
223 if (np->n_mtime.tv_sec != vattr.va_mtime.tv_sec) {
87de5057 224 error = smbfs_vinvalbuf(vp, V_SAVE, 1);
984263bc
MD
225 if (error)
226 return error;
227 np->n_mtime.tv_sec = vattr.va_mtime.tv_sec;
228 }
229 }
dadab5e9 230 smb_makescred(&scred, td, cred);
984263bc
MD
231 return smb_read(smp->sm_share, np->n_fid, uiop, &scred);
232}
233
234int
235smbfs_writevnode(struct vnode *vp, struct uio *uiop,
9c2a2cee 236 struct ucred *cred, int ioflag)
984263bc 237{
dadab5e9 238 struct thread *td;
984263bc
MD
239 struct smbmount *smp = VTOSMBFS(vp);
240 struct smbnode *np = VTOSMB(vp);
241 struct smb_cred scred;
984263bc
MD
242 int error = 0;
243
244 if (vp->v_type != VREG) {
245 SMBERROR("vn types other than VREG unsupported !\n");
246 return EIO;
247 }
248 SMBVDEBUG("ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid);
249 if (uiop->uio_offset < 0)
250 return EINVAL;
dadab5e9 251 td = uiop->uio_td;
984263bc
MD
252 if (ioflag & (IO_APPEND | IO_SYNC)) {
253 if (np->n_flag & NMODIFIED) {
254 smbfs_attr_cacheremove(vp);
87de5057 255 error = smbfs_vinvalbuf(vp, V_SAVE, 1);
984263bc
MD
256 if (error)
257 return error;
258 }
259 if (ioflag & IO_APPEND) {
260#if notyet
261 /*
262 * File size can be changed by another client
263 */
264 smbfs_attr_cacheremove(vp);
87de5057 265 error = VOP_GETATTR(vp, &vattr);
984263bc
MD
266 if (error) return (error);
267#endif
268 uiop->uio_offset = np->n_size;
269 }
270 }
271 if (uiop->uio_resid == 0)
272 return 0;
dadab5e9
MD
273 if (td->td_proc &&
274 uiop->uio_offset + uiop->uio_resid >
275 td->td_proc->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
7278a846 276 lwpsignal(td->td_proc, td->td_lwp, SIGXFSZ);
984263bc
MD
277 return EFBIG;
278 }
dadab5e9 279 smb_makescred(&scred, td, cred);
984263bc
MD
280 error = smb_write(smp->sm_share, np->n_fid, uiop, &scred);
281 SMBVDEBUG("after: ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid);
282 if (!error) {
283 if (uiop->uio_offset > np->n_size) {
284 np->n_size = uiop->uio_offset;
285 vnode_pager_setsize(vp, np->n_size);
286 }
287 }
288 return error;
289}
290
291/*
292 * Do an I/O operation to/from a cache block.
293 */
294int
81b5c339 295smbfs_doio(struct vnode *vp, struct bio *bio, struct ucred *cr, struct thread *td)
984263bc 296{
81b5c339 297 struct buf *bp = bio->bio_buf;
984263bc
MD
298 struct smbmount *smp = VFSTOSMBFS(vp->v_mount);
299 struct smbnode *np = VTOSMB(vp);
300 struct uio uio, *uiop = &uio;
301 struct iovec io;
302 struct smb_cred scred;
303 int error = 0;
304
305 uiop->uio_iov = &io;
306 uiop->uio_iovcnt = 1;
307 uiop->uio_segflg = UIO_SYSSPACE;
dadab5e9 308 uiop->uio_td = td;
984263bc 309
dadab5e9 310 smb_makescred(&scred, td, cr);
984263bc 311
10f3fee5 312 if (bp->b_cmd == BUF_CMD_READ) {
e54488bb 313 io.iov_len = uiop->uio_resid = (size_t)bp->b_bcount;
984263bc
MD
314 io.iov_base = bp->b_data;
315 uiop->uio_rw = UIO_READ;
316 switch (vp->v_type) {
317 case VREG:
54078292 318 uiop->uio_offset = bio->bio_offset;
984263bc
MD
319 error = smb_read(smp->sm_share, np->n_fid, uiop, &scred);
320 if (error)
321 break;
322 if (uiop->uio_resid) {
e54488bb
MD
323 size_t left = uiop->uio_resid;
324 size_t nread = (size_t)bp->b_bcount - left;
984263bc 325 if (left > 0)
e54488bb 326 bzero((char *)bp->b_data + nread, left);
984263bc
MD
327 }
328 break;
329 default:
086c1d7e 330 kprintf("smbfs_doio: type %x unexpected\n",vp->v_type);
984263bc
MD
331 break;
332 };
333 if (error) {
334 bp->b_error = error;
335 bp->b_flags |= B_ERROR;
336 }
337 } else { /* write */
10f3fee5 338 KKASSERT(bp->b_cmd == BUF_CMD_WRITE);
54078292
MD
339 if (bio->bio_offset + bp->b_dirtyend > np->n_size)
340 bp->b_dirtyend = np->n_size - bio->bio_offset;
984263bc
MD
341
342 if (bp->b_dirtyend > bp->b_dirtyoff) {
e54488bb
MD
343 io.iov_len = uiop->uio_resid =
344 (size_t)(bp->b_dirtyend - bp->b_dirtyoff);
54078292 345 uiop->uio_offset = bio->bio_offset + bp->b_dirtyoff;
984263bc
MD
346 io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
347 uiop->uio_rw = UIO_WRITE;
984263bc 348 error = smb_write(smp->sm_share, np->n_fid, uiop, &scred);
984263bc
MD
349
350 /*
351 * For an interrupted write, the buffer is still valid
352 * and the write hasn't been pushed to the server yet,
353 * so we can't set BIO_ERROR and report the interruption
ae8e83e6 354 * by setting B_EINTR. For the async case, B_EINTR
984263bc
MD
355 * is not relevant, so the rpc attempt is essentially
356 * a noop. For the case of a V3 write rpc not being
357 * committed to stable storage, the block is still
358 * dirty and requires either a commit rpc or another
359 * write rpc with iomode == NFSV3WRITE_FILESYNC before
360 * the block is reused. This is indicated by setting
361 * the B_DELWRI and B_NEEDCOMMIT flags.
362 */
363 if (error == EINTR
364 || (!error && (bp->b_flags & B_NEEDCOMMIT))) {
984263bc 365
165dba55 366 crit_enter();
984263bc 367 bp->b_flags &= ~(B_INVAL|B_NOCACHE);
10f3fee5 368 if ((bp->b_flags & B_PAGING) == 0)
984263bc 369 bdirty(bp);
ae8e83e6 370 bp->b_flags |= B_EINTR;
165dba55 371 crit_exit();
984263bc
MD
372 } else {
373 if (error) {
374 bp->b_flags |= B_ERROR;
375 bp->b_error = error;
376 }
377 bp->b_dirtyoff = bp->b_dirtyend = 0;
378 }
379 } else {
380 bp->b_resid = 0;
81b5c339 381 biodone(bio);
984263bc
MD
382 return 0;
383 }
384 }
385 bp->b_resid = uiop->uio_resid;
81b5c339 386 biodone(bio);
984263bc
MD
387 return error;
388}
389
390/*
391 * Vnode op for VM getpages.
392 * Wish wish .... get rid from multiple IO routines
9c2a2cee
CP
393 *
394 * smbfs_getpages(struct vnode *a_vp, vm_page_t *a_m, int a_count,
395 * int a_reqpage, vm_ooffset_t a_offset)
984263bc
MD
396 */
397int
9c2a2cee 398smbfs_getpages(struct vop_getpages_args *ap)
984263bc
MD
399{
400#ifdef SMBFS_RWGENERIC
1787385d 401 return vop_stdgetpages(ap);
984263bc 402#else
e54488bb 403 int i, error, npages;
5f74815a 404 int doclose;
e54488bb 405 size_t size, toff, nextoff, count;
984263bc
MD
406 struct uio uio;
407 struct iovec iov;
408 vm_offset_t kva;
409 struct buf *bp;
410 struct vnode *vp;
dadab5e9 411 struct thread *td = curthread; /* XXX */
984263bc
MD
412 struct ucred *cred;
413 struct smbmount *smp;
414 struct smbnode *np;
415 struct smb_cred scred;
416 vm_page_t *pages;
417
dadab5e9
MD
418 KKASSERT(td->td_proc);
419
984263bc 420 vp = ap->a_vp;
dadab5e9 421 cred = td->td_proc->p_ucred;
984263bc
MD
422 np = VTOSMB(vp);
423 smp = VFSTOSMBFS(vp->v_mount);
424 pages = ap->a_m;
e54488bb 425 count = (size_t)ap->a_count;
984263bc
MD
426
427 if (vp->v_object == NULL) {
086c1d7e 428 kprintf("smbfs_getpages: called with non-merged cache vnode??\n");
984263bc
MD
429 return VM_PAGER_ERROR;
430 }
dadab5e9 431 smb_makescred(&scred, td, cred);
984263bc
MD
432
433 bp = getpbuf(&smbfs_pbuf_freecnt);
434 npages = btoc(count);
435 kva = (vm_offset_t) bp->b_data;
436 pmap_qenter(kva, pages, npages);
437
438 iov.iov_base = (caddr_t) kva;
439 iov.iov_len = count;
440 uio.uio_iov = &iov;
441 uio.uio_iovcnt = 1;
442 uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
443 uio.uio_resid = count;
444 uio.uio_segflg = UIO_SYSSPACE;
445 uio.uio_rw = UIO_READ;
dadab5e9 446 uio.uio_td = td;
984263bc 447
5f74815a
MD
448 /*
449 * This is kinda nasty. Since smbfs is physically closing the
450 * fid on close(), we have to reopen it if necessary. There are
451 * other races here too, such as if another process opens the same
452 * file while we are blocked in read. XXX
453 */
454 error = 0;
455 doclose = 0;
456 if (np->n_opencount == 0) {
457 error = smbfs_smb_open(np, SMB_AM_OPENREAD, &scred);
458 if (error == 0)
459 doclose = 1;
460 }
461 if (error == 0)
462 error = smb_read(smp->sm_share, np->n_fid, &uio, &scred);
463 if (doclose)
464 smbfs_smb_close(smp->sm_share, np->n_fid, NULL, &scred);
984263bc
MD
465 pmap_qremove(kva, npages);
466
467 relpbuf(bp, &smbfs_pbuf_freecnt);
468
469 if (error && (uio.uio_resid == count)) {
086c1d7e 470 kprintf("smbfs_getpages: error %d\n",error);
984263bc
MD
471 for (i = 0; i < npages; i++) {
472 if (ap->a_reqpage != i)
473 vnode_pager_freepage(pages[i]);
474 }
475 return VM_PAGER_ERROR;
476 }
477
478 size = count - uio.uio_resid;
479
480 for (i = 0, toff = 0; i < npages; i++, toff = nextoff) {
481 vm_page_t m;
482 nextoff = toff + PAGE_SIZE;
483 m = pages[i];
484
485 m->flags &= ~PG_ZERO;
486
487 if (nextoff <= size) {
488 m->valid = VM_PAGE_BITS_ALL;
489 m->dirty = 0;
490 } else {
491 int nvalid = ((size + DEV_BSIZE - 1) - toff) & ~(DEV_BSIZE - 1);
492 vm_page_set_validclean(m, 0, nvalid);
493 }
494
495 if (i != ap->a_reqpage) {
496 /*
497 * Whether or not to leave the page activated is up in
498 * the air, but we should put the page on a page queue
499 * somewhere (it already is in the object). Result:
500 * It appears that emperical results show that
501 * deactivating pages is best.
502 */
503
504 /*
505 * Just in case someone was asking for this page we
506 * now tell them that it is ok to use.
507 */
508 if (!error) {
509 if (m->flags & PG_WANTED)
510 vm_page_activate(m);
511 else
512 vm_page_deactivate(m);
513 vm_page_wakeup(m);
514 } else {
515 vnode_pager_freepage(m);
516 }
517 }
518 }
519 return 0;
520#endif /* SMBFS_RWGENERIC */
521}
522
523/*
524 * Vnode op for VM putpages.
525 * possible bug: all IO done in sync mode
526 * Note that vop_close always invalidate pages before close, so it's
527 * not necessary to open vnode.
9c2a2cee
CP
528 *
529 * smbfs_putpages(struct vnode *a_vp, vm_page_t *a_m, int a_count, int a_sync,
530 * int *a_rtvals, vm_ooffset_t a_offset)
984263bc
MD
531 */
532int
9c2a2cee 533smbfs_putpages(struct vop_putpages_args *ap)
984263bc
MD
534{
535 int error;
536 struct vnode *vp = ap->a_vp;
dadab5e9 537 struct thread *td = curthread; /* XXX */
984263bc
MD
538 struct ucred *cred;
539
540#ifdef SMBFS_RWGENERIC
dadab5e9
MD
541 KKASSERT(td->td_proc);
542 cred = td->td_proc->p_ucred;
87de5057 543 VOP_OPEN(vp, FWRITE, cred, NULL);
1787385d 544 error = vop_stdputpages(ap);
87de5057 545 VOP_CLOSE(vp, FWRITE, cred);
984263bc
MD
546 return error;
547#else
548 struct uio uio;
549 struct iovec iov;
550 vm_offset_t kva;
551 struct buf *bp;
552 int i, npages, count;
5f74815a 553 int doclose;
984263bc
MD
554 int *rtvals;
555 struct smbmount *smp;
556 struct smbnode *np;
557 struct smb_cred scred;
558 vm_page_t *pages;
559
dadab5e9
MD
560 KKASSERT(td->td_proc);
561 cred = td->td_proc->p_ucred;
87de5057 562/* VOP_OPEN(vp, FWRITE, cred, NULL);*/
984263bc
MD
563 np = VTOSMB(vp);
564 smp = VFSTOSMBFS(vp->v_mount);
565 pages = ap->a_m;
566 count = ap->a_count;
567 rtvals = ap->a_rtvals;
568 npages = btoc(count);
569
570 for (i = 0; i < npages; i++) {
571 rtvals[i] = VM_PAGER_AGAIN;
572 }
573
574 bp = getpbuf(&smbfs_pbuf_freecnt);
575 kva = (vm_offset_t) bp->b_data;
576 pmap_qenter(kva, pages, npages);
577
578 iov.iov_base = (caddr_t) kva;
579 iov.iov_len = count;
580 uio.uio_iov = &iov;
581 uio.uio_iovcnt = 1;
582 uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
583 uio.uio_resid = count;
584 uio.uio_segflg = UIO_SYSSPACE;
585 uio.uio_rw = UIO_WRITE;
dadab5e9 586 uio.uio_td = td;
984263bc
MD
587 SMBVDEBUG("ofs=%d,resid=%d\n",(int)uio.uio_offset, uio.uio_resid);
588
dadab5e9 589 smb_makescred(&scred, td, cred);
5f74815a
MD
590
591 /*
592 * This is kinda nasty. Since smbfs is physically closing the
593 * fid on close(), we have to reopen it if necessary. There are
594 * other races here too, such as if another process opens the same
595 * file while we are blocked in read, or the file is open read-only
596 * XXX
597 */
598 error = 0;
599 doclose = 0;
600 if (np->n_opencount == 0) {
601 error = smbfs_smb_open(np, SMB_AM_OPENRW, &scred);
602 if (error == 0)
603 doclose = 1;
604 }
605 if (error == 0)
606 error = smb_write(smp->sm_share, np->n_fid, &uio, &scred);
607 if (doclose)
608 smbfs_smb_close(smp->sm_share, np->n_fid, NULL, &scred);
87de5057 609/* VOP_CLOSE(vp, FWRITE, cred);*/
984263bc
MD
610 SMBVDEBUG("paged write done: %d\n", error);
611
612 pmap_qremove(kva, npages);
613 relpbuf(bp, &smbfs_pbuf_freecnt);
614
615 if (!error) {
616 int nwritten = round_page(count - uio.uio_resid) / PAGE_SIZE;
617 for (i = 0; i < nwritten; i++) {
618 rtvals[i] = VM_PAGER_OK;
619 pages[i]->dirty = 0;
620 }
621 }
622 return rtvals[0];
623#endif /* SMBFS_RWGENERIC */
624}
625
626/*
627 * Flush and invalidate all dirty buffers. If another process is already
628 * doing the flush, just wait for completion.
629 */
630int
87de5057 631smbfs_vinvalbuf(struct vnode *vp, int flags, int intrflg)
984263bc
MD
632{
633 struct smbnode *np = VTOSMB(vp);
634 int error = 0, slpflag, slptimeo;
635
5fd012e0 636 if (vp->v_flag & VRECLAIMED)
984263bc
MD
637 return 0;
638 if (intrflg) {
639 slpflag = PCATCH;
640 slptimeo = 2 * hz;
641 } else {
642 slpflag = 0;
643 slptimeo = 0;
644 }
645 while (np->n_flag & NFLUSHINPROG) {
646 np->n_flag |= NFLUSHWANT;
377d4740 647 error = tsleep((caddr_t)&np->n_flag, 0, "smfsvinv", slptimeo);
87de5057 648 error = smb_proc_intr(curthread);
984263bc
MD
649 if (error == EINTR && intrflg)
650 return EINTR;
651 }
652 np->n_flag |= NFLUSHINPROG;
87de5057 653 error = vinvalbuf(vp, flags, slpflag, 0);
984263bc
MD
654 while (error) {
655 if (intrflg && (error == ERESTART || error == EINTR)) {
656 np->n_flag &= ~NFLUSHINPROG;
657 if (np->n_flag & NFLUSHWANT) {
658 np->n_flag &= ~NFLUSHWANT;
659 wakeup((caddr_t)&np->n_flag);
660 }
661 return EINTR;
662 }
87de5057 663 error = vinvalbuf(vp, flags, slpflag, 0);
984263bc
MD
664 }
665 np->n_flag &= ~(NMODIFIED | NFLUSHINPROG);
666 if (np->n_flag & NFLUSHWANT) {
667 np->n_flag &= ~NFLUSHWANT;
668 wakeup((caddr_t)&np->n_flag);
669 }
670 return (error);
671}