chfs_vnops.c revision 1.33 1 /* $NetBSD: chfs_vnops.c,v 1.33 2017/05/26 14:21:02 riastradh Exp $ */
2
3 /*-
4 * Copyright (c) 2010 Department of Software Engineering,
5 * University of Szeged, Hungary
6 * Copyright (C) 2010 Tamas Toth <ttoth (at) inf.u-szeged.hu>
7 * Copyright (C) 2010 Adam Hoka <ahoka (at) NetBSD.org>
8 * All rights reserved.
9 *
10 * This code is derived from software contributed to The NetBSD Foundation
11 * by the Department of Software Engineering, University of Szeged, Hungary
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/param.h>
36 #include <miscfs/specfs/specdev.h>
37 #include <miscfs/fifofs/fifo.h>
38 #include <miscfs/genfs/genfs.h>
39 #include <ufs/ufs/dir.h>
40 #include <ufs/ufs/ufs_extern.h>
41 #include <uvm/uvm.h>
42 #include <sys/namei.h>
43 #include <sys/stat.h>
44 #include <sys/fcntl.h>
45 #include <sys/buf.h>
46 #include <sys/vnode.h>
47
48 #include "chfs.h"
49
50 #define READ_S "chfs_read"
51
52 int
53 chfs_lookup(void *v)
54 {
55 struct vnode *dvp = ((struct vop_lookup_v2_args *) v)->a_dvp;
56 struct vnode **vpp = ((struct vop_lookup_v2_args *) v)->a_vpp;
57 struct componentname *cnp = ((struct vop_lookup_v2_args *) v)->a_cnp;
58
59 int error;
60 struct chfs_inode* ip;
61 struct ufsmount* ump;
62 struct chfs_mount* chmp;
63 struct chfs_vnode_cache* chvc;
64 struct chfs_dirent* fd;
65
66 dbg("lookup(): %s\n", cnp->cn_nameptr);
67
68 KASSERT(VOP_ISLOCKED(dvp));
69
70 *vpp = NULL;
71
72 /* Check accessibility of requested node as a first step. */
73 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred);
74 if (error != 0) {
75 goto out;
76 }
77
78 /* If requesting the last path component on a read-only file system
79 * with a write operation, deny it. */
80 if ((cnp->cn_flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY)
81 && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) {
82 error = EROFS;
83 goto out;
84 }
85
86 /* Avoid doing a linear scan of the directory if the requested
87 * directory/name couple is already in the cache. */
88 if (cache_lookup(dvp, cnp->cn_nameptr, cnp->cn_namelen,
89 cnp->cn_nameiop, cnp->cn_flags, NULL, vpp)) {
90 return (*vpp == NULLVP ? ENOENT : 0);
91 }
92
93 ip = VTOI(dvp);
94 ump = VFSTOUFS(dvp->v_mount);
95 chmp = ump->um_chfs;
96 if (ip->ino == 0) {
97 ip->ino = ++chmp->chm_max_vno;
98 }
99 mutex_enter(&chmp->chm_lock_vnocache);
100 chvc = chfs_vnode_cache_get(chmp, ip->ino);
101 mutex_exit(&chmp->chm_lock_vnocache);
102
103 /* We cannot be requesting the parent directory of the root node. */
104 KASSERT(IMPLIES(ip->ch_type == CHT_DIR && chvc->pvno == chvc->vno,
105 !(cnp->cn_flags & ISDOTDOT)));
106
107 if (cnp->cn_flags & ISDOTDOT) {
108 VOP_UNLOCK(dvp);
109 error = VFS_VGET(dvp->v_mount, ip->chvc->pvno, vpp);
110 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
111 } else if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
112 vref(dvp);
113 *vpp = dvp;
114 error = 0;
115 } else {
116 fd = chfs_dir_lookup(ip, cnp);
117
118 if (fd == NULL) {
119 dbg("fd null\n");
120 /* The entry was not found in the directory.
121 * This is OK if we are creating or renaming an
122 * entry and are working on the last component of
123 * the path name. */
124 if ((cnp->cn_flags & ISLASTCN) && (cnp->cn_nameiop == CREATE
125 || cnp->cn_nameiop == RENAME)) {
126 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred);
127 if (error) {
128 dbg("after the entry was not found in dir\n");
129 goto out;
130 }
131
132 dbg("return EJUSTRETURN\n");
133 error = EJUSTRETURN;
134 } else {
135 error = ENOENT;
136 }
137 } else {
138 /* If we are not at the last path component and
139 * found a non-directory or non-link entry (which
140 * may itself be pointing to a directory), raise
141 * an error. */
142 if ((fd->type != CHT_DIR && fd->type != CHT_LNK) && !(cnp->cn_flags
143 & ISLASTCN)) {
144 error = ENOTDIR;
145 goto out;
146 }
147
148 dbg("vno@allocating new vnode: %llu\n",
149 (unsigned long long)fd->vno);
150 error = VFS_VGET(dvp->v_mount, fd->vno, vpp);
151 }
152 }
153 /* Store the result of this lookup in the cache. Avoid this if the
154 * request was for creation, as it does not improve timings on
155 * emprical tests. */
156 if (cnp->cn_nameiop != CREATE && (cnp->cn_flags & ISDOTDOT) == 0) {
157 cache_enter(dvp, *vpp, cnp->cn_nameptr, cnp->cn_namelen,
158 cnp->cn_flags);
159 }
160
161 out:
162 /* If there were no errors, *vpp cannot be NULL. */
163 KASSERT(IFF(error == 0, *vpp != NULL));
164 KASSERT(VOP_ISLOCKED(dvp));
165
166 if (error)
167 return error;
168 if (*vpp != dvp)
169 VOP_UNLOCK(*vpp);
170 return 0;
171 }
172
173 /* --------------------------------------------------------------------- */
174
175 int
176 chfs_create(void *v)
177 {
178 struct vop_create_v3_args /* {
179 struct vnode *a_dvp;
180 struct vnode **a_vpp;
181 struct componentname *a_cnp;
182 struct vattr *a_vap;
183 } */*ap = v;
184 int error, mode;
185 dbg("create()\n");
186
187 mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode);
188
189 if ((mode & IFMT) == 0) {
190 if (ap->a_vap->va_type == VREG)
191 mode |= IFREG;
192 if (ap->a_vap->va_type == VSOCK)
193 mode |= IFSOCK;
194 }
195
196 error = chfs_makeinode(mode, ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap->va_type);
197
198 if (error) {
199 dbg("error: %d\n", error);
200 return error;
201 }
202
203 VN_KNOTE(ap->a_dvp, NOTE_WRITE);
204 return 0;
205 }
206 /* --------------------------------------------------------------------- */
207
208 int
209 chfs_mknod(void *v)
210 {
211 struct vnode *dvp = ((struct vop_mknod_v3_args *) v)->a_dvp;
212 struct vnode **vpp = ((struct vop_mknod_v3_args *) v)->a_vpp;
213 struct componentname *cnp = ((struct vop_mknod_v3_args *) v)->a_cnp;
214 struct vattr *vap = ((struct vop_mknod_v3_args *) v)->a_vap;
215 int mode, err = 0;
216 struct chfs_inode *ip;
217 struct vnode *vp;
218
219 struct ufsmount *ump;
220 struct chfs_mount *chmp;
221
222 struct chfs_full_dnode *fd;
223 struct buf *bp;
224 int len;
225 dbg("mknod()\n");
226
227 ump = VFSTOUFS(dvp->v_mount);
228 chmp = ump->um_chfs;
229
230 /* Check type of node. */
231 if (vap->va_type != VBLK && vap->va_type != VCHR && vap->va_type != VFIFO)
232 return EINVAL;
233
234 vp = *vpp;
235
236 mode = MAKEIMODE(vap->va_type, vap->va_mode);
237
238 if ((mode & IFMT) == 0) {
239 switch (vap->va_type) {
240 case VBLK:
241 mode |= IFBLK;
242 break;
243 case VCHR:
244 mode |= IFCHR;
245 break;
246 case VFIFO:
247 mode |= IFIFO;
248 break;
249 default:
250 break;
251 }
252 }
253
254 /* Create a new node. */
255 err = chfs_makeinode(mode, dvp, &vp, cnp, vap->va_type);
256
257 ip = VTOI(vp);
258 if (vap->va_rdev != VNOVAL)
259 ip->rdev = vap->va_rdev;
260
261 if (vap->va_type == VFIFO)
262 vp->v_op = chfs_fifoop_p;
263 else {
264 vp->v_op = chfs_specop_p;
265 spec_node_init(vp, ip->rdev);
266 }
267
268 if (err)
269 return err;
270
271 /* Device is written out as a data node. */
272 len = sizeof(dev_t);
273 chfs_set_vnode_size(vp, len);
274 bp = getiobuf(vp, true);
275 bp->b_bufsize = bp->b_resid = len;
276 bp->b_data = kmem_alloc(len, KM_SLEEP);
277 memcpy(bp->b_data, &ip->rdev, len);
278 bp->b_blkno = 0;
279
280 fd = chfs_alloc_full_dnode();
281
282 mutex_enter(&chmp->chm_lock_mountfields);
283
284 err = chfs_write_flash_dnode(chmp, vp, bp, fd);
285 if (err) {
286 mutex_exit(&chmp->chm_lock_mountfields);
287 kmem_free(bp->b_data, len);
288 return err;
289 }
290
291 /* Add data node to the inode. */
292 err = chfs_add_full_dnode_to_inode(chmp, ip, fd);
293 if (err) {
294 mutex_exit(&chmp->chm_lock_mountfields);
295 kmem_free(bp->b_data, len);
296 return err;
297 }
298
299 mutex_exit(&chmp->chm_lock_mountfields);
300
301 *vpp = vp;
302 kmem_free(bp->b_data, len);
303 putiobuf(bp);
304
305 return 0;
306 }
307
308 /* --------------------------------------------------------------------- */
309
310 int
311 chfs_open(void *v)
312 {
313 struct vnode *vp = ((struct vop_open_args *) v)->a_vp;
314 int mode = ((struct vop_open_args *) v)->a_mode;
315 dbg("open()\n");
316
317 int error;
318 struct chfs_inode *ip;
319
320 KASSERT(VOP_ISLOCKED(vp));
321
322 ip = VTOI(vp);
323
324 KASSERT(vp->v_size == ip->size);
325 if (ip->chvc->nlink < 1) {
326 error = ENOENT;
327 goto out;
328 }
329
330 /* If the file is marked append-only, deny write requests. */
331 if (ip->flags & APPEND && (mode & (FWRITE | O_APPEND)) == FWRITE)
332 error = EPERM;
333 else
334 error = 0;
335
336 out:
337 KASSERT(VOP_ISLOCKED(vp));
338 return error;
339 }
340
341 /* --------------------------------------------------------------------- */
342
343 int
344 chfs_close(void *v)
345 {
346 struct vnode *vp = ((struct vop_close_args *) v)->a_vp;
347 dbg("close()\n");
348
349 struct chfs_inode *ip;
350
351 KASSERT(VOP_ISLOCKED(vp));
352
353 ip = VTOI(vp);
354
355 if (ip->chvc->nlink > 0) {
356 chfs_update(vp, NULL, NULL, UPDATE_CLOSE);
357 }
358
359 return 0;
360 }
361
362 /* --------------------------------------------------------------------- */
363
364 int
365 chfs_access(void *v)
366 {
367 struct vnode *vp = ((struct vop_access_args *) v)->a_vp;
368 int mode = ((struct vop_access_args *) v)->a_mode;
369 kauth_cred_t cred = ((struct vop_access_args *) v)->a_cred;
370
371 dbg("access()\n");
372 struct chfs_inode *ip = VTOI(vp);
373
374 if (mode & VWRITE) {
375 switch (vp->v_type) {
376 case VLNK:
377 case VDIR:
378 case VREG:
379 if (vp->v_mount->mnt_flag & MNT_RDONLY)
380 return (EROFS);
381 break;
382 case VBLK:
383 case VCHR:
384 case VSOCK:
385 case VFIFO:
386 break;
387 default:
388 break;
389 }
390 }
391
392 if (mode & VWRITE && ip->flags & IMMUTABLE)
393 return (EPERM);
394
395 return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, vp->v_type,
396 ip->mode & ALLPERMS), vp, NULL, genfs_can_access(vp->v_type,
397 ip->mode & ALLPERMS, ip->uid, ip->gid, mode, cred));
398 }
399
400 /* --------------------------------------------------------------------- */
401
402 int
403 chfs_getattr(void *v)
404 {
405 struct vnode *vp = ((struct vop_getattr_args *) v)->a_vp;
406 struct vattr *vap = ((struct vop_getattr_args *) v)->a_vap;
407
408 struct chfs_inode *ip = VTOI(vp);
409 dbg("getattr()\n");
410
411 KASSERT(vp->v_size == ip->size);
412
413 vattr_null(vap);
414 CHFS_ITIMES(ip, NULL, NULL, NULL);
415
416 vap->va_type = CHTTOVT(ip->ch_type);
417 vap->va_mode = ip->mode & ALLPERMS;
418 vap->va_nlink = ip->chvc->nlink;
419 vap->va_uid = ip->uid;
420 vap->va_gid = ip->gid;
421 vap->va_fsid = ip->dev;
422 vap->va_fileid = ip->ino;
423 vap->va_size = ip->size;
424 vap->va_blocksize = PAGE_SIZE;
425 vap->va_atime.tv_sec = ip->atime;
426 vap->va_atime.tv_nsec = 0;
427 vap->va_mtime.tv_sec = ip->mtime;
428 vap->va_mtime.tv_nsec = 0;
429 vap->va_ctime.tv_sec = ip->ctime;
430 vap->va_ctime.tv_nsec = 0;
431 vap->va_gen = ip->version;
432 vap->va_flags = ip->flags;
433 vap->va_rdev = ip->rdev;
434 vap->va_bytes = round_page(ip->size);
435 vap->va_filerev = VNOVAL;
436 vap->va_vaflags = 0;
437 vap->va_spare = VNOVAL;
438
439 return 0;
440 }
441
442 /* --------------------------------------------------------------------- */
443
444 /* Note: modelled after tmpfs's same function */
445
446 int
447 chfs_setattr(void *v)
448 {
449 struct vnode *vp = ((struct vop_setattr_args *) v)->a_vp;
450 struct vattr *vap = ((struct vop_setattr_args *) v)->a_vap;
451 kauth_cred_t cred = ((struct vop_setattr_args *) v)->a_cred;
452
453 struct chfs_inode *ip;
454 struct ufsmount *ump = VFSTOUFS(vp->v_mount);
455 struct chfs_mount *chmp = ump->um_chfs;
456 int error = 0;
457
458 dbg("setattr()\n");
459
460 KASSERT(VOP_ISLOCKED(vp));
461 ip = VTOI(vp);
462
463 /* Abort if any unsettable attribute is given. */
464 if (vap->va_type != VNON || vap->va_nlink != VNOVAL ||
465 vap->va_fsid != VNOVAL || vap->va_fileid != VNOVAL ||
466 vap->va_blocksize != VNOVAL /*|| GOODTIME(&vap->va_ctime)*/ ||
467 vap->va_gen != VNOVAL || vap->va_rdev != VNOVAL ||
468 vap->va_bytes != VNOVAL) {
469 return EINVAL;
470 }
471
472 /* set flags */
473 if (error == 0 && (vap->va_flags != VNOVAL)) {
474 error = chfs_chflags(vp, vap->va_flags, cred);
475 return error;
476 }
477
478 if (ip->flags & (IMMUTABLE | APPEND)) {
479 error = EPERM;
480 return error;
481 }
482
483 /* set size */
484 if (error == 0 && (vap->va_size != VNOVAL)) {
485 error = chfs_chsize(vp, vap->va_size, cred);
486 if (error)
487 return error;
488 }
489
490 /* set owner */
491 if (error == 0 && (vap->va_uid != VNOVAL || vap->va_gid != VNOVAL)) {
492 error = chfs_chown(vp, vap->va_uid, vap->va_gid, cred);
493 if (error)
494 return error;
495 }
496
497 /* set mode */
498 if (error == 0 && (vap->va_mode != VNOVAL)) {
499 error = chfs_chmod(vp, vap->va_mode, cred);
500 if (error)
501 return error;
502 }
503
504 /* set time */
505 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
506 error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
507 NULL, genfs_can_chtimes(vp, vap->va_vaflags, ip->uid, cred));
508 if (error)
509 return error;
510 if (vap->va_atime.tv_sec != VNOVAL)
511 ip->iflag |= IN_ACCESS;
512 if (vap->va_mtime.tv_sec != VNOVAL)
513 ip->iflag |= IN_CHANGE | IN_UPDATE;
514 error = chfs_update(vp,
515 &vap->va_atime, &vap->va_mtime, UPDATE_WAIT);
516 if (error)
517 return error;
518 }
519
520 /* Write it out. */
521 mutex_enter(&chmp->chm_lock_mountfields);
522 error = chfs_write_flash_vnode(chmp, ip, ALLOC_NORMAL);
523 mutex_exit(&chmp->chm_lock_mountfields);
524
525 return error;
526 }
527
528 int
529 chfs_chmod(struct vnode *vp, int mode, kauth_cred_t cred)
530 {
531 struct chfs_inode *ip = VTOI(vp);
532 int error;
533 dbg("chmod\n");
534
535 error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp,
536 NULL, genfs_can_chmod(vp->v_type, cred, ip->uid, ip->gid, mode));
537 if (error)
538 return error;
539 ip->mode &= ~ALLPERMS;
540 ip->mode |= (mode & ALLPERMS);
541 ip->iflag |= IN_CHANGE;
542
543 error = chfs_update(vp, NULL, NULL, UPDATE_WAIT);
544 if (error)
545 return error;
546
547 return 0;
548 }
549
550 int
551 chfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred)
552 {
553 struct chfs_inode *ip = VTOI(vp);
554 int error;
555 dbg("chown\n");
556
557 if (uid == (uid_t)VNOVAL)
558 uid = ip->uid;
559 if (gid == (gid_t)VNOVAL)
560 gid = ip->gid;
561
562 error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp,
563 NULL, genfs_can_chown(cred, ip->uid, ip->gid, uid, gid));
564 if (error)
565 return error;
566
567 ip->gid = gid;
568 ip->uid = uid;
569 ip->iflag |= IN_CHANGE;
570
571 error = chfs_update(vp, NULL, NULL, UPDATE_WAIT);
572 if (error)
573 return error;
574
575 return 0;
576 }
577
578
579 /* --------------------------------------------------------------------- */
580 /* calculates ((off_t)blk * chmp->chm_chm_fs_bsize) */
581 #define chfs_lblktosize(chmp, blk) \
582 (((off_t)(blk)) << (chmp)->chm_fs_bshift)
583
584 /* calculates (loc % chmp->chm_chm_fs_bsize) */
585 #define chfs_blkoff(chmp, loc) \
586 ((loc) & (chmp)->chm_fs_qbmask)
587
588 /* calculates (loc / chmp->chm_chm_fs_bsize) */
589 #define chfs_lblkno(chmp, loc) \
590 ((loc) >> (chmp)->chm_fs_bshift)
591
592 /* calculates roundup(size, chmp->chm_chm_fs_fsize) */
593 #define chfs_fragroundup(chmp, size) \
594 (((size) + (chmp)->chm_fs_qfmask) & (chmp)->chm_fs_fmask)
595
596 #define chfs_blksize(chmp, ip, lbn) \
597 (((lbn) >= UFS_NDADDR || (ip)->size >= chfs_lblktosize(chmp, (lbn) + 1)) \
598 ? (chmp)->chm_fs_bsize \
599 : (chfs_fragroundup(chmp, chfs_blkoff(chmp, (ip)->size))))
600
601 /* calculates roundup(size, chmp->chm_chm_fs_bsize) */
602 #define chfs_blkroundup(chmp, size) \
603 (((size) + (chmp)->chm_fs_qbmask) & (chmp)->chm_fs_bmask)
604
605 /* from ffs read */
606 int
607 chfs_read(void *v)
608 {
609 struct vop_read_args /* {
610 struct vnode *a_vp;
611 struct uio *a_uio;
612 int a_ioflag;
613 kauth_cred_t a_cred;
614 } */ *ap = v;
615 struct vnode *vp;
616 struct chfs_inode *ip;
617 struct uio *uio;
618 struct ufsmount *ump;
619 struct buf *bp;
620 struct chfs_mount *chmp;
621 daddr_t lbn, nextlbn;
622 off_t bytesinfile;
623 long size, xfersize, blkoffset;
624 int error, ioflag;
625 vsize_t bytelen;
626 bool usepc = false;
627
628 dbg("chfs_read\n");
629
630 vp = ap->a_vp;
631 ip = VTOI(vp);
632 ump = ip->ump;
633 uio = ap->a_uio;
634 ioflag = ap->a_ioflag;
635 error = 0;
636
637 dbg("ip->size:%llu\n", (unsigned long long)ip->size);
638
639 #ifdef DIAGNOSTIC
640 if (uio->uio_rw != UIO_READ)
641 panic("%s: mode", READ_S);
642
643 if (vp->v_type == VLNK) {
644 if (ip->size < ump->um_maxsymlinklen)
645 panic("%s: short symlink", READ_S);
646 } else if (vp->v_type != VREG && vp->v_type != VDIR)
647 panic("%s: type %d", READ_S, vp->v_type);
648 #endif
649 chmp = ip->chmp;
650 if ((u_int64_t)uio->uio_offset > ump->um_maxfilesize)
651 return (EFBIG);
652 if (uio->uio_resid == 0)
653 return (0);
654
655 if (uio->uio_offset >= ip->size)
656 goto out;
657
658 usepc = vp->v_type == VREG;
659 bytelen = 0;
660 if (usepc) {
661 const int advice = IO_ADV_DECODE(ap->a_ioflag);
662
663 while (uio->uio_resid > 0) {
664 if (ioflag & IO_DIRECT) {
665 genfs_directio(vp, uio, ioflag);
666 }
667 bytelen = MIN(ip->size - uio->uio_offset,
668 uio->uio_resid);
669 if (bytelen == 0)
670 break;
671 error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice,
672 UBC_READ | UBC_PARTIALOK |
673 (UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0));
674 if (error)
675 break;
676
677 }
678 goto out;
679 }
680
681 dbg("start reading\n");
682 for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
683 bytesinfile = ip->size - uio->uio_offset;
684 if (bytesinfile <= 0)
685 break;
686 lbn = chfs_lblkno(chmp, uio->uio_offset);
687 nextlbn = lbn + 1;
688 size = chfs_blksize(chmp, ip, lbn);
689 blkoffset = chfs_blkoff(chmp, uio->uio_offset);
690 xfersize = MIN(MIN(chmp->chm_fs_bsize - blkoffset, uio->uio_resid),
691 bytesinfile);
692
693 if (chfs_lblktosize(chmp, nextlbn) >= ip->size) {
694 error = bread(vp, lbn, size, 0, &bp);
695 dbg("after bread\n");
696 } else {
697 int nextsize = chfs_blksize(chmp, ip, nextlbn);
698 dbg("size: %ld\n", size);
699 error = breadn(vp, lbn,
700 size, &nextlbn, &nextsize, 1, 0, &bp);
701 dbg("after breadN\n");
702 }
703 if (error)
704 break;
705
706 /*
707 * We should only get non-zero b_resid when an I/O error
708 * has occurred, which should cause us to break above.
709 * However, if the short read did not cause an error,
710 * then we want to ensure that we do not uiomove bad
711 * or uninitialized data.
712 */
713 size -= bp->b_resid;
714 if (size < xfersize) {
715 if (size == 0)
716 break;
717 xfersize = size;
718 }
719 dbg("uiomove\n");
720 error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio);
721 if (error)
722 break;
723 brelse(bp, 0);
724 }
725
726 if (bp != NULL)
727 brelse(bp, 0);
728
729 out:
730 // FIXME HACK
731 ip->ino = ip->chvc->vno;
732
733 if (!(vp->v_mount->mnt_flag & MNT_NOATIME)) {
734 ip->iflag |= IN_ACCESS;
735 if ((ap->a_ioflag & IO_SYNC) == IO_SYNC) {
736 if (error) {
737 return error;
738 }
739 error = chfs_update(vp, NULL, NULL, UPDATE_WAIT);
740 }
741 }
742
743 dbg("[END]\n");
744
745 return (error);
746 }
747
748
749 /* --------------------------------------------------------------------- */
750
751 /* from ffs write */
752 int
753 chfs_write(void *v)
754 {
755 struct vop_write_args /* {
756 struct vnode *a_vp;
757 struct uio *a_uio;
758 int a_ioflag;
759 kauth_cred_t a_cred;
760 } */ *ap = v;
761 struct vnode *vp ;
762 struct uio *uio;
763 struct chfs_inode *ip;
764 struct chfs_mount *chmp;
765 struct lwp *l;
766 kauth_cred_t cred;
767 off_t osize, origoff, oldoff, preallocoff, endallocoff, nsize;
768 int blkoffset, error, flags, ioflag, resid;
769 int aflag;
770 int extended=0;
771 vsize_t bytelen;
772 bool async;
773 struct ufsmount *ump;
774
775
776 cred = ap->a_cred;
777 ioflag = ap->a_ioflag;
778 uio = ap->a_uio;
779 vp = ap->a_vp;
780 ip = VTOI(vp);
781 ump = ip->ump;
782
783 dbg("write\n");
784
785 KASSERT(vp->v_size == ip->size);
786
787 switch (vp->v_type) {
788 case VREG:
789 if (ioflag & IO_APPEND)
790 uio->uio_offset = ip->size;
791 if ((ip->flags & APPEND) && uio->uio_offset != ip->size)
792 return (EPERM);
793 /* FALLTHROUGH */
794 case VLNK:
795 break;
796 case VDIR:
797 if ((ioflag & IO_SYNC) == 0)
798 panic("chfs_write: nonsync dir write");
799 break;
800 default:
801 panic("chfs_write: type");
802 }
803
804 chmp = ip->chmp;
805 if (uio->uio_offset < 0 ||
806 (u_int64_t)uio->uio_offset +
807 uio->uio_resid > ump->um_maxfilesize) {
808 dbg("uio->uio_offset = %lld | uio->uio_offset + "
809 "uio->uio_resid (%llu) > ump->um_maxfilesize (%lld)\n",
810 (long long)uio->uio_offset,
811 (uint64_t)uio->uio_offset + uio->uio_resid,
812 (long long)ump->um_maxfilesize);
813 return (EFBIG);
814 }
815 /*
816 * Maybe this should be above the vnode op call, but so long as
817 * file servers have no limits, I don't think it matters.
818 */
819 l = curlwp;
820 if (vp->v_type == VREG && l &&
821 uio->uio_offset + uio->uio_resid >
822 l->l_proc->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
823 mutex_enter(proc_lock);
824 psignal(l->l_proc, SIGXFSZ);
825 mutex_exit(proc_lock);
826 return (EFBIG);
827 }
828 if (uio->uio_resid == 0)
829 return (0);
830
831 flags = ioflag & IO_SYNC ? B_SYNC : 0;
832 async = vp->v_mount->mnt_flag & MNT_ASYNC;
833 origoff = uio->uio_offset;
834 resid = uio->uio_resid;
835 osize = ip->size;
836 error = 0;
837
838 preallocoff = round_page(chfs_blkroundup(chmp,
839 MAX(osize, uio->uio_offset)));
840 aflag = ioflag & IO_SYNC ? B_SYNC : 0;
841 nsize = MAX(osize, uio->uio_offset + uio->uio_resid);
842 endallocoff = nsize - chfs_blkoff(chmp, nsize);
843
844 /*
845 * if we're increasing the file size, deal with expanding
846 * the fragment if there is one.
847 */
848
849 if (nsize > osize && chfs_lblkno(chmp, osize) < UFS_NDADDR &&
850 chfs_lblkno(chmp, osize) != chfs_lblkno(chmp, nsize) &&
851 chfs_blkroundup(chmp, osize) != osize) {
852 off_t eob;
853
854 eob = chfs_blkroundup(chmp, osize);
855 uvm_vnp_setwritesize(vp, eob);
856 error = ufs_balloc_range(vp, osize, eob - osize, cred, aflag);
857 if (error)
858 goto out;
859 if (flags & B_SYNC) {
860 mutex_enter(vp->v_interlock);
861 VOP_PUTPAGES(vp,
862 trunc_page(osize & chmp->chm_fs_bmask),
863 round_page(eob),
864 PGO_CLEANIT | PGO_SYNCIO | PGO_JOURNALLOCKED);
865 }
866 }
867
868 while (uio->uio_resid > 0) {
869 int ubc_flags = UBC_WRITE;
870 bool overwrite; /* if we're overwrite a whole block */
871 off_t newoff;
872
873 if (ioflag & IO_DIRECT) {
874 genfs_directio(vp, uio, ioflag | IO_JOURNALLOCKED);
875 }
876
877 oldoff = uio->uio_offset;
878 blkoffset = chfs_blkoff(chmp, uio->uio_offset);
879 bytelen = MIN(chmp->chm_fs_bsize - blkoffset, uio->uio_resid);
880 if (bytelen == 0) {
881 break;
882 }
883
884 /*
885 * if we're filling in a hole, allocate the blocks now and
886 * initialize the pages first. if we're extending the file,
887 * we can safely allocate blocks without initializing pages
888 * since the new blocks will be inaccessible until the write
889 * is complete.
890 */
891 overwrite = uio->uio_offset >= preallocoff &&
892 uio->uio_offset < endallocoff;
893 if (!overwrite && (vp->v_vflag & VV_MAPPED) == 0 &&
894 chfs_blkoff(chmp, uio->uio_offset) == 0 &&
895 (uio->uio_offset & PAGE_MASK) == 0) {
896 vsize_t len;
897
898 len = trunc_page(bytelen);
899 len -= chfs_blkoff(chmp, len);
900 if (len > 0) {
901 overwrite = true;
902 bytelen = len;
903 }
904 }
905
906 newoff = oldoff + bytelen;
907 if (vp->v_size < newoff) {
908 uvm_vnp_setwritesize(vp, newoff);
909 }
910
911 if (!overwrite) {
912 error = ufs_balloc_range(vp, uio->uio_offset, bytelen,
913 cred, aflag);
914 if (error)
915 break;
916 } else {
917 genfs_node_wrlock(vp);
918 error = GOP_ALLOC(vp, uio->uio_offset, bytelen,
919 aflag, cred);
920 genfs_node_unlock(vp);
921 if (error)
922 break;
923 ubc_flags |= UBC_FAULTBUSY;
924 }
925
926 /*
927 * copy the data.
928 */
929
930 ubc_flags |= UBC_WANT_UNMAP(vp) ? UBC_UNMAP : 0;
931 error = ubc_uiomove(&vp->v_uobj, uio, bytelen,
932 IO_ADV_DECODE(ioflag), ubc_flags);
933
934 /*
935 * update UVM's notion of the size now that we've
936 * copied the data into the vnode's pages.
937 *
938 * we should update the size even when uiomove failed.
939 */
940
941 if (vp->v_size < newoff) {
942 uvm_vnp_setsize(vp, newoff);
943 extended = 1;
944 }
945
946 if (error)
947 break;
948
949 /*
950 * flush what we just wrote if necessary.
951 * XXXUBC simplistic async flushing.
952 */
953
954 if (!async && oldoff >> 16 != uio->uio_offset >> 16) {
955 mutex_enter(vp->v_interlock);
956 error = VOP_PUTPAGES(vp, (oldoff >> 16) << 16,
957 (uio->uio_offset >> 16) << 16,
958 PGO_CLEANIT | PGO_JOURNALLOCKED);
959 if (error)
960 break;
961 }
962 }
963 out:
964 if (error == 0 && ioflag & IO_SYNC) {
965 mutex_enter(vp->v_interlock);
966 error = VOP_PUTPAGES(vp,
967 trunc_page(origoff & chmp->chm_fs_bmask),
968 round_page(chfs_blkroundup(chmp, uio->uio_offset)),
969 PGO_CLEANIT | PGO_SYNCIO | PGO_JOURNALLOCKED);
970 }
971 ip->iflag |= IN_CHANGE | IN_UPDATE;
972 if (resid > uio->uio_resid && ap->a_cred) {
973 if (ip->mode & ISUID) {
974 if (kauth_authorize_vnode(ap->a_cred,
975 KAUTH_VNODE_RETAIN_SUID, vp, NULL, EPERM) != 0)
976 ip->mode &= ~ISUID;
977 }
978
979 if (ip->mode & ISGID) {
980 if (kauth_authorize_vnode(ap->a_cred,
981 KAUTH_VNODE_RETAIN_SGID, vp, NULL, EPERM) != 0)
982 ip->mode &= ~ISGID;
983 }
984 }
985 if (resid > uio->uio_resid)
986 VN_KNOTE(vp, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
987 if (error) {
988 (void) UFS_TRUNCATE(vp, osize, ioflag & IO_SYNC, ap->a_cred);
989 uio->uio_offset -= resid - uio->uio_resid;
990 uio->uio_resid = resid;
991 } else if (resid > uio->uio_resid && (ioflag & IO_SYNC) == IO_SYNC)
992 error = UFS_UPDATE(vp, NULL, NULL, UPDATE_WAIT);
993
994 //FIXME HACK
995 chfs_set_vnode_size(vp, vp->v_size);
996
997
998 KASSERT(vp->v_size == ip->size);
999
1000 mutex_enter(&chmp->chm_lock_mountfields);
1001 error = chfs_write_flash_vnode(chmp, ip, ALLOC_NORMAL);
1002 mutex_exit(&chmp->chm_lock_mountfields);
1003
1004 return (error);
1005 }
1006
1007
1008 /* --------------------------------------------------------------------- */
1009
1010 int
1011 chfs_fsync(void *v)
1012 {
1013 struct vop_fsync_args /* {
1014 struct vnode *a_vp;
1015 kauth_cred_t a_cred;
1016 int a_flags;
1017 off_t offlo;
1018 off_t offhi;
1019 } */ *ap = v;
1020 struct vnode *vp = ap->a_vp;
1021
1022 if (ap->a_flags & FSYNC_CACHE) {
1023 return ENODEV;
1024 }
1025 vflushbuf(vp, ap->a_flags);
1026
1027 return 0;
1028 }
1029
1030 /* --------------------------------------------------------------------- */
1031
1032 int
1033 chfs_remove(void *v)
1034 {
1035 struct vnode *dvp = ((struct vop_remove_v2_args *) v)->a_dvp;
1036 struct vnode *vp = ((struct vop_remove_v2_args *) v)->a_vp;
1037 struct componentname *cnp = (((struct vop_remove_v2_args *) v)->a_cnp);
1038 dbg("remove\n");
1039
1040 KASSERT(VOP_ISLOCKED(dvp));
1041 KASSERT(VOP_ISLOCKED(vp));
1042
1043 struct chfs_inode *ip = VTOI(vp);
1044 struct chfs_inode *parent = VTOI(dvp);
1045 int error = 0;
1046
1047 if (vp->v_type == VDIR || (ip->flags & (IMMUTABLE | APPEND)) ||
1048 (parent->flags & APPEND)) {
1049 error = EPERM;
1050 goto out;
1051 }
1052
1053 KASSERT(ip->chvc->vno != ip->chvc->pvno);
1054
1055 error = chfs_do_unlink(ip,
1056 parent, cnp->cn_nameptr, cnp->cn_namelen);
1057
1058 out:
1059 vput(vp);
1060
1061 return error;
1062 }
1063
1064 /* --------------------------------------------------------------------- */
1065
1066 int
1067 chfs_link(void *v)
1068 {
1069 struct vnode *dvp = ((struct vop_link_v2_args *) v)->a_dvp;
1070 struct vnode *vp = ((struct vop_link_v2_args *) v)->a_vp;
1071 struct componentname *cnp = ((struct vop_link_v2_args *) v)->a_cnp;
1072
1073 struct chfs_inode *ip, *parent;
1074 int error = 0;
1075
1076 if (vp->v_type == VDIR) {
1077 VOP_ABORTOP(dvp, cnp);
1078 error = EISDIR;
1079 goto out;
1080 }
1081 if (dvp->v_mount != vp->v_mount) {
1082 VOP_ABORTOP(dvp, cnp);
1083 error = EXDEV;
1084 goto out;
1085 }
1086 if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE))) {
1087 VOP_ABORTOP(dvp, cnp);
1088 goto out;
1089 }
1090
1091 parent = VTOI(dvp);
1092 ip = VTOI(vp);
1093
1094 error = chfs_do_link(ip,
1095 parent, cnp->cn_nameptr, cnp->cn_namelen, ip->ch_type);
1096
1097 if (dvp != vp)
1098 VOP_UNLOCK(vp);
1099 out:
1100 return error;
1101 }
1102
1103 /* --------------------------------------------------------------------- */
1104
1105 int
1106 chfs_rename(void *v)
1107 {
1108 struct vnode *fdvp = ((struct vop_rename_args *) v)->a_fdvp;
1109 struct vnode *fvp = ((struct vop_rename_args *) v)->a_fvp;
1110 struct componentname *fcnp = ((struct vop_rename_args *) v)->a_fcnp;
1111 struct vnode *tdvp = ((struct vop_rename_args *) v)->a_tdvp;
1112 struct vnode *tvp = ((struct vop_rename_args *) v)->a_tvp;
1113 struct componentname *tcnp = ((struct vop_rename_args *) v)->a_tcnp;
1114
1115 struct chfs_inode *oldparent, *old;
1116 struct chfs_inode *newparent;
1117 struct chfs_dirent *fd;
1118 struct chfs_inode *ip;
1119 int error = 0;
1120 dbg("rename\n");
1121
1122 KASSERT(VOP_ISLOCKED(tdvp));
1123 KASSERT(IMPLIES(tvp != NULL, VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
1124
1125 oldparent = VTOI(fdvp);
1126 old = VTOI(fvp);
1127 newparent = VTOI(tdvp);
1128 if (tvp) {
1129 dbg("tvp not null\n");
1130 ip = VTOI(tvp);
1131 if (tvp->v_type == VDIR) {
1132 TAILQ_FOREACH(fd, &ip->dents, fds) {
1133 if (fd->vno) {
1134 error = ENOTEMPTY;
1135 goto out_unlocked;
1136 }
1137 }
1138 }
1139 error = chfs_do_unlink(ip,
1140 newparent, tcnp->cn_nameptr, tcnp->cn_namelen);
1141 vput(tvp);
1142 }
1143 VFS_VGET(tdvp->v_mount, old->ino, &tvp);
1144 ip = VTOI(tvp);
1145
1146 /* link new */
1147 error = chfs_do_link(ip,
1148 newparent, tcnp->cn_nameptr, tcnp->cn_namelen, ip->ch_type);
1149 /* remove old */
1150 error = chfs_do_unlink(old,
1151 oldparent, fcnp->cn_nameptr, fcnp->cn_namelen);
1152
1153 out_unlocked:
1154 /* Release target nodes. */
1155 if (tdvp == tvp)
1156 vrele(tdvp);
1157 else
1158 vput(tdvp);
1159 if (tvp != NULL)
1160 vput(tvp);
1161
1162 /* Release source nodes. */
1163 vrele(fdvp);
1164 vrele(fvp);
1165
1166 return error;
1167 }
1168
1169 /* --------------------------------------------------------------------- */
1170
1171 int
1172 chfs_mkdir(void *v)
1173 {
1174 struct vnode *dvp = ((struct vop_mkdir_v3_args *) v)->a_dvp;
1175 struct vnode **vpp = ((struct vop_mkdir_v3_args *)v)->a_vpp;
1176 struct componentname *cnp = ((struct vop_mkdir_v3_args *) v)->a_cnp;
1177 struct vattr *vap = ((struct vop_mkdir_v3_args *) v)->a_vap;
1178 dbg("mkdir()\n");
1179
1180 int mode;
1181
1182 mode = vap->va_mode & ACCESSPERMS;
1183 if ((mode & IFMT) == 0) {
1184 mode |= IFDIR;
1185 }
1186
1187 KASSERT(vap->va_type == VDIR);
1188
1189 return chfs_makeinode(mode, dvp, vpp, cnp, VDIR);
1190 }
1191
1192 /* --------------------------------------------------------------------- */
1193
1194 int
1195 chfs_rmdir(void *v)
1196 {
1197 struct vnode *dvp = ((struct vop_rmdir_v2_args *) v)->a_dvp;
1198 struct vnode *vp = ((struct vop_rmdir_v2_args *) v)->a_vp;
1199 struct componentname *cnp = ((struct vop_rmdir_v2_args *) v)->a_cnp;
1200 dbg("rmdir()\n");
1201
1202 KASSERT(VOP_ISLOCKED(dvp));
1203 KASSERT(VOP_ISLOCKED(vp));
1204
1205 struct chfs_inode *ip = VTOI(vp);
1206 struct chfs_inode *parent = VTOI(dvp);
1207 struct chfs_dirent *fd;
1208 int error = 0;
1209
1210 if (vp->v_type != VDIR) {
1211 error = ENOTDIR;
1212 goto out;
1213 }
1214
1215 KASSERT(ip->chvc->vno != ip->chvc->pvno);
1216
1217 TAILQ_FOREACH(fd, &ip->dents, fds) {
1218 if (fd->vno) {
1219 error = ENOTEMPTY;
1220 goto out;
1221 }
1222 }
1223
1224 error = chfs_do_unlink(ip,
1225 parent, cnp->cn_nameptr, cnp->cn_namelen);
1226
1227 out:
1228 vput(vp);
1229
1230 return error;
1231 }
1232
1233 /* --------------------------------------------------------------------- */
1234
1235 int
1236 chfs_symlink(void *v)
1237 {
1238 struct vnode *dvp = ((struct vop_symlink_v3_args *) v)->a_dvp;
1239 struct vnode **vpp = ((struct vop_symlink_v3_args *) v)->a_vpp;
1240 struct componentname *cnp = ((struct vop_symlink_v3_args *) v)->a_cnp;
1241 struct vattr *vap = ((struct vop_symlink_v3_args *) v)->a_vap;
1242 char *target = ((struct vop_symlink_v3_args *) v)->a_target;
1243
1244 struct ufsmount *ump;
1245 struct chfs_mount *chmp;
1246 struct vnode *vp;
1247 struct chfs_inode *ip;
1248 int len, err;
1249 struct chfs_full_dnode *fd;
1250 struct buf *bp;
1251 dbg("symlink()\n");
1252
1253 ump = VFSTOUFS(dvp->v_mount);
1254 chmp = ump->um_chfs;
1255
1256 err = chfs_makeinode(IFLNK | vap->va_mode, dvp, vpp, cnp, VLNK);
1257 if (err)
1258 return (err);
1259 VN_KNOTE(dvp, NOTE_WRITE);
1260 vp = *vpp;
1261 len = strlen(target);
1262 ip = VTOI(vp);
1263 /* TODO max symlink len instead of "100" */
1264 if (len < 100) {
1265 /* symlink path stored as a data node */
1266 ip->target = kmem_alloc(len, KM_SLEEP);
1267 memcpy(ip->target, target, len);
1268 chfs_set_vnode_size(vp, len);
1269 ip->iflag |= IN_CHANGE | IN_UPDATE;
1270
1271 bp = getiobuf(vp, true);
1272 bp->b_bufsize = bp->b_resid = len;
1273 bp->b_data = kmem_alloc(len, KM_SLEEP);
1274 memcpy(bp->b_data, target, len);
1275 bp->b_blkno = 0;
1276
1277 fd = chfs_alloc_full_dnode();
1278
1279 mutex_enter(&chmp->chm_lock_mountfields);
1280
1281 /* write out the data node */
1282 err = chfs_write_flash_dnode(chmp, vp, bp, fd);
1283 if (err) {
1284 mutex_exit(&chmp->chm_lock_mountfields);
1285 goto out;
1286 }
1287
1288 /* add it to the inode */
1289 err = chfs_add_full_dnode_to_inode(chmp, ip, fd);
1290 if (err) {
1291 mutex_exit(&chmp->chm_lock_mountfields);
1292 goto out;
1293 }
1294
1295 mutex_exit(&chmp->chm_lock_mountfields);
1296
1297 kmem_free(bp->b_data, len);
1298 putiobuf(bp);
1299
1300 uvm_vnp_setsize(vp, len);
1301 } else {
1302 err = ufs_bufio(UIO_WRITE, vp, target, len, (off_t)0,
1303 IO_NODELOCKED, cnp->cn_cred, (size_t *)0, NULL);
1304 }
1305
1306 out:
1307 if (err)
1308 vrele(vp);
1309
1310 return (err);
1311 }
1312
1313 /* --------------------------------------------------------------------- */
1314
1315 int
1316 chfs_readdir(void *v)
1317 {
1318 struct vnode *vp = ((struct vop_readdir_args *) v)->a_vp;
1319 struct uio *uio = ((struct vop_readdir_args *) v)->a_uio;
1320 int *eofflag = ((struct vop_readdir_args *) v)->a_eofflag;
1321
1322 int error = 0;
1323 off_t skip, offset;
1324 struct chfs_inode *ip;
1325 struct chfs_dirent *fd;
1326
1327 struct ufsmount *ump;
1328 struct chfs_mount *chmp;
1329 struct chfs_vnode_cache *chvc;
1330
1331 KASSERT(VOP_ISLOCKED(vp));
1332
1333 /* This operation only makes sense on directory nodes. */
1334 if (vp->v_type != VDIR) {
1335 error = ENOTDIR;
1336 goto out;
1337 }
1338
1339 ip = VTOI(vp);
1340
1341 /* uiomove in chfs_filldir automatically increments the
1342 * uio_offset by an arbitrary size, so we discard any change
1343 * to uio_offset and set it to our own value on return
1344 */
1345 offset = uio->uio_offset;
1346
1347 /* Add this entry. */
1348 if (offset == CHFS_OFFSET_DOT) {
1349 error = chfs_filldir(uio, ip->ino, ".", 1, CHT_DIR);
1350 if (error == -1) {
1351 error = 0;
1352 goto outok;
1353 } else if (error != 0)
1354 goto outok;
1355
1356 offset = CHFS_OFFSET_DOTDOT;
1357 }
1358
1359 /* Add parent entry. */
1360 if (offset == CHFS_OFFSET_DOTDOT) {
1361 ump = VFSTOUFS(vp->v_mount);
1362 chmp = ump->um_chfs;
1363 mutex_enter(&chmp->chm_lock_vnocache);
1364 chvc = chfs_vnode_cache_get(chmp, ip->ino);
1365 mutex_exit(&chmp->chm_lock_vnocache);
1366
1367 error = chfs_filldir(uio, chvc->pvno, "..", 2, CHT_DIR);
1368 if (error == -1) {
1369 error = 0;
1370 goto outok;
1371 } else if (error != 0) {
1372 goto outok;
1373 }
1374
1375 /* Has child or not? */
1376 if (TAILQ_EMPTY(&ip->dents)) {
1377 offset = CHFS_OFFSET_EOF;
1378 } else {
1379 offset = CHFS_OFFSET_FIRST;
1380 }
1381 }
1382
1383 if (offset != CHFS_OFFSET_EOF) {
1384 /* Child entries. */
1385 skip = offset - CHFS_OFFSET_FIRST;
1386
1387 TAILQ_FOREACH(fd, &ip->dents, fds) {
1388 /* seek to offset by skipping items */
1389 /* XXX race conditions by changed dirent? */
1390 if (skip > 0) {
1391 skip--;
1392 continue;
1393 }
1394
1395 if (fd->vno != 0) {
1396 error = chfs_filldir(uio, fd->vno,
1397 fd->name, fd->nsize, fd->type);
1398 if (error == -1) {
1399 error = 0;
1400 goto outok;
1401 } else if (error != 0) {
1402 dbg("err %d\n", error);
1403 goto outok;
1404 }
1405 }
1406 offset++;
1407 }
1408 }
1409 offset = CHFS_OFFSET_EOF;
1410
1411 outok:
1412 uio->uio_offset = offset;
1413
1414 if (eofflag != NULL) {
1415 *eofflag = (error == 0 &&
1416 uio->uio_offset == CHFS_OFFSET_EOF);
1417 }
1418
1419 out:
1420 KASSERT(VOP_ISLOCKED(vp));
1421
1422 return error;
1423 }
1424
1425 /* --------------------------------------------------------------------- */
1426
1427 int
1428 chfs_readlink(void *v)
1429 {
1430
1431 struct vnode *vp = ((struct vop_readlink_args *) v)->a_vp;
1432 struct uio *uio = ((struct vop_readlink_args *) v)->a_uio;
1433 kauth_cred_t cred = ((struct vop_readlink_args *) v)->a_cred;
1434
1435 struct chfs_inode *ip = VTOI(vp);
1436
1437 dbg("readlink()\n");
1438
1439 /* TODO max symlink len instead of "100" */
1440 if (ip->size < 100) {
1441 uiomove(ip->target, ip->size, uio);
1442 return (0);
1443 }
1444
1445 return (UFS_BUFRD(vp, uio, 0, cred));
1446 }
1447
1448 /* --------------------------------------------------------------------- */
1449
1450 int
1451 chfs_inactive(void *v)
1452 {
1453 struct vnode *vp = ((struct vop_inactive_v2_args *) v)->a_vp;
1454 struct chfs_inode *ip = VTOI(vp);
1455 struct chfs_vnode_cache *chvc;
1456 dbg("inactive | vno: %llu\n", (unsigned long long)ip->ino);
1457
1458 KASSERT(VOP_ISLOCKED(vp));
1459
1460 /* Reclaim only if there is no link to the node. */
1461 if (ip->ino) {
1462 chvc = ip->chvc;
1463 if (chvc->nlink)
1464 *((struct vop_inactive_v2_args *) v)->a_recycle = 0;
1465 } else {
1466 *((struct vop_inactive_v2_args *) v)->a_recycle = 1;
1467 }
1468
1469 return 0;
1470 }
1471
1472 /* --------------------------------------------------------------------- */
1473
1474 int
1475 chfs_reclaim(void *v)
1476 {
1477 struct vop_reclaim_v2_args *ap = v;
1478 struct vnode *vp = ap->a_vp;
1479 struct chfs_inode *ip = VTOI(vp);
1480 struct chfs_mount *chmp = ip->chmp;
1481 struct chfs_dirent *fd;
1482
1483 VOP_UNLOCK(vp);
1484
1485 mutex_enter(&chmp->chm_lock_mountfields);
1486
1487 mutex_enter(&chmp->chm_lock_vnocache);
1488 ip->chvc->state = VNO_STATE_CHECKEDABSENT;
1489 mutex_exit(&chmp->chm_lock_vnocache);
1490
1491 chfs_update(vp, NULL, NULL, UPDATE_CLOSE);
1492
1493 /* Clean fragments. */
1494 chfs_kill_fragtree(chmp, &ip->fragtree);
1495
1496 /* Clean dirents. */
1497 fd = TAILQ_FIRST(&ip->dents);
1498 while (fd) {
1499 TAILQ_REMOVE(&ip->dents, fd, fds);
1500 chfs_free_dirent(fd);
1501 fd = TAILQ_FIRST(&ip->dents);
1502 }
1503
1504 cache_purge(vp);
1505 if (ip->devvp) {
1506 vrele(ip->devvp);
1507 ip->devvp = 0;
1508 }
1509
1510 genfs_node_destroy(vp);
1511 pool_put(&chfs_inode_pool, vp->v_data);
1512 vp->v_data = NULL;
1513
1514 mutex_exit(&chmp->chm_lock_mountfields);
1515
1516 return (0);
1517 }
1518
1519 /* --------------------------------------------------------------------- */
1520
1521 int
1522 chfs_advlock(void *v)
1523 {
1524 return 0;
1525 }
1526
1527 /* --------------------------------------------------------------------- */
1528 int
1529 chfs_strategy(void *v)
1530 {
1531 struct vop_strategy_args /* {
1532 const struct vnodeop_desc *a_desc;
1533 struct vnode *a_vp;
1534 struct buf *a_bp;
1535 } */ *ap = v;
1536 struct chfs_full_dnode *fd;
1537 struct buf *bp = ap->a_bp;
1538 struct vnode *vp = ap->a_vp;
1539 struct chfs_inode *ip = VTOI(vp);
1540 struct chfs_mount *chmp = ip->chmp;
1541 int read = (bp->b_flags & B_READ) ? 1 : 0;
1542 int err = 0;
1543
1544 if (read) {
1545 err = chfs_read_data(chmp, vp, bp);
1546 } else {
1547 mutex_enter(&chmp->chm_lock_mountfields);
1548
1549 fd = chfs_alloc_full_dnode();
1550
1551 err = chfs_write_flash_dnode(chmp, vp, bp, fd);
1552 if (err) {
1553 mutex_exit(&chmp->chm_lock_mountfields);
1554 goto out;
1555 }
1556
1557 ip = VTOI(vp);
1558 err = chfs_add_full_dnode_to_inode(chmp, ip, fd);
1559
1560 mutex_exit(&chmp->chm_lock_mountfields);
1561 }
1562 out:
1563 biodone(bp);
1564 return err;
1565 }
1566
1567 int
1568 chfs_bmap(void *v)
1569 {
1570 struct vop_bmap_args /* {
1571 struct vnode *a_vp;
1572 daddr_t a_bn;
1573 struct vnode **a_vpp;
1574 daddr_t *a_bnp;
1575 int *a_runp;
1576 int *a_runb;
1577 } */ *ap = v;
1578 if (ap->a_vpp != NULL)
1579 *ap->a_vpp = ap->a_vp;
1580 if (ap->a_bnp != NULL)
1581 *ap->a_bnp = ap->a_bn;
1582 if (ap->a_runp != NULL)
1583 *ap->a_runp = 0;
1584 return (0);
1585 }
1586
1587 /*
1588 * vnode operations vector used for files stored in a chfs file system.
1589 */
1590 int
1591 (**chfs_vnodeop_p)(void *);
1592 const struct vnodeopv_entry_desc chfs_vnodeop_entries[] =
1593 {
1594 { &vop_default_desc, vn_default_error },
1595 { &vop_lookup_desc, chfs_lookup },
1596 { &vop_create_desc, chfs_create },
1597 { &vop_mknod_desc, chfs_mknod },
1598 { &vop_open_desc, chfs_open },
1599 { &vop_close_desc, chfs_close },
1600 { &vop_access_desc, chfs_access },
1601 { &vop_getattr_desc, chfs_getattr },
1602 { &vop_setattr_desc, chfs_setattr },
1603 { &vop_read_desc, chfs_read },
1604 { &vop_write_desc, chfs_write },
1605 { &vop_fallocate_desc, genfs_eopnotsupp },
1606 { &vop_fdiscard_desc, genfs_eopnotsupp },
1607 { &vop_ioctl_desc, genfs_enoioctl },
1608 { &vop_fcntl_desc, genfs_fcntl },
1609 { &vop_poll_desc, genfs_poll },
1610 { &vop_kqfilter_desc, genfs_kqfilter },
1611 { &vop_revoke_desc, genfs_revoke },
1612 { &vop_mmap_desc, genfs_mmap },
1613 { &vop_fsync_desc, chfs_fsync },
1614 { &vop_seek_desc, genfs_seek },
1615 { &vop_remove_desc, chfs_remove },
1616 { &vop_link_desc, chfs_link },
1617 { &vop_rename_desc, chfs_rename },
1618 { &vop_mkdir_desc, chfs_mkdir },
1619 { &vop_rmdir_desc, chfs_rmdir },
1620 { &vop_symlink_desc, chfs_symlink },
1621 { &vop_readdir_desc, chfs_readdir },
1622 { &vop_readlink_desc, chfs_readlink },
1623 { &vop_abortop_desc, genfs_abortop },
1624 { &vop_inactive_desc, chfs_inactive },
1625 { &vop_reclaim_desc, chfs_reclaim },
1626 { &vop_lock_desc, genfs_lock },
1627 { &vop_unlock_desc, genfs_unlock },
1628 { &vop_bmap_desc, chfs_bmap },
1629 { &vop_strategy_desc, chfs_strategy },
1630 { &vop_print_desc, ufs_print },
1631 { &vop_pathconf_desc, ufs_pathconf },
1632 { &vop_islocked_desc, genfs_islocked },
1633 { &vop_advlock_desc, chfs_advlock },
1634 { &vop_bwrite_desc, vn_bwrite },
1635 { &vop_getpages_desc, genfs_getpages },
1636 { &vop_putpages_desc, genfs_putpages },
1637 { NULL, NULL } };
1638
1639 const struct vnodeopv_desc chfs_vnodeop_opv_desc =
1640 { &chfs_vnodeop_p, chfs_vnodeop_entries };
1641
1642 /* --------------------------------------------------------------------- */
1643
1644 /*
1645 * vnode operations vector used for special devices stored in a chfs
1646 * file system.
1647 */
1648 int
1649 (**chfs_specop_p)(void *);
1650 const struct vnodeopv_entry_desc chfs_specop_entries[] =
1651 {
1652 { &vop_default_desc, vn_default_error },
1653 { &vop_lookup_desc, spec_lookup },
1654 { &vop_create_desc, spec_create },
1655 { &vop_mknod_desc, spec_mknod },
1656 { &vop_open_desc, spec_open },
1657 { &vop_close_desc, ufsspec_close },
1658 { &vop_access_desc, chfs_access },
1659 { &vop_getattr_desc, chfs_getattr },
1660 { &vop_setattr_desc, chfs_setattr },
1661 { &vop_read_desc, chfs_read },
1662 { &vop_write_desc, chfs_write },
1663 { &vop_fallocate_desc, spec_fallocate },
1664 { &vop_fdiscard_desc, spec_fdiscard },
1665 { &vop_ioctl_desc, spec_ioctl },
1666 { &vop_fcntl_desc, genfs_fcntl },
1667 { &vop_poll_desc, spec_poll },
1668 { &vop_kqfilter_desc, spec_kqfilter },
1669 { &vop_revoke_desc, spec_revoke },
1670 { &vop_mmap_desc, spec_mmap },
1671 { &vop_fsync_desc, spec_fsync },
1672 { &vop_seek_desc, spec_seek },
1673 { &vop_remove_desc, spec_remove },
1674 { &vop_link_desc, spec_link },
1675 { &vop_rename_desc, spec_rename },
1676 { &vop_mkdir_desc, spec_mkdir },
1677 { &vop_rmdir_desc, spec_rmdir },
1678 { &vop_symlink_desc, spec_symlink },
1679 { &vop_readdir_desc, spec_readdir },
1680 { &vop_readlink_desc, spec_readlink },
1681 { &vop_abortop_desc, spec_abortop },
1682 { &vop_inactive_desc, chfs_inactive },
1683 { &vop_reclaim_desc, chfs_reclaim },
1684 { &vop_lock_desc, genfs_lock },
1685 { &vop_unlock_desc, genfs_unlock },
1686 { &vop_bmap_desc, spec_bmap },
1687 { &vop_strategy_desc, spec_strategy },
1688 { &vop_print_desc, ufs_print },
1689 { &vop_pathconf_desc, spec_pathconf },
1690 { &vop_islocked_desc, genfs_islocked },
1691 { &vop_advlock_desc, spec_advlock },
1692 { &vop_bwrite_desc, vn_bwrite },
1693 { &vop_getpages_desc, spec_getpages },
1694 { &vop_putpages_desc, spec_putpages },
1695 { NULL, NULL } };
1696
1697 const struct vnodeopv_desc chfs_specop_opv_desc =
1698 { &chfs_specop_p, chfs_specop_entries };
1699
1700 /* --------------------------------------------------------------------- */
1701 /*
1702 * vnode operations vector used for fifos stored in a chfs file system.
1703 */
1704 int
1705 (**chfs_fifoop_p)(void *);
1706 const struct vnodeopv_entry_desc chfs_fifoop_entries[] =
1707 {
1708 { &vop_default_desc, vn_default_error },
1709 { &vop_lookup_desc, vn_fifo_bypass },
1710 { &vop_create_desc, vn_fifo_bypass },
1711 { &vop_mknod_desc, vn_fifo_bypass },
1712 { &vop_open_desc, vn_fifo_bypass },
1713 { &vop_close_desc, ufsfifo_close },
1714 { &vop_access_desc, chfs_access },
1715 { &vop_getattr_desc, chfs_getattr },
1716 { &vop_setattr_desc, chfs_setattr },
1717 { &vop_read_desc, ufsfifo_read },
1718 { &vop_write_desc, ufsfifo_write },
1719 { &vop_fallocate_desc, vn_fifo_bypass },
1720 { &vop_fdiscard_desc, vn_fifo_bypass },
1721 { &vop_ioctl_desc, vn_fifo_bypass },
1722 { &vop_fcntl_desc, genfs_fcntl },
1723 { &vop_poll_desc, vn_fifo_bypass },
1724 { &vop_kqfilter_desc, vn_fifo_bypass },
1725 { &vop_revoke_desc, vn_fifo_bypass },
1726 { &vop_mmap_desc, vn_fifo_bypass },
1727 { &vop_fsync_desc, vn_fifo_bypass },
1728 { &vop_seek_desc, vn_fifo_bypass },
1729 { &vop_remove_desc, vn_fifo_bypass },
1730 { &vop_link_desc, vn_fifo_bypass },
1731 { &vop_rename_desc, vn_fifo_bypass },
1732 { &vop_mkdir_desc, vn_fifo_bypass },
1733 { &vop_rmdir_desc, vn_fifo_bypass },
1734 { &vop_symlink_desc, vn_fifo_bypass },
1735 { &vop_readdir_desc, vn_fifo_bypass },
1736 { &vop_readlink_desc, vn_fifo_bypass },
1737 { &vop_abortop_desc, vn_fifo_bypass },
1738 { &vop_inactive_desc, chfs_inactive },
1739 { &vop_reclaim_desc, chfs_reclaim },
1740 { &vop_lock_desc, genfs_lock },
1741 { &vop_unlock_desc, genfs_unlock },
1742 { &vop_bmap_desc, vn_fifo_bypass },
1743 { &vop_strategy_desc, vn_fifo_bypass },
1744 { &vop_print_desc, ufs_print },
1745 { &vop_pathconf_desc, vn_fifo_bypass },
1746 { &vop_islocked_desc, genfs_islocked },
1747 { &vop_advlock_desc, vn_fifo_bypass },
1748 { &vop_bwrite_desc, genfs_nullop },
1749 { &vop_getpages_desc, genfs_badop },
1750 { &vop_putpages_desc, vn_fifo_bypass },
1751 { NULL, NULL } };
1752
1753 const struct vnodeopv_desc chfs_fifoop_opv_desc =
1754 { &chfs_fifoop_p, chfs_fifoop_entries };
1755