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