1 /* $NetBSD: sysvbfs_vnops.c,v 1.5 2006/07/01 10:12:36 martin Exp $ */ 2 3 /*- 4 * Copyright (c) 2004 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: sysvbfs_vnops.c,v 1.5 2006/07/01 10:12:36 martin Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/kernel.h> 44 #include <sys/resource.h> 45 #include <sys/vnode.h> 46 #include <sys/namei.h> 47 #include <sys/vnode.h> 48 #include <sys/dirent.h> 49 #include <sys/malloc.h> 50 #include <sys/lockf.h> 51 #include <sys/unistd.h> 52 #include <sys/fcntl.h> 53 #include <sys/kauth.h> 54 55 #include <fs/sysvbfs/sysvbfs.h> 56 #include <fs/sysvbfs/bfs.h> 57 58 #ifdef SYSVBFS_VNOPS_DEBUG 59 #define DPRINTF(fmt, args...) printf(fmt, ##args) 60 #else 61 #define DPRINTF(arg...) ((void)0) 62 #endif 63 #define ROUND_SECTOR(x) (((x) + 511) & ~511) 64 65 MALLOC_DEFINE(M_SYSVBFS_VNODE, "sysvbfs vnode", "sysvbfs vnode structures"); 66 67 int 68 sysvbfs_lookup(void *arg) 69 { 70 struct vop_lookup_args /* { 71 struct vnode *a_dvp; 72 struct vnode **a_vpp; 73 struct componentname *a_cnp; 74 } */ *a = arg; 75 struct vnode *v = a->a_dvp; 76 struct sysvbfs_node *bnode = v->v_data; 77 struct bfs *bfs = bnode->bmp->bfs; /* my filesystem */ 78 struct vnode *vpp = NULL; 79 struct bfs_dirent *dirent = NULL; 80 struct componentname *cnp = a->a_cnp; 81 int nameiop = cnp->cn_nameiop; 82 const char *name = cnp->cn_nameptr; 83 int namelen = cnp->cn_namelen; 84 int error; 85 boolean_t islastcn = cnp->cn_flags & ISLASTCN; 86 boolean_t lockparent = cnp->cn_flags & LOCKPARENT; 87 88 DPRINTF("%s: %s op=%d %ld\n", __FUNCTION__, name, nameiop, 89 cnp->cn_flags); 90 91 if ((error = VOP_ACCESS(a->a_dvp, VEXEC, cnp->cn_cred, 92 cnp->cn_lwp)) != 0) { 93 return error; /* directory permittion. */ 94 } 95 96 97 if (namelen == 1 && name[0] == '.') { /* "." */ 98 VREF(v); 99 *a->a_vpp = v; 100 } else if (cnp->cn_flags & ISDOTDOT) { /* ".." */ 101 VOP_UNLOCK(v, 0); 102 cnp->cn_flags |= PDIRUNLOCK; 103 *a->a_vpp = v; 104 if (lockparent && islastcn) { 105 if ((error = vn_lock(v, LK_EXCLUSIVE))) { 106 vput(v); 107 *a->a_vpp = NULLVP; 108 return error; 109 } 110 cnp->cn_flags &= ~PDIRUNLOCK; 111 } 112 } else { /* Regular file */ 113 if (!bfs_dirent_lookup_by_name(bfs, cnp->cn_nameptr, 114 &dirent)) { 115 if (nameiop != CREATE && nameiop != RENAME) { 116 DPRINTF("%s: no such a file. (1)\n", 117 __FUNCTION__); 118 return ENOENT; 119 } 120 if ((error = VOP_ACCESS(v, VWRITE, cnp->cn_cred, 121 cnp->cn_lwp)) != 0) 122 return error; 123 cnp->cn_flags |= SAVENAME; 124 KDASSERT(cnp->cn_flags & LOCKPARENT); 125 return EJUSTRETURN; 126 } 127 128 /* Allocate v-node */ 129 if ((error = VFS_VGET(v->v_mount, dirent->inode, &vpp)) != 0) { 130 DPRINTF("%s: can't get vnode.\n", __FUNCTION__); 131 return error; 132 } 133 *a->a_vpp = vpp; 134 if (!lockparent || !islastcn) { 135 VOP_UNLOCK(v, 0); 136 cnp->cn_flags |= PDIRUNLOCK; 137 } 138 } 139 140 if (cnp->cn_nameiop != LOOKUP && islastcn) 141 cnp->cn_flags |= SAVENAME; 142 143 return 0; 144 } 145 146 int 147 sysvbfs_create(void *arg) 148 { 149 struct vop_create_args /* { 150 struct vnode *a_dvp; 151 struct vnode **a_vpp; 152 struct componentname *a_cnp; 153 struct vattr *a_vap; 154 } */ *a = arg; 155 struct sysvbfs_node *bnode = a->a_dvp->v_data; 156 struct sysvbfs_mount *bmp = bnode->bmp; 157 struct bfs *bfs = bmp->bfs; 158 struct mount *mp = bmp->mountp; 159 struct bfs_dirent *dirent; 160 struct bfs_fileattr attr; 161 struct vattr *va = a->a_vap; 162 kauth_cred_t cr = a->a_cnp->cn_cred; 163 int err = 0; 164 165 DPRINTF("%s: %s\n", __FUNCTION__, a->a_cnp->cn_nameptr); 166 KDASSERT(a->a_vap->va_type == VREG); 167 attr.uid = kauth_cred_geteuid(cr); 168 attr.gid = kauth_cred_getegid(cr); 169 attr.mode = va->va_mode; 170 171 if ((err = bfs_file_create(bfs, a->a_cnp->cn_nameptr, 0, 0, &attr)) 172 != 0) { 173 DPRINTF("%s: bfs_file_create failed.\n", __FUNCTION__); 174 goto unlock_exit; 175 } 176 177 if (!bfs_dirent_lookup_by_name(bfs, a->a_cnp->cn_nameptr, &dirent)) 178 panic("no dirent for created file."); 179 180 if ((err = sysvbfs_vget(mp, dirent->inode, a->a_vpp)) != 0) { 181 DPRINTF("%s: sysvbfs_vget failed.\n", __FUNCTION__); 182 goto unlock_exit; 183 } 184 bnode = (*a->a_vpp)->v_data; 185 bnode->update_ctime = TRUE; 186 bnode->update_mtime = TRUE; 187 bnode->update_atime = TRUE; 188 189 unlock_exit: 190 /* unlock parent directory */ 191 vput(a->a_dvp); /* locked at sysvbfs_lookup(); */ 192 193 return err; 194 } 195 196 int 197 sysvbfs_open(void *arg) 198 { 199 struct vop_open_args /* { 200 struct vnode *a_vp; 201 int a_mode; 202 kauth_cred_t a_cred; 203 struct lwp *a_l; 204 } */ *a = arg; 205 struct vnode *v = a->a_vp; 206 struct sysvbfs_node *bnode = v->v_data; 207 struct bfs_inode *inode = bnode->inode; 208 struct bfs *bfs = bnode->bmp->bfs; 209 struct bfs_dirent *dirent; 210 211 DPRINTF("%s:\n", __FUNCTION__); 212 KDASSERT(v->v_type == VREG || v->v_type == VDIR); 213 214 if (!bfs_dirent_lookup_by_inode(bfs, inode->number, &dirent)) 215 return ENOENT; 216 bnode->update_atime = TRUE; 217 if ((a->a_mode & FWRITE) && !(a->a_mode & O_APPEND)) { 218 bnode->size = 0; 219 } else { 220 bnode->size = bfs_file_size(inode); 221 } 222 bnode->data_block = inode->start_sector; 223 224 return 0; 225 } 226 227 int 228 sysvbfs_close(void *arg) 229 { 230 struct vop_close_args /* { 231 struct vnodeop_desc *a_desc; 232 struct vnode *a_vp; 233 int a_fflag; 234 kauth_cred_t a_cred; 235 struct lwp *a_l; 236 } */ *a = arg; 237 struct vnode *v = a->a_vp; 238 struct sysvbfs_node *bnode = v->v_data; 239 struct bfs_fileattr attr; 240 241 DPRINTF("%s:\n", __FUNCTION__); 242 uvm_vnp_setsize(v, bnode->size); 243 244 memset(&attr, 0xff, sizeof attr); /* Set VNOVAL all */ 245 if (bnode->update_atime) 246 attr.atime = time_second; 247 if (bnode->update_ctime) 248 attr.ctime = time_second; 249 if (bnode->update_mtime) 250 attr.mtime = time_second; 251 bfs_inode_set_attr(bnode->bmp->bfs, bnode->inode, &attr); 252 253 VOP_FSYNC(a->a_vp, a->a_cred, FSYNC_WAIT, 0, 0, a->a_l); 254 255 return 0; 256 } 257 258 int 259 sysvbfs_access(void *arg) 260 { 261 struct vop_access_args /* { 262 struct vnode *a_vp; 263 int a_mode; 264 kauth_cred_t a_cred; 265 struct lwp *a_l; 266 } */ *ap = arg; 267 struct vnode *vp = ap->a_vp; 268 struct sysvbfs_node *bnode = vp->v_data; 269 struct bfs_fileattr *attr = &bnode->inode->attr; 270 271 DPRINTF("%s:\n", __FUNCTION__); 272 if ((ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) 273 return EROFS; 274 275 return vaccess(vp->v_type, attr->mode, attr->uid, attr->gid, 276 ap->a_mode, ap->a_cred); 277 } 278 279 int 280 sysvbfs_getattr(void *v) 281 { 282 struct vop_getattr_args /* { 283 struct vnode *a_vp; 284 struct vattr *a_vap; 285 kauth_cred_t a_cred; 286 struct lwp *a_l; 287 } */ *ap = v; 288 struct vnode *vp = ap->a_vp; 289 struct sysvbfs_node *bnode = vp->v_data; 290 struct bfs_inode *inode = bnode->inode; 291 struct bfs_fileattr *attr = &inode->attr; 292 struct sysvbfs_mount *bmp = bnode->bmp; 293 struct vattr *vap = ap->a_vap; 294 295 DPRINTF("%s:\n", __FUNCTION__); 296 297 vap->va_type = vp->v_type; 298 vap->va_mode = attr->mode; 299 vap->va_nlink = attr->nlink; 300 vap->va_uid = attr->uid; 301 vap->va_gid = attr->gid; 302 vap->va_fsid = bmp->devvp->v_rdev; 303 vap->va_fileid = inode->number; 304 vap->va_size = bfs_file_size(inode); 305 vap->va_blocksize = BFS_BSIZE; 306 vap->va_atime.tv_sec = attr->atime; 307 vap->va_mtime.tv_sec = attr->mtime; 308 vap->va_ctime.tv_sec = attr->ctime; 309 vap->va_birthtime.tv_sec = 0; 310 vap->va_gen = 1; 311 vap->va_flags = 0; 312 vap->va_rdev = 0; /* No device file */ 313 vap->va_bytes = vap->va_size; 314 vap->va_filerev = 0; 315 vap->va_vaflags = 0; 316 317 return 0; 318 } 319 320 int 321 sysvbfs_setattr(void *arg) 322 { 323 struct vop_setattr_args /* { 324 struct vnode *a_vp; 325 struct vattr *a_vap; 326 kauth_cred_t a_cred; 327 struct proc *p; 328 } */ *ap = arg; 329 struct vnode *vp = ap->a_vp; 330 struct vattr *vap = ap->a_vap; 331 struct sysvbfs_node *bnode = vp->v_data; 332 struct bfs_inode *inode = bnode->inode; 333 struct bfs_fileattr *attr = &inode->attr; 334 struct bfs *bfs = bnode->bmp->bfs; 335 336 DPRINTF("%s:\n", __FUNCTION__); 337 if (vp->v_mount->mnt_flag & MNT_RDONLY) 338 return EROFS; 339 340 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || 341 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || 342 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || 343 ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) 344 return EINVAL; 345 346 if (vap->va_uid != (uid_t)VNOVAL) 347 attr->uid = vap->va_uid; 348 if (vap->va_gid != (uid_t)VNOVAL) 349 attr->gid = vap->va_gid; 350 if (vap->va_mode != (mode_t)VNOVAL) 351 attr->mode = vap->va_mode; 352 if (vap->va_atime.tv_sec != VNOVAL) 353 attr->atime = vap->va_atime.tv_sec; 354 if (vap->va_mtime.tv_sec != VNOVAL) 355 attr->mtime = vap->va_mtime.tv_sec; 356 if (vap->va_ctime.tv_sec != VNOVAL) 357 attr->ctime = vap->va_ctime.tv_sec; 358 359 bfs_inode_set_attr(bfs, inode, attr); 360 361 return 0; 362 } 363 364 int 365 sysvbfs_read(void *arg) 366 { 367 struct vop_read_args /* { 368 struct vnode *a_vp; 369 struct uio *a_uio; 370 int a_ioflag; 371 kauth_cred_t a_cred; 372 } */ *a = arg; 373 struct vnode *v = a->a_vp; 374 struct uio *uio = a->a_uio; 375 struct sysvbfs_node *bnode = v->v_data; 376 struct bfs_inode *inode = bnode->inode; 377 vsize_t sz, filesz = bfs_file_size(inode); 378 int err; 379 void *win; 380 const int advice = IO_ADV_DECODE(a->a_ioflag); 381 382 DPRINTF("%s: type=%d\n", __FUNCTION__, v->v_type); 383 if (v->v_type != VREG) 384 return EINVAL; 385 386 while (uio->uio_resid > 0) { 387 if ((sz = MIN(filesz - uio->uio_offset, uio->uio_resid)) == 0) 388 break; 389 390 win = ubc_alloc(&v->v_uobj, uio->uio_offset, &sz, advice, 391 UBC_READ); 392 err = uiomove(win, sz, uio); 393 ubc_release(win, 0); 394 if (err) 395 break; 396 DPRINTF("%s: read %ldbyte\n", __FUNCTION__, sz); 397 } 398 399 return sysvbfs_update(v, NULL, NULL, UPDATE_WAIT); 400 } 401 402 int 403 sysvbfs_write(void *arg) 404 { 405 struct vop_write_args /* { 406 struct vnode *a_vp; 407 struct uio *a_uio; 408 int a_ioflag; 409 kauth_cred_t a_cred; 410 } */ *a = arg; 411 struct vnode *v = a->a_vp; 412 struct uio *uio = a->a_uio; 413 struct sysvbfs_node *bnode = v->v_data; 414 struct bfs_inode *inode = bnode->inode; 415 boolean_t extended = FALSE; 416 vsize_t sz; 417 void *win; 418 int err = 0; 419 420 if (a->a_vp->v_type != VREG) 421 return EISDIR; 422 423 if (a->a_ioflag & IO_APPEND) 424 uio->uio_offset = bnode->size; 425 426 if (uio->uio_resid == 0) 427 return 0; 428 429 if (bnode->size < uio->uio_offset + uio->uio_resid) { 430 bnode->size = uio->uio_offset + uio->uio_resid; 431 uvm_vnp_setsize(v, bnode->size); 432 extended = TRUE; 433 } 434 435 while (uio->uio_resid > 0) { 436 sz = uio->uio_resid; 437 win = ubc_alloc(&v->v_uobj, uio->uio_offset, &sz, 438 UVM_ADV_NORMAL, UBC_WRITE); 439 err = uiomove(win, sz, uio); 440 ubc_release(win, 0); 441 if (err) 442 break; 443 DPRINTF("%s: write %ldbyte\n", __FUNCTION__, sz); 444 } 445 inode->end_sector = bnode->data_block + 446 (ROUND_SECTOR(bnode->size) >> DEV_BSHIFT) - 1; 447 inode->eof_offset_byte = bnode->data_block * DEV_BSIZE + 448 bnode->size - 1; 449 bnode->update_mtime = TRUE; 450 451 VN_KNOTE(v, NOTE_WRITE | (extended ? NOTE_EXTEND : 0)); 452 453 return err; 454 } 455 456 int 457 sysvbfs_remove(void *arg) 458 { 459 struct vop_remove_args /* { 460 struct vnodeop_desc *a_desc; 461 struct vnode * a_dvp; 462 struct vnode * a_vp; 463 struct componentname * a_cnp; 464 } */ *ap = arg; 465 struct vnode *vp = ap->a_vp; 466 struct vnode *dvp = ap->a_dvp; 467 struct sysvbfs_node *bnode = vp->v_data; 468 struct sysvbfs_mount *bmp = bnode->bmp; 469 struct bfs *bfs = bmp->bfs; 470 int err; 471 472 DPRINTF("%s: delete %s\n", __FUNCTION__, ap->a_cnp->cn_nameptr); 473 474 if (vp->v_type == VDIR) 475 return EPERM; 476 477 if ((err = bfs_file_delete(bfs, ap->a_cnp->cn_nameptr)) != 0) 478 DPRINTF("%s: bfs_file_delete failed.\n", __FUNCTION__); 479 480 VN_KNOTE(ap->a_vp, NOTE_DELETE); 481 VN_KNOTE(ap->a_dvp, NOTE_WRITE); 482 if (dvp == vp) 483 vrele(vp); 484 else 485 vput(vp); 486 vput(dvp); 487 488 return err; 489 } 490 491 int 492 sysvbfs_rename(void *arg) 493 { 494 struct vop_rename_args /* { 495 struct vnode *a_fdvp; from parent-directory v-node 496 struct vnode *a_fvp; from file v-node 497 struct componentname *a_fcnp; 498 struct vnode *a_tdvp; to parent-directory 499 struct vnode *a_tvp; to file v-node 500 struct componentname *a_tcnp; 501 } */ *ap = arg; 502 struct vnode *fvp = ap->a_fvp; 503 struct vnode *tvp = ap->a_tvp; 504 struct sysvbfs_node *bnode = fvp->v_data; 505 struct bfs *bfs = bnode->bmp->bfs; 506 const char *from_name = ap->a_fcnp->cn_nameptr; 507 const char *to_name = ap->a_tcnp->cn_nameptr; 508 int error; 509 510 DPRINTF("%s: %s->%s\n", __FUNCTION__, from_name, to_name); 511 if ((fvp->v_mount != ap->a_tdvp->v_mount) || 512 (tvp && (fvp->v_mount != tvp->v_mount))) { 513 error = EXDEV; 514 printf("cross-device link\n"); 515 goto out; 516 } 517 518 KDASSERT(fvp->v_type == VREG); 519 KDASSERT(tvp == NULL ? TRUE : tvp->v_type == VREG); 520 521 error = bfs_file_rename(bfs, from_name, to_name); 522 out: 523 vput(ap->a_tdvp); 524 if (ap->a_tdvp != ap->a_fdvp) 525 vrele(ap->a_fdvp); 526 vrele(ap->a_fvp); /* unlocked and refcnt is incremented on entry. */ 527 if (tvp) 528 vput(ap->a_tvp); /* locked on entry */ 529 530 return 0; 531 } 532 533 int 534 sysvbfs_readdir(void *v) 535 { 536 struct vop_readdir_args /* { 537 struct vnode *a_vp; 538 struct uio *a_uio; 539 kauth_cred_t a_cred; 540 int *a_eofflag; 541 off_t **a_cookies; 542 int *a_ncookies; 543 } */ *ap = v; 544 struct uio *uio = ap->a_uio; 545 struct vnode *vp = ap->a_vp; 546 struct sysvbfs_node *bnode = vp->v_data; 547 struct bfs *bfs = bnode->bmp->bfs; 548 struct dirent d; 549 struct bfs_dirent *file; 550 int i, n, error; 551 552 DPRINTF("%s: offset=%lld residue=%d\n", __FUNCTION__, 553 uio->uio_offset, uio->uio_resid); 554 555 KDASSERT(vp->v_type == VDIR); 556 KDASSERT(uio->uio_offset >= 0); 557 558 i = uio->uio_offset / sizeof(struct dirent); 559 n = uio->uio_resid / sizeof(struct dirent); 560 if ((i + n) > bfs->n_dirent) 561 n = bfs->n_dirent - i; 562 563 for (file = &bfs->dirent[i]; i < n; file++) { 564 if (file->inode == 0) 565 continue; 566 if (i == bfs->max_dirent) { 567 DPRINTF("%s: file system inconsistent.\n", 568 __FUNCTION__); 569 break; 570 } 571 i++; 572 memset(&d, 0, sizeof d); 573 d.d_fileno = file->inode; 574 d.d_type = file->inode == BFS_ROOT_INODE ? DT_DIR : DT_REG; 575 d.d_namlen = strlen(file->name); 576 strncpy(d.d_name, file->name, BFS_FILENAME_MAXLEN); 577 d.d_reclen = sizeof(struct dirent); 578 if ((error = uiomove(&d, d.d_reclen, uio)) != 0) { 579 DPRINTF("%s: uiomove failed.\n", __FUNCTION__); 580 return error; 581 } 582 } 583 DPRINTF("%s: %d %d %d\n", __FUNCTION__, i, n, bfs->n_dirent); 584 *ap->a_eofflag = i == bfs->n_dirent; 585 586 return 0; 587 } 588 589 int 590 sysvbfs_inactive(void *arg) 591 { 592 struct vop_inactive_args /* { 593 struct vnode *a_vp; 594 struct lwp *a_l; 595 } */ *a = arg; 596 struct vnode *v = a->a_vp; 597 struct lwp *l = a->a_l; 598 599 DPRINTF("%s:\n", __FUNCTION__); 600 VOP_UNLOCK(v, 0); 601 vrecycle(v, NULL, l); 602 603 return 0; 604 } 605 606 int 607 sysvbfs_reclaim(void *v) 608 { 609 extern struct pool sysvbfs_node_pool; 610 struct vop_reclaim_args /* { 611 struct vnode *a_vp; 612 } */ *ap = v; 613 struct vnode *vp = ap->a_vp; 614 struct sysvbfs_node *bnode = vp->v_data; 615 616 DPRINTF("%s:\n", __FUNCTION__); 617 simple_lock(&mntvnode_slock); 618 LIST_REMOVE(bnode, link); 619 simple_unlock(&mntvnode_slock); 620 cache_purge(vp); 621 pool_put(&sysvbfs_node_pool, bnode); 622 vp->v_data = NULL; 623 624 return 0; 625 } 626 627 int 628 sysvbfs_bmap(void *arg) 629 { 630 struct vop_bmap_args /* { 631 struct vnode *a_vp; 632 daddr_t a_bn; 633 struct vnode **a_vpp; 634 daddr_t *a_bnp; 635 int *a_runp; 636 } */ *a = arg; 637 struct vnode *v = a->a_vp; 638 struct sysvbfs_node *bnode = v->v_data; 639 struct sysvbfs_mount *bmp = bnode->bmp; 640 struct bfs_inode *inode = bnode->inode; 641 daddr_t blk; 642 643 DPRINTF("%s:\n", __FUNCTION__); 644 /* BFS algorythm is contiguous allocation */ 645 blk = inode->start_sector + a->a_bn; 646 647 if (blk * BFS_BSIZE > bmp->bfs->data_end) 648 return ENOSPC; 649 650 *a->a_vpp = bmp->devvp; 651 *a->a_runp = 0; 652 DPRINTF("%s: %d + %lld\n", __FUNCTION__, inode->start_sector, a->a_bn); 653 654 *a->a_bnp = blk; 655 656 657 return 0; 658 } 659 660 int 661 sysvbfs_strategy(void *arg) 662 { 663 struct vop_strategy_args /* { 664 struct vnode *a_vp; 665 struct buf *a_bp; 666 } */ *a = arg; 667 struct buf *b = a->a_bp; 668 struct vnode *v = a->a_vp; 669 struct sysvbfs_node *bnode = v->v_data; 670 struct sysvbfs_mount *bmp = bnode->bmp; 671 int error; 672 673 DPRINTF("%s:\n", __FUNCTION__); 674 KDASSERT(v->v_type == VREG); 675 if (b->b_blkno == b->b_lblkno) { 676 error = VOP_BMAP(v, b->b_lblkno, NULL, &b->b_blkno, NULL); 677 if (error) { 678 b->b_error = error; 679 b->b_flags |= B_ERROR; 680 biodone(b); 681 return error; 682 } 683 if ((long)b->b_blkno == -1) 684 clrbuf(b); 685 } 686 if ((long)b->b_blkno == -1) { 687 biodone(b); 688 return 0; 689 } 690 691 return VOP_STRATEGY(bmp->devvp, b); 692 } 693 694 int 695 sysvbfs_print(void *v) 696 { 697 struct vop_print_args /* { 698 struct vnode *a_vp; 699 } */ *ap = v; 700 struct sysvbfs_node *bnode = ap->a_vp->v_data; 701 702 DPRINTF("%s:\n", __FUNCTION__); 703 bfs_dump(bnode->bmp->bfs); 704 705 return 0; 706 } 707 708 int 709 sysvbfs_advlock(void *v) 710 { 711 struct vop_advlock_args /* { 712 struct vnode *a_vp; 713 void *a_id; 714 int a_op; 715 struct flock *a_fl; 716 int a_flags; 717 } */ *ap = v; 718 struct sysvbfs_node *bnode = ap->a_vp->v_data; 719 720 DPRINTF("%s: op=%d\n", __FUNCTION__, ap->a_op); 721 722 return lf_advlock(ap, &bnode->lockf, bfs_file_size(bnode->inode)); 723 } 724 725 int 726 sysvbfs_pathconf(void *v) 727 { 728 struct vop_pathconf_args /* { 729 struct vnode *a_vp; 730 int a_name; 731 register_t *a_retval; 732 } */ *ap = v; 733 int err = 0; 734 735 DPRINTF("%s:\n", __FUNCTION__); 736 737 switch (ap->a_name) { 738 case _PC_LINK_MAX: 739 *ap->a_retval = 1; 740 break;; 741 case _PC_NAME_MAX: 742 *ap->a_retval = BFS_FILENAME_MAXLEN; 743 break;; 744 case _PC_PATH_MAX: 745 *ap->a_retval = BFS_FILENAME_MAXLEN; 746 break;; 747 case _PC_CHOWN_RESTRICTED: 748 *ap->a_retval = 1; 749 break;; 750 case _PC_NO_TRUNC: 751 *ap->a_retval = 0; 752 break;; 753 case _PC_SYNC_IO: 754 *ap->a_retval = 1; 755 break;; 756 case _PC_FILESIZEBITS: 757 *ap->a_retval = 32; 758 break;; 759 default: 760 err = EINVAL; 761 break; 762 } 763 764 return err; 765 } 766 767 int 768 sysvbfs_fsync(void *v) 769 { 770 struct vop_fsync_args /* { 771 struct vnode *a_vp; 772 kauth_cred_t a_cred; 773 int a_flags; 774 off_t offlo; 775 off_t offhi; 776 struct lwp *a_l; 777 } */ *ap = v; 778 struct vnode *vp = ap->a_vp; 779 int error, wait; 780 781 if (ap->a_flags & FSYNC_CACHE) { 782 return EOPNOTSUPP; 783 } 784 785 wait = (ap->a_flags & FSYNC_WAIT) != 0; 786 vflushbuf(vp, wait); 787 788 if ((ap->a_flags & FSYNC_DATAONLY) != 0) 789 error = 0; 790 else 791 error = sysvbfs_update(vp, NULL, NULL, wait ? UPDATE_WAIT : 0); 792 793 return error; 794 } 795 796 int 797 sysvbfs_update(struct vnode *vp, const struct timespec *acc, 798 const struct timespec *mod, int flags) 799 { 800 struct sysvbfs_node *bnode = vp->v_data; 801 struct bfs_fileattr attr; 802 803 DPRINTF("%s:\n", __FUNCTION__); 804 memset(&attr, 0xff, sizeof attr); /* Set VNOVAL all */ 805 if (bnode->update_atime) { 806 attr.atime = acc ? acc->tv_sec : time_second; 807 bnode->update_atime = FALSE; 808 } 809 if (bnode->update_ctime) { 810 attr.ctime = time_second; 811 bnode->update_ctime = FALSE; 812 } 813 if (bnode->update_mtime) { 814 attr.mtime = mod ? mod->tv_sec : time_second; 815 bnode->update_mtime = FALSE; 816 } 817 bfs_inode_set_attr(bnode->bmp->bfs, bnode->inode, &attr); 818 819 return 0; 820 } 821