Print this page
5382 pvn_getpages handles lengths <= PAGESIZE just fine
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/fs/pcfs/pc_vnops.c
+++ new/usr/src/uts/common/fs/pcfs/pc_vnops.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /*
28 28 * Copyright (c) 2013, Joyent, Inc. All rights reserved.
29 + * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
29 30 */
30 31
31 32 #include <sys/param.h>
32 33 #include <sys/t_lock.h>
33 34 #include <sys/systm.h>
34 35 #include <sys/sysmacros.h>
35 36 #include <sys/user.h>
36 37 #include <sys/buf.h>
37 38 #include <sys/stat.h>
38 39 #include <sys/vfs.h>
39 40 #include <sys/vfs_opreg.h>
40 41 #include <sys/dirent.h>
41 42 #include <sys/vnode.h>
42 43 #include <sys/proc.h>
43 44 #include <sys/file.h>
44 45 #include <sys/fcntl.h>
45 46 #include <sys/uio.h>
46 47 #include <sys/fs/pc_label.h>
47 48 #include <sys/fs/pc_fs.h>
48 49 #include <sys/fs/pc_dir.h>
49 50 #include <sys/fs/pc_node.h>
50 51 #include <sys/mman.h>
51 52 #include <sys/pathname.h>
52 53 #include <sys/vmsystm.h>
53 54 #include <sys/cmn_err.h>
54 55 #include <sys/debug.h>
55 56 #include <sys/statvfs.h>
56 57 #include <sys/unistd.h>
57 58 #include <sys/kmem.h>
58 59 #include <sys/conf.h>
59 60 #include <sys/flock.h>
60 61 #include <sys/policy.h>
61 62 #include <sys/sdt.h>
62 63 #include <sys/sunddi.h>
63 64 #include <sys/types.h>
64 65 #include <sys/errno.h>
65 66
66 67 #include <vm/seg.h>
67 68 #include <vm/page.h>
68 69 #include <vm/pvn.h>
69 70 #include <vm/seg_map.h>
70 71 #include <vm/seg_vn.h>
71 72 #include <vm/hat.h>
72 73 #include <vm/as.h>
73 74 #include <vm/seg_kmem.h>
74 75
75 76 #include <fs/fs_subr.h>
76 77
77 78 static int pcfs_open(struct vnode **, int, struct cred *, caller_context_t *ct);
78 79 static int pcfs_close(struct vnode *, int, int, offset_t, struct cred *,
79 80 caller_context_t *ct);
80 81 static int pcfs_read(struct vnode *, struct uio *, int, struct cred *,
81 82 caller_context_t *);
82 83 static int pcfs_write(struct vnode *, struct uio *, int, struct cred *,
83 84 caller_context_t *);
84 85 static int pcfs_getattr(struct vnode *, struct vattr *, int, struct cred *,
85 86 caller_context_t *ct);
86 87 static int pcfs_setattr(struct vnode *, struct vattr *, int, struct cred *,
87 88 caller_context_t *);
88 89 static int pcfs_access(struct vnode *, int, int, struct cred *,
89 90 caller_context_t *ct);
90 91 static int pcfs_lookup(struct vnode *, char *, struct vnode **,
91 92 struct pathname *, int, struct vnode *, struct cred *,
92 93 caller_context_t *, int *, pathname_t *);
93 94 static int pcfs_create(struct vnode *, char *, struct vattr *,
94 95 enum vcexcl, int mode, struct vnode **, struct cred *, int,
95 96 caller_context_t *, vsecattr_t *);
96 97 static int pcfs_remove(struct vnode *, char *, struct cred *,
97 98 caller_context_t *, int);
98 99 static int pcfs_rename(struct vnode *, char *, struct vnode *, char *,
99 100 struct cred *, caller_context_t *, int);
100 101 static int pcfs_mkdir(struct vnode *, char *, struct vattr *, struct vnode **,
101 102 struct cred *, caller_context_t *, int, vsecattr_t *);
102 103 static int pcfs_rmdir(struct vnode *, char *, struct vnode *, struct cred *,
103 104 caller_context_t *, int);
104 105 static int pcfs_readdir(struct vnode *, struct uio *, struct cred *, int *,
105 106 caller_context_t *, int);
106 107 static int pcfs_fsync(struct vnode *, int, struct cred *, caller_context_t *);
107 108 static void pcfs_inactive(struct vnode *, struct cred *, caller_context_t *);
108 109 static int pcfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *);
109 110 static int pcfs_space(struct vnode *, int, struct flock64 *, int,
110 111 offset_t, cred_t *, caller_context_t *);
111 112 static int pcfs_getpage(struct vnode *, offset_t, size_t, uint_t *, page_t *[],
112 113 size_t, struct seg *, caddr_t, enum seg_rw, struct cred *,
113 114 caller_context_t *);
114 115 static int pcfs_getapage(struct vnode *, u_offset_t, size_t, uint_t *,
115 116 page_t *[], size_t, struct seg *, caddr_t, enum seg_rw, struct cred *);
116 117 static int pcfs_putpage(struct vnode *, offset_t, size_t, int, struct cred *,
117 118 caller_context_t *);
118 119 static int pcfs_map(struct vnode *, offset_t, struct as *, caddr_t *, size_t,
119 120 uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *);
120 121 static int pcfs_addmap(struct vnode *, offset_t, struct as *, caddr_t,
121 122 size_t, uchar_t, uchar_t, uint_t, struct cred *, caller_context_t *);
122 123 static int pcfs_delmap(struct vnode *, offset_t, struct as *, caddr_t,
123 124 size_t, uint_t, uint_t, uint_t, struct cred *, caller_context_t *);
124 125 static int pcfs_seek(struct vnode *, offset_t, offset_t *,
125 126 caller_context_t *);
126 127 static int pcfs_pathconf(struct vnode *, int, ulong_t *, struct cred *,
127 128 caller_context_t *);
128 129
129 130 int pcfs_putapage(struct vnode *, page_t *, u_offset_t *, size_t *, int,
130 131 struct cred *);
131 132 static int rwpcp(struct pcnode *, struct uio *, enum uio_rw, int);
132 133 static int get_long_fn_chunk(struct pcdir_lfn *ep, char *buf);
133 134
134 135 extern krwlock_t pcnodes_lock;
135 136
136 137 #define lround(r) (((r)+sizeof (long long)-1)&(~(sizeof (long long)-1)))
137 138
138 139 /*
139 140 * vnode op vectors for files and directories.
140 141 */
141 142 struct vnodeops *pcfs_fvnodeops;
142 143 struct vnodeops *pcfs_dvnodeops;
143 144
144 145 const fs_operation_def_t pcfs_fvnodeops_template[] = {
145 146 VOPNAME_OPEN, { .vop_open = pcfs_open },
146 147 VOPNAME_CLOSE, { .vop_close = pcfs_close },
147 148 VOPNAME_READ, { .vop_read = pcfs_read },
148 149 VOPNAME_WRITE, { .vop_write = pcfs_write },
149 150 VOPNAME_GETATTR, { .vop_getattr = pcfs_getattr },
150 151 VOPNAME_SETATTR, { .vop_setattr = pcfs_setattr },
151 152 VOPNAME_ACCESS, { .vop_access = pcfs_access },
152 153 VOPNAME_FSYNC, { .vop_fsync = pcfs_fsync },
153 154 VOPNAME_INACTIVE, { .vop_inactive = pcfs_inactive },
154 155 VOPNAME_FID, { .vop_fid = pcfs_fid },
155 156 VOPNAME_SEEK, { .vop_seek = pcfs_seek },
156 157 VOPNAME_SPACE, { .vop_space = pcfs_space },
157 158 VOPNAME_GETPAGE, { .vop_getpage = pcfs_getpage },
158 159 VOPNAME_PUTPAGE, { .vop_putpage = pcfs_putpage },
159 160 VOPNAME_MAP, { .vop_map = pcfs_map },
160 161 VOPNAME_ADDMAP, { .vop_addmap = pcfs_addmap },
161 162 VOPNAME_DELMAP, { .vop_delmap = pcfs_delmap },
162 163 VOPNAME_PATHCONF, { .vop_pathconf = pcfs_pathconf },
163 164 VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support },
164 165 NULL, NULL
165 166 };
166 167
167 168 const fs_operation_def_t pcfs_dvnodeops_template[] = {
168 169 VOPNAME_OPEN, { .vop_open = pcfs_open },
169 170 VOPNAME_CLOSE, { .vop_close = pcfs_close },
170 171 VOPNAME_GETATTR, { .vop_getattr = pcfs_getattr },
171 172 VOPNAME_SETATTR, { .vop_setattr = pcfs_setattr },
172 173 VOPNAME_ACCESS, { .vop_access = pcfs_access },
173 174 VOPNAME_LOOKUP, { .vop_lookup = pcfs_lookup },
174 175 VOPNAME_CREATE, { .vop_create = pcfs_create },
175 176 VOPNAME_REMOVE, { .vop_remove = pcfs_remove },
176 177 VOPNAME_RENAME, { .vop_rename = pcfs_rename },
177 178 VOPNAME_MKDIR, { .vop_mkdir = pcfs_mkdir },
178 179 VOPNAME_RMDIR, { .vop_rmdir = pcfs_rmdir },
179 180 VOPNAME_READDIR, { .vop_readdir = pcfs_readdir },
180 181 VOPNAME_FSYNC, { .vop_fsync = pcfs_fsync },
181 182 VOPNAME_INACTIVE, { .vop_inactive = pcfs_inactive },
182 183 VOPNAME_FID, { .vop_fid = pcfs_fid },
183 184 VOPNAME_SEEK, { .vop_seek = pcfs_seek },
184 185 VOPNAME_PATHCONF, { .vop_pathconf = pcfs_pathconf },
185 186 VOPNAME_VNEVENT, { .vop_vnevent = fs_vnevent_support },
186 187 NULL, NULL
187 188 };
188 189
189 190
190 191 /*ARGSUSED*/
191 192 static int
192 193 pcfs_open(
193 194 struct vnode **vpp,
194 195 int flag,
195 196 struct cred *cr,
196 197 caller_context_t *ct)
197 198 {
198 199 return (0);
199 200 }
200 201
201 202 /*
202 203 * files are sync'ed on close to keep floppy up to date
203 204 */
204 205
205 206 /*ARGSUSED*/
206 207 static int
207 208 pcfs_close(
208 209 struct vnode *vp,
209 210 int flag,
210 211 int count,
211 212 offset_t offset,
212 213 struct cred *cr,
213 214 caller_context_t *ct)
214 215 {
215 216 return (0);
216 217 }
217 218
218 219 /*ARGSUSED*/
219 220 static int
220 221 pcfs_read(
221 222 struct vnode *vp,
222 223 struct uio *uiop,
223 224 int ioflag,
224 225 struct cred *cr,
225 226 struct caller_context *ct)
226 227 {
227 228 struct pcfs *fsp;
228 229 struct pcnode *pcp;
229 230 int error;
230 231
231 232 fsp = VFSTOPCFS(vp->v_vfsp);
232 233 if (error = pc_verify(fsp))
233 234 return (error);
234 235 error = pc_lockfs(fsp, 0, 0);
235 236 if (error)
236 237 return (error);
237 238 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
238 239 pc_unlockfs(fsp);
239 240 return (EIO);
240 241 }
241 242 error = rwpcp(pcp, uiop, UIO_READ, ioflag);
242 243 if ((fsp->pcfs_vfs->vfs_flag & VFS_RDONLY) == 0) {
243 244 pc_mark_acc(fsp, pcp);
244 245 }
245 246 pc_unlockfs(fsp);
246 247 if (error) {
247 248 PC_DPRINTF1(1, "pcfs_read: io error = %d\n", error);
248 249 }
249 250 return (error);
250 251 }
251 252
252 253 /*ARGSUSED*/
253 254 static int
254 255 pcfs_write(
255 256 struct vnode *vp,
256 257 struct uio *uiop,
257 258 int ioflag,
258 259 struct cred *cr,
259 260 struct caller_context *ct)
260 261 {
261 262 struct pcfs *fsp;
262 263 struct pcnode *pcp;
263 264 int error;
264 265
265 266 fsp = VFSTOPCFS(vp->v_vfsp);
266 267 if (error = pc_verify(fsp))
267 268 return (error);
268 269 error = pc_lockfs(fsp, 0, 0);
269 270 if (error)
270 271 return (error);
271 272 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
272 273 pc_unlockfs(fsp);
273 274 return (EIO);
274 275 }
275 276 if (ioflag & FAPPEND) {
276 277 /*
277 278 * in append mode start at end of file.
278 279 */
279 280 uiop->uio_loffset = pcp->pc_size;
280 281 }
281 282 error = rwpcp(pcp, uiop, UIO_WRITE, ioflag);
282 283 pcp->pc_flags |= PC_MOD;
283 284 pc_mark_mod(fsp, pcp);
284 285 if (ioflag & (FSYNC|FDSYNC))
285 286 (void) pc_nodeupdate(pcp);
286 287
287 288 pc_unlockfs(fsp);
288 289 if (error) {
289 290 PC_DPRINTF1(1, "pcfs_write: io error = %d\n", error);
290 291 }
291 292 return (error);
292 293 }
293 294
294 295 /*
295 296 * read or write a vnode
296 297 */
297 298 static int
298 299 rwpcp(
299 300 struct pcnode *pcp,
300 301 struct uio *uio,
301 302 enum uio_rw rw,
302 303 int ioflag)
303 304 {
304 305 struct vnode *vp = PCTOV(pcp);
305 306 struct pcfs *fsp;
306 307 daddr_t bn; /* phys block number */
307 308 int n;
308 309 offset_t off;
309 310 caddr_t base;
310 311 int mapon, pagecreate;
311 312 int newpage;
312 313 int error = 0;
313 314 rlim64_t limit = uio->uio_llimit;
314 315 int oresid = uio->uio_resid;
315 316
316 317 /*
317 318 * If the filesystem was umounted by force, return immediately.
318 319 */
319 320 if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
320 321 return (EIO);
321 322
322 323 PC_DPRINTF4(5, "rwpcp pcp=%p off=%lld resid=%ld size=%u\n", (void *)pcp,
323 324 uio->uio_loffset, uio->uio_resid, pcp->pc_size);
324 325
325 326 ASSERT(rw == UIO_READ || rw == UIO_WRITE);
326 327 ASSERT(vp->v_type == VREG);
327 328
328 329 if (uio->uio_loffset >= UINT32_MAX && rw == UIO_READ) {
329 330 return (0);
330 331 }
331 332
332 333 if (uio->uio_loffset < 0)
333 334 return (EINVAL);
334 335
335 336 if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
336 337 limit = MAXOFFSET_T;
337 338
338 339 if (uio->uio_loffset >= limit && rw == UIO_WRITE) {
339 340 proc_t *p = ttoproc(curthread);
340 341
341 342 mutex_enter(&p->p_lock);
342 343 (void) rctl_action(rctlproc_legacy[RLIMIT_FSIZE], p->p_rctls,
343 344 p, RCA_UNSAFE_SIGINFO);
344 345 mutex_exit(&p->p_lock);
345 346 return (EFBIG);
346 347 }
347 348
348 349 /* the following condition will occur only for write */
349 350
350 351 if (uio->uio_loffset >= UINT32_MAX)
351 352 return (EFBIG);
352 353
353 354 if (uio->uio_resid == 0)
354 355 return (0);
355 356
356 357 if (limit > UINT32_MAX)
357 358 limit = UINT32_MAX;
358 359
359 360 fsp = VFSTOPCFS(vp->v_vfsp);
360 361 if (fsp->pcfs_flags & PCFS_IRRECOV)
361 362 return (EIO);
362 363
363 364 do {
364 365 /*
365 366 * Assignments to "n" in this block may appear
366 367 * to overflow in some cases. However, after careful
367 368 * analysis it was determined that all assignments to
368 369 * "n" serve only to make "n" smaller. Since "n"
369 370 * starts out as no larger than MAXBSIZE, "int" is
370 371 * safe.
371 372 */
372 373 off = uio->uio_loffset & MAXBMASK;
373 374 mapon = (int)(uio->uio_loffset & MAXBOFFSET);
374 375 n = MIN(MAXBSIZE - mapon, uio->uio_resid);
375 376 if (rw == UIO_READ) {
376 377 offset_t diff;
377 378
378 379 diff = pcp->pc_size - uio->uio_loffset;
379 380 if (diff <= 0)
380 381 return (0);
381 382 if (diff < n)
382 383 n = (int)diff;
383 384 }
384 385 /*
385 386 * Compare limit with the actual offset + n, not the
386 387 * rounded down offset "off" or we will overflow
387 388 * the maximum file size after all.
388 389 */
389 390 if (rw == UIO_WRITE && uio->uio_loffset + n >= limit) {
390 391 if (uio->uio_loffset >= limit) {
391 392 error = EFBIG;
392 393 break;
393 394 }
394 395 n = (int)(limit - uio->uio_loffset);
395 396 }
396 397
397 398 /*
398 399 * Touch the page and fault it in if it is not in
399 400 * core before segmap_getmapflt can lock it. This
400 401 * is to avoid the deadlock if the buffer is mapped
401 402 * to the same file through mmap which we want to
402 403 * write to.
403 404 */
404 405 uio_prefaultpages((long)n, uio);
405 406
406 407 base = segmap_getmap(segkmap, vp, (u_offset_t)off);
407 408 pagecreate = 0;
408 409 newpage = 0;
409 410 if (rw == UIO_WRITE) {
410 411 /*
411 412 * If PAGESIZE < MAXBSIZE, perhaps we ought to deal
412 413 * with one page at a time, instead of one MAXBSIZE
413 414 * at a time, so we can fully explore pagecreate
414 415 * optimization??
415 416 */
416 417 if (uio->uio_loffset + n > pcp->pc_size) {
417 418 uint_t ncl, lcn;
418 419
419 420 ncl = (uint_t)howmany((offset_t)pcp->pc_size,
420 421 fsp->pcfs_clsize);
421 422 if (uio->uio_loffset > pcp->pc_size &&
422 423 ncl < (uint_t)howmany(uio->uio_loffset,
423 424 fsp->pcfs_clsize)) {
424 425 /*
425 426 * Allocate and zerofill skipped
426 427 * clusters. This may not be worth the
427 428 * effort since a small lseek beyond
428 429 * eof but still within the cluster
429 430 * will not be zeroed out.
430 431 */
431 432 lcn = pc_lblkno(fsp, uio->uio_loffset);
432 433 error = pc_balloc(pcp, (daddr_t)lcn,
433 434 1, &bn);
434 435 ncl = lcn + 1;
435 436 }
436 437 if (!error &&
437 438 ncl < (uint_t)howmany(uio->uio_loffset + n,
438 439 fsp->pcfs_clsize))
439 440 /*
440 441 * allocate clusters w/o zerofill
441 442 */
442 443 error = pc_balloc(pcp,
443 444 (daddr_t)pc_lblkno(fsp,
444 445 uio->uio_loffset + n - 1),
445 446 0, &bn);
446 447
447 448 pcp->pc_flags |= PC_CHG;
448 449
449 450 if (error) {
450 451 pc_cluster32_t ncl;
451 452 int nerror;
452 453
453 454 /*
454 455 * figure out new file size from
455 456 * cluster chain length. If this
456 457 * is detected to loop, the chain
457 458 * is corrupted and we'd better
458 459 * keep our fingers off that file.
459 460 */
460 461 nerror = pc_fileclsize(fsp,
461 462 pcp->pc_scluster, &ncl);
462 463 if (nerror) {
463 464 PC_DPRINTF1(2,
464 465 "cluster chain "
465 466 "corruption, "
466 467 "scluster=%d\n",
467 468 pcp->pc_scluster);
468 469 pcp->pc_size = 0;
469 470 pcp->pc_flags |= PC_INVAL;
470 471 error = nerror;
471 472 (void) segmap_release(segkmap,
472 473 base, 0);
473 474 break;
474 475 }
475 476 pcp->pc_size = fsp->pcfs_clsize * ncl;
476 477
477 478 if (error == ENOSPC &&
478 479 (pcp->pc_size - uio->uio_loffset)
479 480 > 0) {
480 481 PC_DPRINTF3(2, "rwpcp ENOSPC "
481 482 "off=%lld n=%d size=%d\n",
482 483 uio->uio_loffset,
483 484 n, pcp->pc_size);
484 485 n = (int)(pcp->pc_size -
485 486 uio->uio_loffset);
486 487 } else {
487 488 PC_DPRINTF1(1,
488 489 "rwpcp error1=%d\n", error);
489 490 (void) segmap_release(segkmap,
490 491 base, 0);
491 492 break;
492 493 }
493 494 } else {
494 495 pcp->pc_size =
495 496 (uint_t)(uio->uio_loffset + n);
496 497 }
497 498 if (mapon == 0) {
498 499 newpage = segmap_pagecreate(segkmap,
499 500 base, (size_t)n, 0);
500 501 pagecreate = 1;
501 502 }
502 503 } else if (n == MAXBSIZE) {
503 504 newpage = segmap_pagecreate(segkmap, base,
504 505 (size_t)n, 0);
505 506 pagecreate = 1;
506 507 }
507 508 }
508 509 error = uiomove(base + mapon, (size_t)n, rw, uio);
509 510
510 511 if (pagecreate && uio->uio_loffset <
511 512 roundup(off + mapon + n, PAGESIZE)) {
512 513 offset_t nzero, nmoved;
513 514
514 515 nmoved = uio->uio_loffset - (off + mapon);
515 516 nzero = roundup(mapon + n, PAGESIZE) - nmoved;
516 517 (void) kzero(base + mapon + nmoved, (size_t)nzero);
517 518 }
518 519
519 520 /*
520 521 * Unlock the pages which have been allocated by
521 522 * page_create_va() in segmap_pagecreate().
522 523 */
523 524 if (newpage) {
524 525 segmap_pageunlock(segkmap, base, (size_t)n,
525 526 rw == UIO_WRITE ? S_WRITE : S_READ);
526 527 }
527 528
528 529 if (error) {
529 530 PC_DPRINTF1(1, "rwpcp error2=%d\n", error);
530 531 /*
531 532 * If we failed on a write, we may have already
532 533 * allocated file blocks as well as pages. It's hard
533 534 * to undo the block allocation, but we must be sure
534 535 * to invalidate any pages that may have been
535 536 * allocated.
536 537 */
537 538 if (rw == UIO_WRITE)
538 539 (void) segmap_release(segkmap, base, SM_INVAL);
539 540 else
540 541 (void) segmap_release(segkmap, base, 0);
541 542 } else {
542 543 uint_t flags = 0;
543 544
544 545 if (rw == UIO_READ) {
545 546 if (n + mapon == MAXBSIZE ||
546 547 uio->uio_loffset == pcp->pc_size)
547 548 flags = SM_DONTNEED;
548 549 } else if (ioflag & (FSYNC|FDSYNC)) {
549 550 flags = SM_WRITE;
550 551 } else if (n + mapon == MAXBSIZE) {
551 552 flags = SM_WRITE|SM_ASYNC|SM_DONTNEED;
552 553 }
553 554 error = segmap_release(segkmap, base, flags);
554 555 }
555 556
556 557 } while (error == 0 && uio->uio_resid > 0 && n != 0);
557 558
558 559 if (oresid != uio->uio_resid)
559 560 error = 0;
560 561 return (error);
561 562 }
562 563
563 564 /*ARGSUSED*/
564 565 static int
565 566 pcfs_getattr(
566 567 struct vnode *vp,
567 568 struct vattr *vap,
568 569 int flags,
569 570 struct cred *cr,
570 571 caller_context_t *ct)
571 572 {
572 573 struct pcnode *pcp;
573 574 struct pcfs *fsp;
574 575 int error;
575 576 char attr;
576 577 struct pctime atime;
577 578 int64_t unixtime;
578 579
579 580 PC_DPRINTF1(8, "pcfs_getattr: vp=%p\n", (void *)vp);
580 581
581 582 fsp = VFSTOPCFS(vp->v_vfsp);
582 583 error = pc_lockfs(fsp, 0, 0);
583 584 if (error)
584 585 return (error);
585 586
586 587 /*
587 588 * Note that we don't check for "invalid node" (PC_INVAL) here
588 589 * only in order to make stat() succeed. We allow no I/O on such
589 590 * a node, but do allow to check for its existence.
590 591 */
591 592 if ((pcp = VTOPC(vp)) == NULL) {
592 593 pc_unlockfs(fsp);
593 594 return (EIO);
594 595 }
595 596 /*
596 597 * Copy from pcnode.
597 598 */
598 599 vap->va_type = vp->v_type;
599 600 attr = pcp->pc_entry.pcd_attr;
600 601 if (PCA_IS_HIDDEN(fsp, attr))
601 602 vap->va_mode = 0;
602 603 else if (attr & PCA_LABEL)
603 604 vap->va_mode = 0444;
604 605 else if (attr & PCA_RDONLY)
605 606 vap->va_mode = 0555;
606 607 else if (fsp->pcfs_flags & PCFS_BOOTPART) {
607 608 vap->va_mode = 0755;
608 609 } else {
609 610 vap->va_mode = 0777;
610 611 }
611 612
612 613 if (attr & PCA_DIR)
613 614 vap->va_mode |= S_IFDIR;
614 615 else
615 616 vap->va_mode |= S_IFREG;
616 617 if (fsp->pcfs_flags & PCFS_BOOTPART) {
617 618 vap->va_uid = 0;
618 619 vap->va_gid = 0;
619 620 } else {
620 621 vap->va_uid = crgetuid(cr);
621 622 vap->va_gid = crgetgid(cr);
622 623 }
623 624 vap->va_fsid = vp->v_vfsp->vfs_dev;
624 625 vap->va_nodeid = (ino64_t)pc_makenodeid(pcp->pc_eblkno,
625 626 pcp->pc_eoffset, pcp->pc_entry.pcd_attr,
626 627 pc_getstartcluster(fsp, &pcp->pc_entry), pc_direntpersec(fsp));
627 628 vap->va_nlink = 1;
628 629 vap->va_size = (u_offset_t)pcp->pc_size;
629 630 vap->va_rdev = 0;
630 631 vap->va_nblocks =
631 632 (fsblkcnt64_t)howmany((offset_t)pcp->pc_size, DEV_BSIZE);
632 633 vap->va_blksize = fsp->pcfs_clsize;
633 634
634 635 /*
635 636 * FAT root directories have no timestamps. In order not to return
636 637 * "time zero" (1/1/1970), we record the time of the mount and give
637 638 * that. This breaks less expectations.
638 639 */
639 640 if (vp->v_flag & VROOT) {
640 641 vap->va_mtime = fsp->pcfs_mounttime;
641 642 vap->va_atime = fsp->pcfs_mounttime;
642 643 vap->va_ctime = fsp->pcfs_mounttime;
643 644 pc_unlockfs(fsp);
644 645 return (0);
645 646 }
646 647
647 648 pc_pcttotv(&pcp->pc_entry.pcd_mtime, &unixtime);
648 649 if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0) {
649 650 if (unixtime > INT32_MAX)
650 651 DTRACE_PROBE1(pcfs__mtimeclamped, int64_t, unixtime);
651 652 unixtime = MIN(unixtime, INT32_MAX);
652 653 } else if (unixtime > INT32_MAX &&
653 654 get_udatamodel() == DATAMODEL_ILP32) {
654 655 pc_unlockfs(fsp);
655 656 DTRACE_PROBE1(pcfs__mtimeoverflowed, int64_t, unixtime);
656 657 return (EOVERFLOW);
657 658 }
658 659
659 660 vap->va_mtime.tv_sec = (time_t)unixtime;
660 661 vap->va_mtime.tv_nsec = 0;
661 662
662 663 /*
663 664 * FAT doesn't know about POSIX ctime.
664 665 * Best approximation is to always set it to mtime.
665 666 */
666 667 vap->va_ctime = vap->va_mtime;
667 668
668 669 /*
669 670 * FAT only stores "last access date". If that's the
670 671 * same as the date of last modification then the time
671 672 * of last access is known. Otherwise, use midnight.
672 673 */
673 674 atime.pct_date = pcp->pc_entry.pcd_ladate;
674 675 if (atime.pct_date == pcp->pc_entry.pcd_mtime.pct_date)
675 676 atime.pct_time = pcp->pc_entry.pcd_mtime.pct_time;
676 677 else
677 678 atime.pct_time = 0;
678 679 pc_pcttotv(&atime, &unixtime);
679 680 if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0) {
680 681 if (unixtime > INT32_MAX)
681 682 DTRACE_PROBE1(pcfs__atimeclamped, int64_t, unixtime);
682 683 unixtime = MIN(unixtime, INT32_MAX);
683 684 } else if (unixtime > INT32_MAX &&
684 685 get_udatamodel() == DATAMODEL_ILP32) {
685 686 pc_unlockfs(fsp);
686 687 DTRACE_PROBE1(pcfs__atimeoverflowed, int64_t, unixtime);
687 688 return (EOVERFLOW);
688 689 }
689 690
690 691 vap->va_atime.tv_sec = (time_t)unixtime;
691 692 vap->va_atime.tv_nsec = 0;
692 693
693 694 pc_unlockfs(fsp);
694 695 return (0);
695 696 }
696 697
697 698
698 699 /*ARGSUSED*/
699 700 static int
700 701 pcfs_setattr(
701 702 struct vnode *vp,
702 703 struct vattr *vap,
703 704 int flags,
704 705 struct cred *cr,
705 706 caller_context_t *ct)
706 707 {
707 708 struct pcnode *pcp;
708 709 mode_t mask = vap->va_mask;
709 710 int error;
710 711 struct pcfs *fsp;
711 712 timestruc_t now, *timep;
712 713
713 714 PC_DPRINTF2(6, "pcfs_setattr: vp=%p mask=%x\n", (void *)vp, (int)mask);
714 715 /*
715 716 * cannot set these attributes
716 717 */
717 718 if (mask & (AT_NOSET | AT_UID | AT_GID)) {
718 719 return (EINVAL);
719 720 }
720 721 /*
721 722 * pcfs_setattr is now allowed on directories to avoid silly warnings
722 723 * from 'tar' when it tries to set times on a directory, and console
723 724 * printf's on the NFS server when it gets EINVAL back on such a
724 725 * request. One possible problem with that since a directory entry
725 726 * identifies a file, '.' and all the '..' entries in subdirectories
726 727 * may get out of sync when the directory is updated since they're
727 728 * treated like separate files. We could fix that by looking for
728 729 * '.' and giving it the same attributes, and then looking for
729 730 * all the subdirectories and updating '..', but that's pretty
730 731 * expensive for something that doesn't seem likely to matter.
731 732 */
732 733 /* can't do some ops on directories anyway */
733 734 if ((vp->v_type == VDIR) &&
734 735 (mask & AT_SIZE)) {
735 736 return (EINVAL);
736 737 }
737 738
738 739 fsp = VFSTOPCFS(vp->v_vfsp);
739 740 error = pc_lockfs(fsp, 0, 0);
740 741 if (error)
741 742 return (error);
742 743 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
743 744 pc_unlockfs(fsp);
744 745 return (EIO);
745 746 }
746 747
747 748 if (fsp->pcfs_flags & PCFS_BOOTPART) {
748 749 if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
749 750 pc_unlockfs(fsp);
750 751 return (EACCES);
751 752 }
752 753 }
753 754
754 755 /*
755 756 * Change file access modes.
756 757 * If nobody has write permission, file is marked readonly.
757 758 * Otherwise file is writable by anyone.
758 759 */
759 760 if ((mask & AT_MODE) && (vap->va_mode != (mode_t)-1)) {
760 761 if ((vap->va_mode & 0222) == 0)
761 762 pcp->pc_entry.pcd_attr |= PCA_RDONLY;
762 763 else
763 764 pcp->pc_entry.pcd_attr &= ~PCA_RDONLY;
764 765 pcp->pc_flags |= PC_CHG;
765 766 }
766 767 /*
767 768 * Truncate file. Must have write permission.
768 769 */
769 770 if ((mask & AT_SIZE) && (vap->va_size != (u_offset_t)-1)) {
770 771 if (pcp->pc_entry.pcd_attr & PCA_RDONLY) {
771 772 error = EACCES;
772 773 goto out;
773 774 }
774 775 if (vap->va_size > UINT32_MAX) {
775 776 error = EFBIG;
776 777 goto out;
777 778 }
778 779 error = pc_truncate(pcp, (uint_t)vap->va_size);
779 780
780 781 if (error)
781 782 goto out;
782 783
783 784 if (vap->va_size == 0)
784 785 vnevent_truncate(vp, ct);
785 786 }
786 787 /*
787 788 * Change file modified times.
788 789 */
789 790 if (mask & (AT_MTIME | AT_CTIME)) {
790 791 /*
791 792 * If SysV-compatible option to set access and
792 793 * modified times if privileged, owner, or write access,
793 794 * use current time rather than va_mtime.
794 795 *
795 796 * XXX - va_mtime.tv_sec == -1 flags this.
796 797 */
797 798 timep = &vap->va_mtime;
798 799 if (vap->va_mtime.tv_sec == -1) {
799 800 gethrestime(&now);
800 801 timep = &now;
801 802 }
802 803 if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0 &&
803 804 timep->tv_sec > INT32_MAX) {
804 805 error = EOVERFLOW;
805 806 goto out;
806 807 }
807 808 error = pc_tvtopct(timep, &pcp->pc_entry.pcd_mtime);
808 809 if (error)
809 810 goto out;
810 811 pcp->pc_flags |= PC_CHG;
811 812 }
812 813 /*
813 814 * Change file access times.
814 815 */
815 816 if (mask & AT_ATIME) {
816 817 /*
817 818 * If SysV-compatible option to set access and
818 819 * modified times if privileged, owner, or write access,
819 820 * use current time rather than va_mtime.
820 821 *
821 822 * XXX - va_atime.tv_sec == -1 flags this.
822 823 */
823 824 struct pctime atime;
824 825
825 826 timep = &vap->va_atime;
826 827 if (vap->va_atime.tv_sec == -1) {
827 828 gethrestime(&now);
828 829 timep = &now;
829 830 }
830 831 if ((fsp->pcfs_flags & PCFS_NOCLAMPTIME) == 0 &&
831 832 timep->tv_sec > INT32_MAX) {
832 833 error = EOVERFLOW;
833 834 goto out;
834 835 }
835 836 error = pc_tvtopct(timep, &atime);
836 837 if (error)
837 838 goto out;
838 839 pcp->pc_entry.pcd_ladate = atime.pct_date;
839 840 pcp->pc_flags |= PC_CHG;
840 841 }
841 842 out:
842 843 pc_unlockfs(fsp);
843 844 return (error);
844 845 }
845 846
846 847
847 848 /*ARGSUSED*/
848 849 static int
849 850 pcfs_access(
850 851 struct vnode *vp,
851 852 int mode,
852 853 int flags,
853 854 struct cred *cr,
854 855 caller_context_t *ct)
855 856 {
856 857 struct pcnode *pcp;
857 858 struct pcfs *fsp;
858 859
859 860
860 861 fsp = VFSTOPCFS(vp->v_vfsp);
861 862
862 863 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL)
863 864 return (EIO);
864 865 if ((mode & VWRITE) && (pcp->pc_entry.pcd_attr & PCA_RDONLY))
865 866 return (EACCES);
866 867
867 868 /*
868 869 * If this is a boot partition, privileged users have full access while
869 870 * others have read-only access.
870 871 */
871 872 if (fsp->pcfs_flags & PCFS_BOOTPART) {
872 873 if ((mode & VWRITE) &&
873 874 secpolicy_pcfs_modify_bootpartition(cr) != 0)
874 875 return (EACCES);
875 876 }
876 877 return (0);
877 878 }
878 879
879 880
880 881 /*ARGSUSED*/
881 882 static int
882 883 pcfs_fsync(
883 884 struct vnode *vp,
884 885 int syncflag,
885 886 struct cred *cr,
886 887 caller_context_t *ct)
887 888 {
888 889 struct pcfs *fsp;
889 890 struct pcnode *pcp;
890 891 int error;
891 892
892 893 fsp = VFSTOPCFS(vp->v_vfsp);
893 894 if (error = pc_verify(fsp))
894 895 return (error);
895 896 error = pc_lockfs(fsp, 0, 0);
896 897 if (error)
897 898 return (error);
898 899 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
899 900 pc_unlockfs(fsp);
900 901 return (EIO);
901 902 }
902 903 rw_enter(&pcnodes_lock, RW_WRITER);
903 904 error = pc_nodesync(pcp);
904 905 rw_exit(&pcnodes_lock);
905 906 pc_unlockfs(fsp);
906 907 return (error);
907 908 }
908 909
909 910
910 911 /*ARGSUSED*/
911 912 static void
912 913 pcfs_inactive(
913 914 struct vnode *vp,
914 915 struct cred *cr,
915 916 caller_context_t *ct)
916 917 {
917 918 struct pcnode *pcp;
918 919 struct pcfs *fsp;
919 920 int error;
920 921
921 922 fsp = VFSTOPCFS(vp->v_vfsp);
922 923 error = pc_lockfs(fsp, 0, 1);
923 924
924 925 /*
925 926 * If the filesystem was umounted by force, all dirty
926 927 * pages associated with this vnode are invalidated
927 928 * and then the vnode will be freed.
928 929 */
929 930 if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) {
930 931 pcp = VTOPC(vp);
931 932 if (vn_has_cached_data(vp)) {
932 933 (void) pvn_vplist_dirty(vp, (u_offset_t)0,
933 934 pcfs_putapage, B_INVAL, (struct cred *)NULL);
934 935 }
935 936 remque(pcp);
936 937 if (error == 0)
937 938 pc_unlockfs(fsp);
938 939 vn_free(vp);
939 940 kmem_free(pcp, sizeof (struct pcnode));
940 941 VFS_RELE(PCFSTOVFS(fsp));
941 942 return;
942 943 }
943 944
944 945 mutex_enter(&vp->v_lock);
945 946 ASSERT(vp->v_count >= 1);
946 947 if (vp->v_count > 1) {
947 948 vp->v_count--; /* release our hold from vn_rele */
948 949 mutex_exit(&vp->v_lock);
949 950 pc_unlockfs(fsp);
950 951 return;
951 952 }
952 953 mutex_exit(&vp->v_lock);
953 954
954 955 /*
955 956 * Check again to confirm that no intervening I/O error
956 957 * with a subsequent pc_diskchanged() call has released
957 958 * the pcnode. If it has then release the vnode as above.
958 959 */
959 960 pcp = VTOPC(vp);
960 961 if (pcp == NULL || pcp->pc_flags & PC_INVAL) {
961 962 if (vn_has_cached_data(vp))
962 963 (void) pvn_vplist_dirty(vp, (u_offset_t)0,
963 964 pcfs_putapage, B_INVAL | B_TRUNC,
964 965 (struct cred *)NULL);
965 966 }
966 967
967 968 if (pcp == NULL) {
968 969 vn_free(vp);
969 970 } else {
970 971 pc_rele(pcp);
971 972 }
972 973
973 974 if (!error)
974 975 pc_unlockfs(fsp);
975 976 }
976 977
977 978 /*ARGSUSED*/
978 979 static int
979 980 pcfs_lookup(
980 981 struct vnode *dvp,
981 982 char *nm,
982 983 struct vnode **vpp,
983 984 struct pathname *pnp,
984 985 int flags,
985 986 struct vnode *rdir,
986 987 struct cred *cr,
987 988 caller_context_t *ct,
988 989 int *direntflags,
989 990 pathname_t *realpnp)
990 991 {
991 992 struct pcfs *fsp;
992 993 struct pcnode *pcp;
993 994 int error;
994 995
995 996 /*
996 997 * If the filesystem was umounted by force, return immediately.
997 998 */
998 999 if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
999 1000 return (EIO);
1000 1001
1001 1002 /*
1002 1003 * verify that the dvp is still valid on the disk
1003 1004 */
1004 1005 fsp = VFSTOPCFS(dvp->v_vfsp);
1005 1006 if (error = pc_verify(fsp))
1006 1007 return (error);
1007 1008 error = pc_lockfs(fsp, 0, 0);
1008 1009 if (error)
1009 1010 return (error);
1010 1011 if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) {
1011 1012 pc_unlockfs(fsp);
1012 1013 return (EIO);
1013 1014 }
1014 1015 /*
1015 1016 * Null component name is a synonym for directory being searched.
1016 1017 */
1017 1018 if (*nm == '\0') {
1018 1019 VN_HOLD(dvp);
1019 1020 *vpp = dvp;
1020 1021 pc_unlockfs(fsp);
1021 1022 return (0);
1022 1023 }
1023 1024
1024 1025 error = pc_dirlook(VTOPC(dvp), nm, &pcp);
1025 1026 if (!error) {
1026 1027 *vpp = PCTOV(pcp);
1027 1028 pcp->pc_flags |= PC_EXTERNAL;
1028 1029 }
1029 1030 pc_unlockfs(fsp);
1030 1031 return (error);
1031 1032 }
1032 1033
1033 1034
1034 1035 /*ARGSUSED*/
1035 1036 static int
1036 1037 pcfs_create(
1037 1038 struct vnode *dvp,
1038 1039 char *nm,
1039 1040 struct vattr *vap,
1040 1041 enum vcexcl exclusive,
1041 1042 int mode,
1042 1043 struct vnode **vpp,
1043 1044 struct cred *cr,
1044 1045 int flag,
1045 1046 caller_context_t *ct,
1046 1047 vsecattr_t *vsecp)
1047 1048 {
1048 1049 int error;
1049 1050 struct pcnode *pcp;
1050 1051 struct vnode *vp;
1051 1052 struct pcfs *fsp;
1052 1053
1053 1054 /*
1054 1055 * can't create directories. use pcfs_mkdir.
1055 1056 * can't create anything other than files.
1056 1057 */
1057 1058 if (vap->va_type == VDIR)
1058 1059 return (EISDIR);
1059 1060 else if (vap->va_type != VREG)
1060 1061 return (EINVAL);
1061 1062
1062 1063 pcp = NULL;
1063 1064 fsp = VFSTOPCFS(dvp->v_vfsp);
1064 1065 error = pc_lockfs(fsp, 0, 0);
1065 1066 if (error)
1066 1067 return (error);
1067 1068 if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) {
1068 1069 pc_unlockfs(fsp);
1069 1070 return (EIO);
1070 1071 }
1071 1072
1072 1073 if (fsp->pcfs_flags & PCFS_BOOTPART) {
1073 1074 if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
1074 1075 pc_unlockfs(fsp);
1075 1076 return (EACCES);
1076 1077 }
1077 1078 }
1078 1079
1079 1080 if (*nm == '\0') {
1080 1081 /*
1081 1082 * Null component name refers to the directory itself.
1082 1083 */
1083 1084 VN_HOLD(dvp);
1084 1085 pcp = VTOPC(dvp);
1085 1086 error = EEXIST;
1086 1087 } else {
1087 1088 error = pc_direnter(VTOPC(dvp), nm, vap, &pcp);
1088 1089 }
1089 1090 /*
1090 1091 * if file exists and this is a nonexclusive create,
1091 1092 * check for access permissions
1092 1093 */
1093 1094 if (error == EEXIST) {
1094 1095 vp = PCTOV(pcp);
1095 1096 if (exclusive == NONEXCL) {
1096 1097 if (vp->v_type == VDIR) {
1097 1098 error = EISDIR;
1098 1099 } else if (mode) {
1099 1100 error = pcfs_access(PCTOV(pcp), mode, 0,
1100 1101 cr, ct);
1101 1102 } else {
1102 1103 error = 0;
1103 1104 }
1104 1105 }
1105 1106 if (error) {
1106 1107 VN_RELE(PCTOV(pcp));
1107 1108 } else if ((vp->v_type == VREG) && (vap->va_mask & AT_SIZE) &&
1108 1109 (vap->va_size == 0)) {
1109 1110 error = pc_truncate(pcp, 0L);
1110 1111 if (error) {
1111 1112 VN_RELE(PCTOV(pcp));
1112 1113 } else {
1113 1114 vnevent_create(PCTOV(pcp), ct);
1114 1115 }
1115 1116 }
1116 1117 }
1117 1118 if (error) {
1118 1119 pc_unlockfs(fsp);
1119 1120 return (error);
1120 1121 }
1121 1122 *vpp = PCTOV(pcp);
1122 1123 pcp->pc_flags |= PC_EXTERNAL;
1123 1124 pc_unlockfs(fsp);
1124 1125 return (error);
1125 1126 }
1126 1127
1127 1128 /*ARGSUSED*/
1128 1129 static int
1129 1130 pcfs_remove(
1130 1131 struct vnode *vp,
1131 1132 char *nm,
1132 1133 struct cred *cr,
1133 1134 caller_context_t *ct,
1134 1135 int flags)
1135 1136 {
1136 1137 struct pcfs *fsp;
1137 1138 struct pcnode *pcp;
1138 1139 int error;
1139 1140
1140 1141 fsp = VFSTOPCFS(vp->v_vfsp);
1141 1142 if (error = pc_verify(fsp))
1142 1143 return (error);
1143 1144 error = pc_lockfs(fsp, 0, 0);
1144 1145 if (error)
1145 1146 return (error);
1146 1147 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
1147 1148 pc_unlockfs(fsp);
1148 1149 return (EIO);
1149 1150 }
1150 1151 if (fsp->pcfs_flags & PCFS_BOOTPART) {
1151 1152 if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
1152 1153 pc_unlockfs(fsp);
1153 1154 return (EACCES);
1154 1155 }
1155 1156 }
1156 1157 error = pc_dirremove(pcp, nm, (struct vnode *)0, VREG, ct);
1157 1158 pc_unlockfs(fsp);
1158 1159 return (error);
1159 1160 }
1160 1161
1161 1162 /*
1162 1163 * Rename a file or directory
1163 1164 * This rename is restricted to only rename files within a directory.
1164 1165 * XX should make rename more general
1165 1166 */
1166 1167 /*ARGSUSED*/
1167 1168 static int
1168 1169 pcfs_rename(
1169 1170 struct vnode *sdvp, /* old (source) parent vnode */
1170 1171 char *snm, /* old (source) entry name */
1171 1172 struct vnode *tdvp, /* new (target) parent vnode */
1172 1173 char *tnm, /* new (target) entry name */
1173 1174 struct cred *cr,
1174 1175 caller_context_t *ct,
1175 1176 int flags)
1176 1177 {
1177 1178 struct pcfs *fsp;
1178 1179 struct pcnode *dp; /* parent pcnode */
1179 1180 struct pcnode *tdp;
1180 1181 int error;
1181 1182
1182 1183 fsp = VFSTOPCFS(sdvp->v_vfsp);
1183 1184 if (error = pc_verify(fsp))
1184 1185 return (error);
1185 1186
1186 1187 /*
1187 1188 * make sure we can muck with this directory.
1188 1189 */
1189 1190 error = pcfs_access(sdvp, VWRITE, 0, cr, ct);
1190 1191 if (error) {
1191 1192 return (error);
1192 1193 }
1193 1194 error = pc_lockfs(fsp, 0, 0);
1194 1195 if (error)
1195 1196 return (error);
1196 1197 if (((dp = VTOPC(sdvp)) == NULL) || ((tdp = VTOPC(tdvp)) == NULL) ||
1197 1198 (dp->pc_flags & PC_INVAL) || (tdp->pc_flags & PC_INVAL)) {
1198 1199 pc_unlockfs(fsp);
1199 1200 return (EIO);
1200 1201 }
1201 1202 error = pc_rename(dp, tdp, snm, tnm, ct);
1202 1203 pc_unlockfs(fsp);
1203 1204 return (error);
1204 1205 }
1205 1206
1206 1207 /*ARGSUSED*/
1207 1208 static int
1208 1209 pcfs_mkdir(
1209 1210 struct vnode *dvp,
1210 1211 char *nm,
1211 1212 struct vattr *vap,
1212 1213 struct vnode **vpp,
1213 1214 struct cred *cr,
1214 1215 caller_context_t *ct,
1215 1216 int flags,
1216 1217 vsecattr_t *vsecp)
1217 1218 {
1218 1219 struct pcfs *fsp;
1219 1220 struct pcnode *pcp;
1220 1221 int error;
1221 1222
1222 1223 fsp = VFSTOPCFS(dvp->v_vfsp);
1223 1224 if (error = pc_verify(fsp))
1224 1225 return (error);
1225 1226 error = pc_lockfs(fsp, 0, 0);
1226 1227 if (error)
1227 1228 return (error);
1228 1229 if (VTOPC(dvp) == NULL || VTOPC(dvp)->pc_flags & PC_INVAL) {
1229 1230 pc_unlockfs(fsp);
1230 1231 return (EIO);
1231 1232 }
1232 1233
1233 1234 if (fsp->pcfs_flags & PCFS_BOOTPART) {
1234 1235 if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
1235 1236 pc_unlockfs(fsp);
1236 1237 return (EACCES);
1237 1238 }
1238 1239 }
1239 1240
1240 1241 error = pc_direnter(VTOPC(dvp), nm, vap, &pcp);
1241 1242
1242 1243 if (!error) {
1243 1244 pcp -> pc_flags |= PC_EXTERNAL;
1244 1245 *vpp = PCTOV(pcp);
1245 1246 } else if (error == EEXIST) {
1246 1247 VN_RELE(PCTOV(pcp));
1247 1248 }
1248 1249 pc_unlockfs(fsp);
1249 1250 return (error);
1250 1251 }
1251 1252
1252 1253 /*ARGSUSED*/
1253 1254 static int
1254 1255 pcfs_rmdir(
1255 1256 struct vnode *dvp,
1256 1257 char *nm,
1257 1258 struct vnode *cdir,
1258 1259 struct cred *cr,
1259 1260 caller_context_t *ct,
1260 1261 int flags)
1261 1262 {
1262 1263 struct pcfs *fsp;
1263 1264 struct pcnode *pcp;
1264 1265 int error;
1265 1266
1266 1267 fsp = VFSTOPCFS(dvp -> v_vfsp);
1267 1268 if (error = pc_verify(fsp))
1268 1269 return (error);
1269 1270 if (error = pc_lockfs(fsp, 0, 0))
1270 1271 return (error);
1271 1272
1272 1273 if ((pcp = VTOPC(dvp)) == NULL || pcp->pc_flags & PC_INVAL) {
1273 1274 pc_unlockfs(fsp);
1274 1275 return (EIO);
1275 1276 }
1276 1277
1277 1278 if (fsp->pcfs_flags & PCFS_BOOTPART) {
1278 1279 if (secpolicy_pcfs_modify_bootpartition(cr) != 0) {
1279 1280 pc_unlockfs(fsp);
1280 1281 return (EACCES);
1281 1282 }
1282 1283 }
1283 1284
1284 1285 error = pc_dirremove(pcp, nm, cdir, VDIR, ct);
1285 1286 pc_unlockfs(fsp);
1286 1287 return (error);
1287 1288 }
1288 1289
1289 1290 /*
1290 1291 * read entries in a directory.
1291 1292 * we must convert pc format to unix format
1292 1293 */
1293 1294
1294 1295 /*ARGSUSED*/
1295 1296 static int
1296 1297 pcfs_readdir(
1297 1298 struct vnode *dvp,
1298 1299 struct uio *uiop,
1299 1300 struct cred *cr,
1300 1301 int *eofp,
1301 1302 caller_context_t *ct,
1302 1303 int flags)
1303 1304 {
1304 1305 struct pcnode *pcp;
1305 1306 struct pcfs *fsp;
1306 1307 struct pcdir *ep;
1307 1308 struct buf *bp = NULL;
1308 1309 offset_t offset;
1309 1310 int boff;
1310 1311 struct pc_dirent lbp;
1311 1312 struct pc_dirent *ld = &lbp;
1312 1313 int error;
1313 1314
1314 1315 /*
1315 1316 * If the filesystem was umounted by force, return immediately.
1316 1317 */
1317 1318 if (dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1318 1319 return (EIO);
1319 1320
1320 1321 if ((uiop->uio_iovcnt != 1) ||
1321 1322 (uiop->uio_loffset % sizeof (struct pcdir)) != 0) {
1322 1323 return (EINVAL);
1323 1324 }
1324 1325 fsp = VFSTOPCFS(dvp->v_vfsp);
1325 1326 /*
1326 1327 * verify that the dp is still valid on the disk
1327 1328 */
1328 1329 if (error = pc_verify(fsp)) {
1329 1330 return (error);
1330 1331 }
1331 1332 error = pc_lockfs(fsp, 0, 0);
1332 1333 if (error)
1333 1334 return (error);
1334 1335 if ((pcp = VTOPC(dvp)) == NULL || pcp->pc_flags & PC_INVAL) {
1335 1336 pc_unlockfs(fsp);
1336 1337 return (EIO);
1337 1338 }
1338 1339
1339 1340 bzero(ld, sizeof (*ld));
1340 1341
1341 1342 if (eofp != NULL)
1342 1343 *eofp = 0;
1343 1344 offset = uiop->uio_loffset;
1344 1345
1345 1346 if (dvp->v_flag & VROOT) {
1346 1347 /*
1347 1348 * kludge up entries for "." and ".." in the root.
1348 1349 */
1349 1350 if (offset == 0) {
1350 1351 (void) strcpy(ld->d_name, ".");
1351 1352 ld->d_reclen = DIRENT64_RECLEN(1);
1352 1353 ld->d_off = (off64_t)sizeof (struct pcdir);
1353 1354 ld->d_ino = (ino64_t)UINT_MAX;
1354 1355 if (ld->d_reclen > uiop->uio_resid) {
1355 1356 pc_unlockfs(fsp);
1356 1357 return (ENOSPC);
1357 1358 }
1358 1359 (void) uiomove(ld, ld->d_reclen, UIO_READ, uiop);
1359 1360 uiop->uio_loffset = ld->d_off;
1360 1361 offset = uiop->uio_loffset;
1361 1362 }
1362 1363 if (offset == sizeof (struct pcdir)) {
1363 1364 (void) strcpy(ld->d_name, "..");
1364 1365 ld->d_reclen = DIRENT64_RECLEN(2);
1365 1366 if (ld->d_reclen > uiop->uio_resid) {
1366 1367 pc_unlockfs(fsp);
1367 1368 return (ENOSPC);
1368 1369 }
1369 1370 ld->d_off = (off64_t)(uiop->uio_loffset +
1370 1371 sizeof (struct pcdir));
1371 1372 ld->d_ino = (ino64_t)UINT_MAX;
1372 1373 (void) uiomove(ld, ld->d_reclen, UIO_READ, uiop);
1373 1374 uiop->uio_loffset = ld->d_off;
1374 1375 offset = uiop->uio_loffset;
1375 1376 }
1376 1377 offset -= 2 * sizeof (struct pcdir);
1377 1378 /* offset now has the real offset value into directory file */
1378 1379 }
1379 1380
1380 1381 for (;;) {
1381 1382 boff = pc_blkoff(fsp, offset);
1382 1383 if (boff == 0 || bp == NULL || boff >= bp->b_bcount) {
1383 1384 if (bp != NULL) {
1384 1385 brelse(bp);
1385 1386 bp = NULL;
1386 1387 }
1387 1388 error = pc_blkatoff(pcp, offset, &bp, &ep);
1388 1389 if (error) {
1389 1390 if (error == ENOENT) {
1390 1391 error = 0;
1391 1392 if (eofp)
1392 1393 *eofp = 1;
1393 1394 }
1394 1395 break;
1395 1396 }
1396 1397 }
1397 1398 if (ep->pcd_filename[0] == PCD_UNUSED) {
1398 1399 if (eofp)
1399 1400 *eofp = 1;
1400 1401 break;
1401 1402 }
1402 1403 /*
1403 1404 * Don't display label because it may contain funny characters.
1404 1405 */
1405 1406 if (ep->pcd_filename[0] == PCD_ERASED) {
1406 1407 uiop->uio_loffset += sizeof (struct pcdir);
1407 1408 offset += sizeof (struct pcdir);
1408 1409 ep++;
1409 1410 continue;
1410 1411 }
1411 1412 if (PCDL_IS_LFN(ep)) {
1412 1413 if (pc_read_long_fn(dvp, uiop, ld, &ep, &offset, &bp) !=
1413 1414 0)
1414 1415 break;
1415 1416 continue;
1416 1417 }
1417 1418
1418 1419 if (pc_read_short_fn(dvp, uiop, ld, &ep, &offset, &bp) != 0)
↓ open down ↓ |
1380 lines elided |
↑ open up ↑ |
1419 1420 break;
1420 1421 }
1421 1422 if (bp)
1422 1423 brelse(bp);
1423 1424 pc_unlockfs(fsp);
1424 1425 return (error);
1425 1426 }
1426 1427
1427 1428
1428 1429 /*
1429 - * Called from pvn_getpages or pcfs_getpage to get a particular page.
1430 - * When we are called the pcfs is already locked.
1430 + * Called from pvn_getpages to get a particular page. When we are called
1431 + * the pcfs is already locked.
1431 1432 */
1432 1433 /*ARGSUSED*/
1433 1434 static int
1434 1435 pcfs_getapage(
1435 1436 struct vnode *vp,
1436 1437 u_offset_t off,
1437 1438 size_t len,
1438 1439 uint_t *protp,
1439 1440 page_t *pl[], /* NULL if async IO is requested */
1440 1441 size_t plsz,
1441 1442 struct seg *seg,
1442 1443 caddr_t addr,
1443 1444 enum seg_rw rw,
1444 1445 struct cred *cr)
1445 1446 {
1446 1447 struct pcnode *pcp;
1447 1448 struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp);
1448 1449 struct vnode *devvp;
1449 1450 page_t *pp;
1450 1451 page_t *pagefound;
1451 1452 int err;
1452 1453
1453 1454 /*
1454 1455 * If the filesystem was umounted by force, return immediately.
1455 1456 */
1456 1457 if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1457 1458 return (EIO);
1458 1459
1459 1460 PC_DPRINTF3(5, "pcfs_getapage: vp=%p off=%lld len=%lu\n",
1460 1461 (void *)vp, off, len);
1461 1462
1462 1463 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL)
1463 1464 return (EIO);
1464 1465 devvp = fsp->pcfs_devvp;
1465 1466
1466 1467 /* pcfs doesn't do readaheads */
1467 1468 if (pl == NULL)
1468 1469 return (0);
1469 1470
1470 1471 pl[0] = NULL;
1471 1472 err = 0;
1472 1473 /*
1473 1474 * If the accessed time on the pcnode has not already been
1474 1475 * set elsewhere (e.g. for read/setattr) we set the time now.
1475 1476 * This gives us approximate modified times for mmap'ed files
1476 1477 * which are accessed via loads in the user address space.
1477 1478 */
1478 1479 if ((pcp->pc_flags & PC_ACC) == 0 &&
1479 1480 ((fsp->pcfs_vfs->vfs_flag & VFS_RDONLY) == 0)) {
1480 1481 pc_mark_acc(fsp, pcp);
1481 1482 }
1482 1483 reread:
1483 1484 if ((pagefound = page_exists(vp, off)) == NULL) {
1484 1485 /*
1485 1486 * Need to really do disk IO to get the page(s).
1486 1487 */
1487 1488 struct buf *bp;
1488 1489 daddr_t lbn, bn;
1489 1490 u_offset_t io_off;
1490 1491 size_t io_len;
1491 1492 u_offset_t lbnoff, xferoffset;
1492 1493 u_offset_t pgoff;
1493 1494 uint_t xfersize;
1494 1495 int err1;
1495 1496
1496 1497 lbn = pc_lblkno(fsp, off);
1497 1498 lbnoff = off & ~(fsp->pcfs_clsize - 1);
1498 1499 xferoffset = off & ~(fsp->pcfs_secsize - 1);
1499 1500
1500 1501 pp = pvn_read_kluster(vp, off, seg, addr, &io_off, &io_len,
1501 1502 off, (size_t)MIN(pc_blksize(fsp, pcp, off), PAGESIZE), 0);
1502 1503 if (pp == NULL)
1503 1504 /*
1504 1505 * XXX - If pcfs is made MT-hot, this should go
1505 1506 * back to reread.
1506 1507 */
1507 1508 panic("pcfs_getapage pvn_read_kluster");
1508 1509
1509 1510 for (pgoff = 0; pgoff < PAGESIZE && xferoffset < pcp->pc_size;
1510 1511 pgoff += xfersize,
1511 1512 lbn += howmany(xfersize, fsp->pcfs_clsize),
1512 1513 lbnoff += xfersize, xferoffset += xfersize) {
1513 1514 /*
1514 1515 * read as many contiguous blocks as possible to
1515 1516 * fill this page
1516 1517 */
1517 1518 xfersize = PAGESIZE - pgoff;
1518 1519 err1 = pc_bmap(pcp, lbn, &bn, &xfersize);
1519 1520 if (err1) {
1520 1521 PC_DPRINTF1(1, "pc_getapage err=%d", err1);
1521 1522 err = err1;
1522 1523 goto out;
1523 1524 }
1524 1525 bp = pageio_setup(pp, xfersize, devvp, B_READ);
1525 1526 bp->b_edev = devvp->v_rdev;
1526 1527 bp->b_dev = cmpdev(devvp->v_rdev);
1527 1528 bp->b_blkno = bn + btodt(xferoffset - lbnoff);
1528 1529 bp->b_un.b_addr = (caddr_t)(uintptr_t)pgoff;
1529 1530 bp->b_file = vp;
1530 1531 bp->b_offset = (offset_t)(off + pgoff);
1531 1532
1532 1533 (void) bdev_strategy(bp);
1533 1534
1534 1535 lwp_stat_update(LWP_STAT_INBLK, 1);
1535 1536
1536 1537 if (err == 0)
1537 1538 err = biowait(bp);
1538 1539 else
1539 1540 (void) biowait(bp);
1540 1541 pageio_done(bp);
1541 1542 if (err)
1542 1543 goto out;
1543 1544 }
1544 1545 if (pgoff < PAGESIZE) {
1545 1546 pagezero(pp->p_prev, pgoff, PAGESIZE - pgoff);
1546 1547 }
1547 1548 pvn_plist_init(pp, pl, plsz, off, io_len, rw);
1548 1549 }
1549 1550 out:
1550 1551 if (err) {
1551 1552 if (pp != NULL)
1552 1553 pvn_read_done(pp, B_ERROR);
1553 1554 return (err);
1554 1555 }
1555 1556
1556 1557 if (pagefound) {
1557 1558 /*
1558 1559 * Page exists in the cache, acquire the "shared"
1559 1560 * lock. If this fails, go back to reread.
1560 1561 */
1561 1562 if ((pp = page_lookup(vp, off, SE_SHARED)) == NULL) {
1562 1563 goto reread;
1563 1564 }
1564 1565 pl[0] = pp;
1565 1566 pl[1] = NULL;
1566 1567 }
1567 1568 return (err);
1568 1569 }
1569 1570
1570 1571 /*
1571 1572 * Return all the pages from [off..off+len] in given file
1572 1573 */
1573 1574 /* ARGSUSED */
1574 1575 static int
1575 1576 pcfs_getpage(
1576 1577 struct vnode *vp,
1577 1578 offset_t off,
1578 1579 size_t len,
1579 1580 uint_t *protp,
1580 1581 page_t *pl[],
1581 1582 size_t plsz,
1582 1583 struct seg *seg,
1583 1584 caddr_t addr,
1584 1585 enum seg_rw rw,
1585 1586 struct cred *cr,
1586 1587 caller_context_t *ct)
1587 1588 {
1588 1589 struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp);
1589 1590 int err;
1590 1591
1591 1592 PC_DPRINTF0(6, "pcfs_getpage\n");
1592 1593 if (err = pc_verify(fsp))
1593 1594 return (err);
↓ open down ↓ |
153 lines elided |
↑ open up ↑ |
1594 1595 if (vp->v_flag & VNOMAP)
1595 1596 return (ENOSYS);
1596 1597 ASSERT(off <= UINT32_MAX);
1597 1598 err = pc_lockfs(fsp, 0, 0);
1598 1599 if (err)
1599 1600 return (err);
1600 1601 if (protp != NULL)
1601 1602 *protp = PROT_ALL;
1602 1603
1603 1604 ASSERT((off & PAGEOFFSET) == 0);
1604 - if (len <= PAGESIZE) {
1605 - err = pcfs_getapage(vp, off, len, protp, pl,
1606 - plsz, seg, addr, rw, cr);
1607 - } else {
1608 - err = pvn_getpages(pcfs_getapage, vp, off,
1609 - len, protp, pl, plsz, seg, addr, rw, cr);
1610 - }
1605 + err = pvn_getpages(pcfs_getapage, vp, off, len, protp, pl, plsz,
1606 + seg, addr, rw, cr);
1607 +
1611 1608 pc_unlockfs(fsp);
1612 1609 return (err);
1613 1610 }
1614 1611
1615 1612
1616 1613 /*
1617 1614 * Flags are composed of {B_INVAL, B_FREE, B_DONTNEED, B_FORCE}
1618 1615 * If len == 0, do from off to EOF.
1619 1616 *
1620 1617 * The normal cases should be len == 0 & off == 0 (entire vp list),
1621 1618 * len == MAXBSIZE (from segmap_release actions), and len == PAGESIZE
1622 1619 * (from pageout).
1623 1620 *
1624 1621 */
1625 1622 /*ARGSUSED*/
1626 1623 static int
1627 1624 pcfs_putpage(
1628 1625 struct vnode *vp,
1629 1626 offset_t off,
1630 1627 size_t len,
1631 1628 int flags,
1632 1629 struct cred *cr,
1633 1630 caller_context_t *ct)
1634 1631 {
1635 1632 struct pcnode *pcp;
1636 1633 page_t *pp;
1637 1634 struct pcfs *fsp;
1638 1635 u_offset_t io_off;
1639 1636 size_t io_len;
1640 1637 offset_t eoff;
1641 1638 int err;
1642 1639
1643 1640 /*
1644 1641 * If the filesystem was umounted by force, return immediately.
1645 1642 */
1646 1643 if (vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1647 1644 return (EIO);
1648 1645
1649 1646 PC_DPRINTF1(6, "pcfs_putpage vp=0x%p\n", (void *)vp);
1650 1647 if (vp->v_flag & VNOMAP)
1651 1648 return (ENOSYS);
1652 1649
1653 1650 fsp = VFSTOPCFS(vp->v_vfsp);
1654 1651
1655 1652 if (err = pc_verify(fsp))
1656 1653 return (err);
1657 1654 if ((pcp = VTOPC(vp)) == NULL) {
1658 1655 PC_DPRINTF1(3, "pcfs_putpage NULL vp=0x%p\n", (void *)vp);
1659 1656 return (EIO);
1660 1657 }
1661 1658 if (pcp->pc_flags & PC_INVAL)
1662 1659 return (EIO);
1663 1660
1664 1661 if (curproc == proc_pageout) {
1665 1662 /*
1666 1663 * XXX - This is a quick hack to avoid blocking
1667 1664 * pageout. Also to avoid pcfs_getapage deadlocking
1668 1665 * with putpage when memory is running out,
1669 1666 * since we only have one global lock and we don't
1670 1667 * support async putpage.
1671 1668 * It should be fixed someday.
1672 1669 *
1673 1670 * Interestingly, this used to be a test of NOMEMWAIT().
1674 1671 * We only ever got here once pcfs started supporting
1675 1672 * NFS sharing, and then only because the NFS server
1676 1673 * threads seem to do writes in sched's process context.
1677 1674 * Since everyone else seems to just care about pageout,
1678 1675 * the test was changed to look for pageout directly.
1679 1676 */
1680 1677 return (ENOMEM);
1681 1678 }
1682 1679
1683 1680 ASSERT(off <= UINT32_MAX);
1684 1681
1685 1682 flags &= ~B_ASYNC; /* XXX should fix this later */
1686 1683
1687 1684 err = pc_lockfs(fsp, 0, 0);
1688 1685 if (err)
1689 1686 return (err);
1690 1687 if (!vn_has_cached_data(vp) || off >= pcp->pc_size) {
1691 1688 pc_unlockfs(fsp);
1692 1689 return (0);
1693 1690 }
1694 1691
1695 1692 if (len == 0) {
1696 1693 /*
1697 1694 * Search the entire vp list for pages >= off
1698 1695 */
1699 1696 err = pvn_vplist_dirty(vp, off,
1700 1697 pcfs_putapage, flags, cr);
1701 1698 } else {
1702 1699 eoff = off + len;
1703 1700
1704 1701 for (io_off = off; io_off < eoff &&
1705 1702 io_off < pcp->pc_size; io_off += io_len) {
1706 1703 /*
1707 1704 * If we are not invalidating, synchronously
1708 1705 * freeing or writing pages use the routine
1709 1706 * page_lookup_nowait() to prevent reclaiming
1710 1707 * them from the free list.
1711 1708 */
1712 1709 if ((flags & B_INVAL) || ((flags & B_ASYNC) == 0)) {
1713 1710 pp = page_lookup(vp, io_off,
1714 1711 (flags & (B_INVAL | B_FREE)) ?
1715 1712 SE_EXCL : SE_SHARED);
1716 1713 } else {
1717 1714 pp = page_lookup_nowait(vp, io_off,
1718 1715 (flags & B_FREE) ? SE_EXCL : SE_SHARED);
1719 1716 }
1720 1717
1721 1718 if (pp == NULL || pvn_getdirty(pp, flags) == 0)
1722 1719 io_len = PAGESIZE;
1723 1720 else {
1724 1721 err = pcfs_putapage(vp, pp, &io_off, &io_len,
1725 1722 flags, cr);
1726 1723 if (err != 0)
1727 1724 break;
1728 1725 /*
1729 1726 * "io_off" and "io_len" are returned as
1730 1727 * the range of pages we actually wrote.
1731 1728 * This allows us to skip ahead more quickly
1732 1729 * since several pages may've been dealt
1733 1730 * with by this iteration of the loop.
1734 1731 */
1735 1732 }
1736 1733 }
1737 1734 }
1738 1735 if (err == 0 && (flags & B_INVAL) &&
1739 1736 off == 0 && len == 0 && vn_has_cached_data(vp)) {
1740 1737 /*
1741 1738 * If doing "invalidation", make sure that
1742 1739 * all pages on the vnode list are actually
1743 1740 * gone.
1744 1741 */
1745 1742 cmn_err(CE_PANIC,
1746 1743 "pcfs_putpage: B_INVAL, pages not gone");
1747 1744 } else if (err) {
1748 1745 PC_DPRINTF1(1, "pcfs_putpage err=%d\n", err);
1749 1746 }
1750 1747 pc_unlockfs(fsp);
1751 1748 return (err);
1752 1749 }
1753 1750
1754 1751 /*
1755 1752 * Write out a single page, possibly klustering adjacent dirty pages.
1756 1753 */
1757 1754 /*ARGSUSED*/
1758 1755 int
1759 1756 pcfs_putapage(
1760 1757 struct vnode *vp,
1761 1758 page_t *pp,
1762 1759 u_offset_t *offp,
1763 1760 size_t *lenp,
1764 1761 int flags,
1765 1762 struct cred *cr)
1766 1763 {
1767 1764 struct pcnode *pcp;
1768 1765 struct pcfs *fsp;
1769 1766 struct vnode *devvp;
1770 1767 size_t io_len;
1771 1768 daddr_t bn;
1772 1769 u_offset_t lbn, lbnoff, xferoffset;
1773 1770 uint_t pgoff, xfersize;
1774 1771 int err = 0;
1775 1772 u_offset_t io_off;
1776 1773
1777 1774 pcp = VTOPC(vp);
1778 1775 fsp = VFSTOPCFS(vp->v_vfsp);
1779 1776 devvp = fsp->pcfs_devvp;
1780 1777
1781 1778 /*
1782 1779 * If the modified time on the inode has not already been
1783 1780 * set elsewhere (e.g. for write/setattr) and this is not
1784 1781 * a call from msync (B_FORCE) we set the time now.
1785 1782 * This gives us approximate modified times for mmap'ed files
1786 1783 * which are modified via stores in the user address space.
1787 1784 */
1788 1785 if ((pcp->pc_flags & PC_MOD) == 0 || (flags & B_FORCE)) {
1789 1786 pcp->pc_flags |= PC_MOD;
1790 1787 pc_mark_mod(fsp, pcp);
1791 1788 }
1792 1789 pp = pvn_write_kluster(vp, pp, &io_off, &io_len, pp->p_offset,
1793 1790 PAGESIZE, flags);
1794 1791
1795 1792 if (fsp->pcfs_flags & PCFS_IRRECOV) {
1796 1793 goto out;
1797 1794 }
1798 1795
1799 1796 PC_DPRINTF1(7, "pc_putpage writing dirty page off=%llu\n", io_off);
1800 1797
1801 1798 lbn = pc_lblkno(fsp, io_off);
1802 1799 lbnoff = io_off & ~(fsp->pcfs_clsize - 1);
1803 1800 xferoffset = io_off & ~(fsp->pcfs_secsize - 1);
1804 1801
1805 1802 for (pgoff = 0; pgoff < io_len && xferoffset < pcp->pc_size;
1806 1803 pgoff += xfersize,
1807 1804 lbn += howmany(xfersize, fsp->pcfs_clsize),
1808 1805 lbnoff += xfersize, xferoffset += xfersize) {
1809 1806
1810 1807 struct buf *bp;
1811 1808 int err1;
1812 1809
1813 1810 /*
1814 1811 * write as many contiguous blocks as possible from this page
1815 1812 */
1816 1813 xfersize = io_len - pgoff;
1817 1814 err1 = pc_bmap(pcp, (daddr_t)lbn, &bn, &xfersize);
1818 1815 if (err1) {
1819 1816 err = err1;
1820 1817 goto out;
1821 1818 }
1822 1819 bp = pageio_setup(pp, xfersize, devvp, B_WRITE | flags);
1823 1820 bp->b_edev = devvp->v_rdev;
1824 1821 bp->b_dev = cmpdev(devvp->v_rdev);
1825 1822 bp->b_blkno = bn + btodt(xferoffset - lbnoff);
1826 1823 bp->b_un.b_addr = (caddr_t)(uintptr_t)pgoff;
1827 1824 bp->b_file = vp;
1828 1825 bp->b_offset = (offset_t)(io_off + pgoff);
1829 1826
1830 1827 (void) bdev_strategy(bp);
1831 1828
1832 1829 lwp_stat_update(LWP_STAT_OUBLK, 1);
1833 1830
1834 1831 if (err == 0)
1835 1832 err = biowait(bp);
1836 1833 else
1837 1834 (void) biowait(bp);
1838 1835 pageio_done(bp);
1839 1836 }
1840 1837 pvn_write_done(pp, ((err) ? B_ERROR : 0) | B_WRITE | flags);
1841 1838 pp = NULL;
1842 1839
1843 1840 out:
1844 1841 if ((fsp->pcfs_flags & PCFS_IRRECOV) && pp != NULL) {
1845 1842 pvn_write_done(pp, B_WRITE | flags);
1846 1843 } else if (err != 0 && pp != NULL) {
1847 1844 pvn_write_done(pp, B_ERROR | B_WRITE | flags);
1848 1845 }
1849 1846
1850 1847 if (offp)
1851 1848 *offp = io_off;
1852 1849 if (lenp)
1853 1850 *lenp = io_len;
1854 1851 PC_DPRINTF4(4, "pcfs_putapage: vp=%p pp=%p off=%lld len=%lu\n",
1855 1852 (void *)vp, (void *)pp, io_off, io_len);
1856 1853 if (err) {
1857 1854 PC_DPRINTF1(1, "pcfs_putapage err=%d", err);
1858 1855 }
1859 1856 return (err);
1860 1857 }
1861 1858
1862 1859 /*ARGSUSED*/
1863 1860 static int
1864 1861 pcfs_map(
1865 1862 struct vnode *vp,
1866 1863 offset_t off,
1867 1864 struct as *as,
1868 1865 caddr_t *addrp,
1869 1866 size_t len,
1870 1867 uchar_t prot,
1871 1868 uchar_t maxprot,
1872 1869 uint_t flags,
1873 1870 struct cred *cr,
1874 1871 caller_context_t *ct)
1875 1872 {
1876 1873 struct segvn_crargs vn_a;
1877 1874 int error;
1878 1875
1879 1876 PC_DPRINTF0(6, "pcfs_map\n");
1880 1877 if (vp->v_flag & VNOMAP)
1881 1878 return (ENOSYS);
1882 1879
1883 1880 if (off > UINT32_MAX || off + len > UINT32_MAX)
1884 1881 return (ENXIO);
1885 1882
1886 1883 as_rangelock(as);
1887 1884 error = choose_addr(as, addrp, len, off, ADDR_VACALIGN, flags);
1888 1885 if (error != 0) {
1889 1886 as_rangeunlock(as);
1890 1887 return (error);
1891 1888 }
1892 1889
1893 1890 vn_a.vp = vp;
1894 1891 vn_a.offset = off;
1895 1892 vn_a.type = flags & MAP_TYPE;
1896 1893 vn_a.prot = prot;
1897 1894 vn_a.maxprot = maxprot;
1898 1895 vn_a.flags = flags & ~MAP_TYPE;
1899 1896 vn_a.cred = cr;
1900 1897 vn_a.amp = NULL;
1901 1898 vn_a.szc = 0;
1902 1899 vn_a.lgrp_mem_policy_flags = 0;
1903 1900
1904 1901 error = as_map(as, *addrp, len, segvn_create, &vn_a);
1905 1902 as_rangeunlock(as);
1906 1903 return (error);
1907 1904 }
1908 1905
1909 1906 /* ARGSUSED */
1910 1907 static int
1911 1908 pcfs_seek(
1912 1909 struct vnode *vp,
1913 1910 offset_t ooff,
1914 1911 offset_t *noffp,
1915 1912 caller_context_t *ct)
1916 1913 {
1917 1914 if (*noffp < 0)
1918 1915 return (EINVAL);
1919 1916 else if (*noffp > MAXOFFSET_T)
1920 1917 return (EINVAL);
1921 1918 else
1922 1919 return (0);
1923 1920 }
1924 1921
1925 1922 /* ARGSUSED */
1926 1923 static int
1927 1924 pcfs_addmap(
1928 1925 struct vnode *vp,
1929 1926 offset_t off,
1930 1927 struct as *as,
1931 1928 caddr_t addr,
1932 1929 size_t len,
1933 1930 uchar_t prot,
1934 1931 uchar_t maxprot,
1935 1932 uint_t flags,
1936 1933 struct cred *cr,
1937 1934 caller_context_t *ct)
1938 1935 {
1939 1936 if (vp->v_flag & VNOMAP)
1940 1937 return (ENOSYS);
1941 1938 return (0);
1942 1939 }
1943 1940
1944 1941 /*ARGSUSED*/
1945 1942 static int
1946 1943 pcfs_delmap(
1947 1944 struct vnode *vp,
1948 1945 offset_t off,
1949 1946 struct as *as,
1950 1947 caddr_t addr,
1951 1948 size_t len,
1952 1949 uint_t prot,
1953 1950 uint_t maxprot,
1954 1951 uint_t flags,
1955 1952 struct cred *cr,
1956 1953 caller_context_t *ct)
1957 1954 {
1958 1955 if (vp->v_flag & VNOMAP)
1959 1956 return (ENOSYS);
1960 1957 return (0);
1961 1958 }
1962 1959
1963 1960 /*
1964 1961 * POSIX pathconf() support.
1965 1962 */
1966 1963 /* ARGSUSED */
1967 1964 static int
1968 1965 pcfs_pathconf(
1969 1966 struct vnode *vp,
1970 1967 int cmd,
1971 1968 ulong_t *valp,
1972 1969 struct cred *cr,
1973 1970 caller_context_t *ct)
1974 1971 {
1975 1972 struct pcfs *fsp = VFSTOPCFS(vp->v_vfsp);
1976 1973
1977 1974 switch (cmd) {
1978 1975 case _PC_LINK_MAX:
1979 1976 *valp = 1;
1980 1977 return (0);
1981 1978
1982 1979 case _PC_CASE_BEHAVIOR:
1983 1980 return (EINVAL);
1984 1981
1985 1982 case _PC_FILESIZEBITS:
1986 1983 /*
1987 1984 * Both FAT16 and FAT32 support 4GB - 1 byte for file size.
1988 1985 * FAT12 can only go up to the maximum filesystem capacity
1989 1986 * which is ~509MB.
1990 1987 */
1991 1988 *valp = IS_FAT12(fsp) ? 30 : 33;
1992 1989 return (0);
1993 1990
1994 1991 case _PC_TIMESTAMP_RESOLUTION:
1995 1992 /*
1996 1993 * PCFS keeps track of modification times, it its own
1997 1994 * internal format, to a resolution of 2 seconds.
1998 1995 * Since 2000 million is representable in an int32_t
1999 1996 * without overflow (or becoming negative), we allow
2000 1997 * this value to be returned.
2001 1998 */
2002 1999 *valp = 2000000000L;
2003 2000 return (0);
2004 2001
2005 2002 default:
2006 2003 return (fs_pathconf(vp, cmd, valp, cr, ct));
2007 2004 }
2008 2005
2009 2006 }
2010 2007
2011 2008 /* ARGSUSED */
2012 2009 static int
2013 2010 pcfs_space(
2014 2011 struct vnode *vp,
2015 2012 int cmd,
2016 2013 struct flock64 *bfp,
2017 2014 int flag,
2018 2015 offset_t offset,
2019 2016 cred_t *cr,
2020 2017 caller_context_t *ct)
2021 2018 {
2022 2019 struct vattr vattr;
2023 2020 int error;
2024 2021
2025 2022 if (cmd != F_FREESP)
2026 2023 return (EINVAL);
2027 2024
2028 2025 if ((error = convoff(vp, bfp, 0, offset)) == 0) {
2029 2026 if ((bfp->l_start > UINT32_MAX) || (bfp->l_len > UINT32_MAX))
2030 2027 return (EFBIG);
2031 2028 /*
2032 2029 * we only support the special case of l_len == 0,
2033 2030 * meaning free to end of file at this moment.
2034 2031 */
2035 2032 if (bfp->l_len != 0)
2036 2033 return (EINVAL);
2037 2034 vattr.va_mask = AT_SIZE;
2038 2035 vattr.va_size = bfp->l_start;
2039 2036 error = VOP_SETATTR(vp, (vattr_t *)&vattr, 0, cr, ct);
2040 2037 }
2041 2038 return (error);
2042 2039 }
2043 2040
2044 2041 /*
2045 2042 * Break up 'len' chars from 'buf' into a long file name chunk.
2046 2043 * Pad with '0xff' to make Norton Disk Doctor and Microsoft ScanDisk happy.
2047 2044 */
2048 2045 void
2049 2046 set_long_fn_chunk(struct pcdir_lfn *ep, char *buf, int len)
2050 2047 {
2051 2048 int i;
2052 2049
2053 2050 ASSERT(buf != NULL);
2054 2051
2055 2052 for (i = 0; i < PCLF_FIRSTNAMESIZE; i += 2) {
2056 2053 if (len > 0) {
2057 2054 ep->pcdl_firstfilename[i] = *buf++;
2058 2055 ep->pcdl_firstfilename[i + 1] = *buf++;
2059 2056 len -= 2;
2060 2057 } else {
2061 2058 ep->pcdl_firstfilename[i] = (uchar_t)0xff;
2062 2059 ep->pcdl_firstfilename[i + 1] = (uchar_t)0xff;
2063 2060 }
2064 2061 }
2065 2062
2066 2063 for (i = 0; i < PCLF_SECONDNAMESIZE; i += 2) {
2067 2064 if (len > 0) {
2068 2065 ep->pcdl_secondfilename[i] = *buf++;
2069 2066 ep->pcdl_secondfilename[i + 1] = *buf++;
2070 2067 len -= 2;
2071 2068 } else {
2072 2069 ep->pcdl_secondfilename[i] = (uchar_t)0xff;
2073 2070 ep->pcdl_secondfilename[i + 1] = (uchar_t)0xff;
2074 2071 }
2075 2072 }
2076 2073 for (i = 0; i < PCLF_THIRDNAMESIZE; i += 2) {
2077 2074 if (len > 0) {
2078 2075 ep->pcdl_thirdfilename[i] = *buf++;
2079 2076 ep->pcdl_thirdfilename[i + 1] = *buf++;
2080 2077 len -= 2;
2081 2078 } else {
2082 2079 ep->pcdl_thirdfilename[i] = (uchar_t)0xff;
2083 2080 ep->pcdl_thirdfilename[i + 1] = (uchar_t)0xff;
2084 2081 }
2085 2082 }
2086 2083 }
2087 2084
2088 2085 /*
2089 2086 * Extract the characters from the long filename chunk into 'buf'.
2090 2087 * Return the number of characters extracted.
2091 2088 */
2092 2089 static int
2093 2090 get_long_fn_chunk(struct pcdir_lfn *ep, char *buf)
2094 2091 {
2095 2092 char *tmp = buf;
2096 2093 int i;
2097 2094
2098 2095 /* Copy all the names, no filtering now */
2099 2096
2100 2097 for (i = 0; i < PCLF_FIRSTNAMESIZE; i += 2, tmp += 2) {
2101 2098 *tmp = ep->pcdl_firstfilename[i];
2102 2099 *(tmp + 1) = ep->pcdl_firstfilename[i + 1];
2103 2100
2104 2101 if ((*tmp == '\0') && (*(tmp+1) == '\0'))
2105 2102 return (tmp - buf);
2106 2103 }
2107 2104 for (i = 0; i < PCLF_SECONDNAMESIZE; i += 2, tmp += 2) {
2108 2105 *tmp = ep->pcdl_secondfilename[i];
2109 2106 *(tmp + 1) = ep->pcdl_secondfilename[i + 1];
2110 2107
2111 2108 if ((*tmp == '\0') && (*(tmp+1) == '\0'))
2112 2109 return (tmp - buf);
2113 2110 }
2114 2111 for (i = 0; i < PCLF_THIRDNAMESIZE; i += 2, tmp += 2) {
2115 2112 *tmp = ep->pcdl_thirdfilename[i];
2116 2113 *(tmp + 1) = ep->pcdl_thirdfilename[i + 1];
2117 2114
2118 2115 if ((*tmp == '\0') && (*(tmp+1) == '\0'))
2119 2116 return (tmp - buf);
2120 2117 }
2121 2118 return (tmp - buf);
2122 2119 }
2123 2120
2124 2121
2125 2122 /*
2126 2123 * Checksum the passed in short filename.
2127 2124 * This is used to validate each component of the long name to make
2128 2125 * sure the long name is valid (it hasn't been "detached" from the
2129 2126 * short filename). This algorithm was found in FreeBSD.
2130 2127 * (sys/fs/msdosfs/msdosfs_conv.c:winChksum(), Wolfgang Solfrank)
2131 2128 */
2132 2129
2133 2130 uchar_t
2134 2131 pc_checksum_long_fn(char *name, char *ext)
2135 2132 {
2136 2133 uchar_t c;
2137 2134 char b[11];
2138 2135
2139 2136 bcopy(name, b, 8);
2140 2137 bcopy(ext, b+8, 3);
2141 2138
2142 2139 c = b[0];
2143 2140 c = ((c << 7) | (c >> 1)) + b[1];
2144 2141 c = ((c << 7) | (c >> 1)) + b[2];
2145 2142 c = ((c << 7) | (c >> 1)) + b[3];
2146 2143 c = ((c << 7) | (c >> 1)) + b[4];
2147 2144 c = ((c << 7) | (c >> 1)) + b[5];
2148 2145 c = ((c << 7) | (c >> 1)) + b[6];
2149 2146 c = ((c << 7) | (c >> 1)) + b[7];
2150 2147 c = ((c << 7) | (c >> 1)) + b[8];
2151 2148 c = ((c << 7) | (c >> 1)) + b[9];
2152 2149 c = ((c << 7) | (c >> 1)) + b[10];
2153 2150
2154 2151 return (c);
2155 2152 }
2156 2153
2157 2154 /*
2158 2155 * Read a chunk of long filename entries into 'namep'.
2159 2156 * Return with offset pointing to short entry (on success), or next
2160 2157 * entry to read (if this wasn't a valid lfn really).
2161 2158 * Uses the passed-in buffer if it can, otherwise kmem_allocs() room for
2162 2159 * a long filename.
2163 2160 *
2164 2161 * Can also be called with a NULL namep, in which case it just returns
2165 2162 * whether this was really a valid long filename and consumes it
2166 2163 * (used by pc_dirempty()).
2167 2164 */
2168 2165 int
2169 2166 pc_extract_long_fn(struct pcnode *pcp, char *namep,
2170 2167 struct pcdir **epp, offset_t *offset, struct buf **bp)
2171 2168 {
2172 2169 struct pcdir *ep = *epp;
2173 2170 struct pcdir_lfn *lep = (struct pcdir_lfn *)ep;
2174 2171 struct vnode *dvp = PCTOV(pcp);
2175 2172 struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp);
2176 2173 char *lfn;
2177 2174 char *lfn_base;
2178 2175 int boff;
2179 2176 int i, cs;
2180 2177 char *buf;
2181 2178 uchar_t cksum;
2182 2179 int detached = 0;
2183 2180 int error = 0;
2184 2181 int foldcase;
2185 2182 int count = 0;
2186 2183 size_t u16l = 0, u8l = 0;
2187 2184 char *outbuf;
2188 2185 size_t ret, inlen, outlen;
2189 2186
2190 2187 foldcase = (fsp->pcfs_flags & PCFS_FOLDCASE);
2191 2188 lfn_base = kmem_alloc(PCMAXNAM_UTF16, KM_SLEEP);
2192 2189 lfn = lfn_base + PCMAXNAM_UTF16 - sizeof (uint16_t);
2193 2190 *lfn = '\0';
2194 2191 *(lfn + 1) = '\0';
2195 2192 cksum = lep->pcdl_checksum;
2196 2193
2197 2194 buf = kmem_alloc(PCMAXNAM_UTF16, KM_SLEEP);
2198 2195 for (i = (lep->pcdl_ordinal & ~0xc0); i > 0; i--) {
2199 2196 /* read next block if necessary */
2200 2197 boff = pc_blkoff(fsp, *offset);
2201 2198 if (boff == 0 || *bp == NULL || boff >= (*bp)->b_bcount) {
2202 2199 if (*bp != NULL) {
2203 2200 brelse(*bp);
2204 2201 *bp = NULL;
2205 2202 }
2206 2203 error = pc_blkatoff(pcp, *offset, bp, &ep);
2207 2204 if (error) {
2208 2205 kmem_free(lfn_base, PCMAXNAM_UTF16);
2209 2206 kmem_free(buf, PCMAXNAM_UTF16);
2210 2207 return (error);
2211 2208 }
2212 2209 lep = (struct pcdir_lfn *)ep;
2213 2210 }
2214 2211 /* can this happen? Bad fs? */
2215 2212 if (!PCDL_IS_LFN((struct pcdir *)lep)) {
2216 2213 detached = 1;
2217 2214 break;
2218 2215 }
2219 2216 if (cksum != lep->pcdl_checksum)
2220 2217 detached = 1;
2221 2218 /* process current entry */
2222 2219 cs = get_long_fn_chunk(lep, buf);
2223 2220 count += cs;
2224 2221 for (; cs > 0; cs--) {
2225 2222 /* see if we underflow */
2226 2223 if (lfn >= lfn_base)
2227 2224 *--lfn = buf[cs - 1];
2228 2225 else
2229 2226 detached = 1;
2230 2227 }
2231 2228 lep++;
2232 2229 *offset += sizeof (struct pcdir);
2233 2230 }
2234 2231 kmem_free(buf, PCMAXNAM_UTF16);
2235 2232 /* read next block if necessary */
2236 2233 boff = pc_blkoff(fsp, *offset);
2237 2234 ep = (struct pcdir *)lep;
2238 2235 if (boff == 0 || *bp == NULL || boff >= (*bp)->b_bcount) {
2239 2236 if (*bp != NULL) {
2240 2237 brelse(*bp);
2241 2238 *bp = NULL;
2242 2239 }
2243 2240 error = pc_blkatoff(pcp, *offset, bp, &ep);
2244 2241 if (error) {
2245 2242 kmem_free(lfn_base, PCMAXNAM_UTF16);
2246 2243 return (error);
2247 2244 }
2248 2245 }
2249 2246 /* should be on the short one */
2250 2247 if (PCDL_IS_LFN(ep) || ((ep->pcd_filename[0] == PCD_UNUSED) ||
2251 2248 (ep->pcd_filename[0] == PCD_ERASED))) {
2252 2249 detached = 1;
2253 2250 }
2254 2251 if (detached ||
2255 2252 (cksum != pc_checksum_long_fn(ep->pcd_filename, ep->pcd_ext)) ||
2256 2253 !pc_valid_long_fn(lfn, 0)) {
2257 2254 /*
2258 2255 * process current entry again. This may end up another lfn
2259 2256 * or a short name.
2260 2257 */
2261 2258 *epp = ep;
2262 2259 kmem_free(lfn_base, PCMAXNAM_UTF16);
2263 2260 return (EINVAL);
2264 2261 }
2265 2262 if (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) {
2266 2263 /*
2267 2264 * Don't display label because it may contain
2268 2265 * funny characters.
2269 2266 */
2270 2267 *offset += sizeof (struct pcdir);
2271 2268 ep++;
2272 2269 *epp = ep;
2273 2270 kmem_free(lfn_base, PCMAXNAM_UTF16);
2274 2271 return (EINVAL);
2275 2272 }
2276 2273 if (namep) {
2277 2274 u16l = count / 2;
2278 2275 u8l = PCMAXNAMLEN;
2279 2276 error = uconv_u16tou8((const uint16_t *)lfn, &u16l,
2280 2277 (uchar_t *)namep, &u8l, UCONV_IN_LITTLE_ENDIAN);
2281 2278 /*
2282 2279 * uconv_u16tou8() will catch conversion errors including
2283 2280 * the case where there is not enough room to write the
2284 2281 * converted result and the u8l will never go over the given
2285 2282 * PCMAXNAMLEN.
2286 2283 */
2287 2284 if (error != 0) {
2288 2285 kmem_free(lfn_base, PCMAXNAM_UTF16);
2289 2286 return (EINVAL);
2290 2287 }
2291 2288 namep[u8l] = '\0';
2292 2289 if (foldcase) {
2293 2290 inlen = strlen(namep);
2294 2291 outlen = PCMAXNAMLEN;
2295 2292 outbuf = kmem_alloc(PCMAXNAMLEN + 1, KM_SLEEP);
2296 2293 ret = u8_textprep_str(namep, &inlen, outbuf,
2297 2294 &outlen, U8_TEXTPREP_TOLOWER, U8_UNICODE_LATEST,
2298 2295 &error);
2299 2296 if (ret == -1) {
2300 2297 kmem_free(outbuf, PCMAXNAMLEN + 1);
2301 2298 kmem_free(lfn_base, PCMAXNAM_UTF16);
2302 2299 return (EINVAL);
2303 2300 }
2304 2301 outbuf[PCMAXNAMLEN - outlen] = '\0';
2305 2302 (void) strncpy(namep, outbuf, PCMAXNAMLEN + 1);
2306 2303 kmem_free(outbuf, PCMAXNAMLEN + 1);
2307 2304 }
2308 2305 }
2309 2306 kmem_free(lfn_base, PCMAXNAM_UTF16);
2310 2307 *epp = ep;
2311 2308 return (0);
2312 2309 }
2313 2310 /*
2314 2311 * Read a long filename into the pc_dirent structure and copy it out.
2315 2312 */
2316 2313 int
2317 2314 pc_read_long_fn(struct vnode *dvp, struct uio *uiop, struct pc_dirent *ld,
2318 2315 struct pcdir **epp, offset_t *offset, struct buf **bp)
2319 2316 {
2320 2317 struct pcdir *ep;
2321 2318 struct pcnode *pcp = VTOPC(dvp);
2322 2319 struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp);
2323 2320 offset_t uiooffset = uiop->uio_loffset;
2324 2321 int error = 0;
2325 2322 offset_t oldoffset;
2326 2323
2327 2324 oldoffset = *offset;
2328 2325 error = pc_extract_long_fn(pcp, ld->d_name, epp, offset, bp);
2329 2326 if (error) {
2330 2327 if (error == EINVAL) {
2331 2328 uiop->uio_loffset += *offset - oldoffset;
2332 2329 return (0);
2333 2330 } else
2334 2331 return (error);
2335 2332 }
2336 2333
2337 2334 ep = *epp;
2338 2335 uiop->uio_loffset += *offset - oldoffset;
2339 2336 ld->d_reclen = DIRENT64_RECLEN(strlen(ld->d_name));
2340 2337 if (ld->d_reclen > uiop->uio_resid) {
2341 2338 uiop->uio_loffset = uiooffset;
2342 2339 return (ENOSPC);
2343 2340 }
2344 2341 ld->d_off = uiop->uio_loffset + sizeof (struct pcdir);
2345 2342 ld->d_ino = pc_makenodeid(pc_daddrdb(fsp, (*bp)->b_blkno),
2346 2343 pc_blkoff(fsp, *offset), ep->pcd_attr,
2347 2344 pc_getstartcluster(fsp, ep), pc_direntpersec(fsp));
2348 2345 (void) uiomove((caddr_t)ld, ld->d_reclen, UIO_READ, uiop);
2349 2346 uiop->uio_loffset = ld->d_off;
2350 2347 *offset += sizeof (struct pcdir);
2351 2348 ep++;
2352 2349 *epp = ep;
2353 2350 return (0);
2354 2351 }
2355 2352
2356 2353 /*
2357 2354 * Read a short filename into the pc_dirent structure and copy it out.
2358 2355 */
2359 2356 int
2360 2357 pc_read_short_fn(struct vnode *dvp, struct uio *uiop, struct pc_dirent *ld,
2361 2358 struct pcdir **epp, offset_t *offset, struct buf **bp)
2362 2359 {
2363 2360 struct pcfs *fsp = VFSTOPCFS(dvp->v_vfsp);
2364 2361 int boff = pc_blkoff(fsp, *offset);
2365 2362 struct pcdir *ep = *epp;
2366 2363 offset_t oldoffset = uiop->uio_loffset;
2367 2364 int error;
2368 2365 int foldcase;
2369 2366
2370 2367 if (PCA_IS_HIDDEN(fsp, ep->pcd_attr)) {
2371 2368 uiop->uio_loffset += sizeof (struct pcdir);
2372 2369 *offset += sizeof (struct pcdir);
2373 2370 ep++;
2374 2371 *epp = ep;
2375 2372 return (0);
2376 2373 }
2377 2374 ld->d_ino = (ino64_t)pc_makenodeid(pc_daddrdb(fsp, (*bp)->b_blkno),
2378 2375 boff, ep->pcd_attr, pc_getstartcluster(fsp, ep),
2379 2376 pc_direntpersec(fsp));
2380 2377 foldcase = (fsp->pcfs_flags & PCFS_FOLDCASE);
2381 2378 error = pc_fname_ext_to_name(&ld->d_name[0], &ep->pcd_filename[0],
2382 2379 &ep->pcd_ext[0], foldcase);
2383 2380 if (error == 0) {
2384 2381 ld->d_reclen = DIRENT64_RECLEN(strlen(ld->d_name));
2385 2382 if (ld->d_reclen > uiop->uio_resid) {
2386 2383 uiop->uio_loffset = oldoffset;
2387 2384 return (ENOSPC);
2388 2385 }
2389 2386 ld->d_off = (off64_t)(uiop->uio_loffset +
2390 2387 sizeof (struct pcdir));
2391 2388 (void) uiomove((caddr_t)ld,
2392 2389 ld->d_reclen, UIO_READ, uiop);
2393 2390 uiop->uio_loffset = ld->d_off;
2394 2391 } else {
2395 2392 uiop->uio_loffset += sizeof (struct pcdir);
2396 2393 }
2397 2394 *offset += sizeof (struct pcdir);
2398 2395 ep++;
2399 2396 *epp = ep;
2400 2397 return (0);
2401 2398 }
2402 2399
2403 2400 /* ARGSUSED */
2404 2401 static int
2405 2402 pcfs_fid(struct vnode *vp, struct fid *fidp, caller_context_t *ct)
2406 2403 {
2407 2404 struct pc_fid *pcfid;
2408 2405 struct pcnode *pcp;
2409 2406 struct pcfs *fsp;
2410 2407 int error;
2411 2408
2412 2409 fsp = VFSTOPCFS(vp->v_vfsp);
2413 2410 if (fsp == NULL)
2414 2411 return (EIO);
2415 2412 error = pc_lockfs(fsp, 0, 0);
2416 2413 if (error)
2417 2414 return (error);
2418 2415 if ((pcp = VTOPC(vp)) == NULL || pcp->pc_flags & PC_INVAL) {
2419 2416 pc_unlockfs(fsp);
2420 2417 return (EIO);
2421 2418 }
2422 2419 if (fidp->fid_len < (sizeof (struct pc_fid) - sizeof (ushort_t))) {
2423 2420 fidp->fid_len = sizeof (struct pc_fid) - sizeof (ushort_t);
2424 2421 pc_unlockfs(fsp);
2425 2422 return (ENOSPC);
2426 2423 }
2427 2424
2428 2425 pcfid = (struct pc_fid *)fidp;
2429 2426 bzero(pcfid, sizeof (struct pc_fid));
2430 2427 pcfid->pcfid_len = sizeof (struct pc_fid) - sizeof (ushort_t);
2431 2428 if (vp->v_flag & VROOT) {
2432 2429 pcfid->pcfid_block = 0;
2433 2430 pcfid->pcfid_offset = 0;
2434 2431 pcfid->pcfid_ctime = 0;
2435 2432 } else {
2436 2433 pcfid->pcfid_block = pcp->pc_eblkno;
2437 2434 pcfid->pcfid_offset = pcp->pc_eoffset;
2438 2435 pcfid->pcfid_ctime = pcp->pc_entry.pcd_crtime.pct_time;
2439 2436 }
2440 2437 pc_unlockfs(fsp);
2441 2438 return (0);
2442 2439 }
↓ open down ↓ |
822 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX