sysvbfs_vnops.c revision 1.4 1 /* $NetBSD: sysvbfs_vnops.c,v 1.4 2006/07/01 08:42:39 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.4 2006/07/01 08:42:39 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 struct timespec ts;
241
242 DPRINTF("%s:\n", __FUNCTION__);
243 uvm_vnp_setsize(v, bnode->size);
244
245 memset(&attr, 0xff, sizeof attr); /* Set VNOVAL all */
246 getnanotime(&ts);
247 if (bnode->update_atime)
248 attr.atime = ts.tv_sec;
249 if (bnode->update_ctime)
250 attr.ctime = ts.tv_sec;
251 if (bnode->update_mtime)
252 attr.mtime = ts.tv_sec;
253 bfs_inode_set_attr(bnode->bmp->bfs, bnode->inode, &attr);
254
255 VOP_FSYNC(a->a_vp, a->a_cred, FSYNC_WAIT, 0, 0, a->a_l);
256
257 return 0;
258 }
259
260 int
261 sysvbfs_access(void *arg)
262 {
263 struct vop_access_args /* {
264 struct vnode *a_vp;
265 int a_mode;
266 kauth_cred_t a_cred;
267 struct lwp *a_l;
268 } */ *ap = arg;
269 struct vnode *vp = ap->a_vp;
270 struct sysvbfs_node *bnode = vp->v_data;
271 struct bfs_fileattr *attr = &bnode->inode->attr;
272
273 DPRINTF("%s:\n", __FUNCTION__);
274 if ((ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY))
275 return EROFS;
276
277 return vaccess(vp->v_type, attr->mode, attr->uid, attr->gid,
278 ap->a_mode, ap->a_cred);
279 }
280
281 int
282 sysvbfs_getattr(void *v)
283 {
284 struct vop_getattr_args /* {
285 struct vnode *a_vp;
286 struct vattr *a_vap;
287 kauth_cred_t a_cred;
288 struct lwp *a_l;
289 } */ *ap = v;
290 struct vnode *vp = ap->a_vp;
291 struct sysvbfs_node *bnode = vp->v_data;
292 struct bfs_inode *inode = bnode->inode;
293 struct bfs_fileattr *attr = &inode->attr;
294 struct sysvbfs_mount *bmp = bnode->bmp;
295 struct vattr *vap = ap->a_vap;
296
297 DPRINTF("%s:\n", __FUNCTION__);
298
299 vap->va_type = vp->v_type;
300 vap->va_mode = attr->mode;
301 vap->va_nlink = attr->nlink;
302 vap->va_uid = attr->uid;
303 vap->va_gid = attr->gid;
304 vap->va_fsid = bmp->devvp->v_rdev;
305 vap->va_fileid = inode->number;
306 vap->va_size = bfs_file_size(inode);
307 vap->va_blocksize = BFS_BSIZE;
308 vap->va_atime.tv_sec = attr->atime;
309 vap->va_mtime.tv_sec = attr->mtime;
310 vap->va_ctime.tv_sec = attr->ctime;
311 vap->va_birthtime.tv_sec = 0;
312 vap->va_gen = 1;
313 vap->va_flags = 0;
314 vap->va_rdev = 0; /* No device file */
315 vap->va_bytes = vap->va_size;
316 vap->va_filerev = 0;
317 vap->va_vaflags = 0;
318
319 return 0;
320 }
321
322 int
323 sysvbfs_setattr(void *arg)
324 {
325 struct vop_setattr_args /* {
326 struct vnode *a_vp;
327 struct vattr *a_vap;
328 kauth_cred_t a_cred;
329 struct proc *p;
330 } */ *ap = arg;
331 struct vnode *vp = ap->a_vp;
332 struct vattr *vap = ap->a_vap;
333 struct sysvbfs_node *bnode = vp->v_data;
334 struct bfs_inode *inode = bnode->inode;
335 struct bfs_fileattr *attr = &inode->attr;
336 struct bfs *bfs = bnode->bmp->bfs;
337
338 DPRINTF("%s:\n", __FUNCTION__);
339 if (vp->v_mount->mnt_flag & MNT_RDONLY)
340 return EROFS;
341
342 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
343 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
344 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
345 ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL))
346 return EINVAL;
347
348 if (vap->va_uid != (uid_t)VNOVAL)
349 attr->uid = vap->va_uid;
350 if (vap->va_gid != (uid_t)VNOVAL)
351 attr->gid = vap->va_gid;
352 if (vap->va_mode != (mode_t)VNOVAL)
353 attr->mode = vap->va_mode;
354 if (vap->va_atime.tv_sec != VNOVAL)
355 attr->atime = vap->va_atime.tv_sec;
356 if (vap->va_mtime.tv_sec != VNOVAL)
357 attr->mtime = vap->va_mtime.tv_sec;
358 if (vap->va_ctime.tv_sec != VNOVAL)
359 attr->ctime = vap->va_ctime.tv_sec;
360
361 bfs_inode_set_attr(bfs, inode, attr);
362
363 return 0;
364 }
365
366 int
367 sysvbfs_read(void *arg)
368 {
369 struct vop_read_args /* {
370 struct vnode *a_vp;
371 struct uio *a_uio;
372 int a_ioflag;
373 kauth_cred_t a_cred;
374 } */ *a = arg;
375 struct vnode *v = a->a_vp;
376 struct uio *uio = a->a_uio;
377 struct sysvbfs_node *bnode = v->v_data;
378 struct bfs_inode *inode = bnode->inode;
379 vsize_t sz, filesz = bfs_file_size(inode);
380 int err;
381 void *win;
382 const int advice = IO_ADV_DECODE(a->a_ioflag);
383
384 DPRINTF("%s: type=%d\n", __FUNCTION__, v->v_type);
385 if (v->v_type != VREG)
386 return EINVAL;
387
388 while (uio->uio_resid > 0) {
389 if ((sz = MIN(filesz - uio->uio_offset, uio->uio_resid)) == 0)
390 break;
391
392 win = ubc_alloc(&v->v_uobj, uio->uio_offset, &sz, advice,
393 UBC_READ);
394 err = uiomove(win, sz, uio);
395 ubc_release(win, 0);
396 if (err)
397 break;
398 DPRINTF("%s: read %ldbyte\n", __FUNCTION__, sz);
399 }
400
401 return sysvbfs_update(v, NULL, NULL, UPDATE_WAIT);
402 }
403
404 int
405 sysvbfs_write(void *arg)
406 {
407 struct vop_write_args /* {
408 struct vnode *a_vp;
409 struct uio *a_uio;
410 int a_ioflag;
411 kauth_cred_t a_cred;
412 } */ *a = arg;
413 struct vnode *v = a->a_vp;
414 struct uio *uio = a->a_uio;
415 struct sysvbfs_node *bnode = v->v_data;
416 struct bfs_inode *inode = bnode->inode;
417 boolean_t extended = FALSE;
418 vsize_t sz;
419 void *win;
420 int err = 0;
421
422 if (a->a_vp->v_type != VREG)
423 return EISDIR;
424
425 if (a->a_ioflag & IO_APPEND)
426 uio->uio_offset = bnode->size;
427
428 if (uio->uio_resid == 0)
429 return 0;
430
431 if (bnode->size < uio->uio_offset + uio->uio_resid) {
432 bnode->size = uio->uio_offset + uio->uio_resid;
433 uvm_vnp_setsize(v, bnode->size);
434 extended = TRUE;
435 }
436
437 while (uio->uio_resid > 0) {
438 sz = uio->uio_resid;
439 win = ubc_alloc(&v->v_uobj, uio->uio_offset, &sz,
440 UVM_ADV_NORMAL, UBC_WRITE);
441 err = uiomove(win, sz, uio);
442 ubc_release(win, 0);
443 if (err)
444 break;
445 DPRINTF("%s: write %ldbyte\n", __FUNCTION__, sz);
446 }
447 inode->end_sector = bnode->data_block +
448 (ROUND_SECTOR(bnode->size) >> DEV_BSHIFT) - 1;
449 inode->eof_offset_byte = bnode->data_block * DEV_BSIZE +
450 bnode->size - 1;
451 bnode->update_mtime = TRUE;
452
453 VN_KNOTE(v, NOTE_WRITE | (extended ? NOTE_EXTEND : 0));
454
455 return err;
456 }
457
458 int
459 sysvbfs_remove(void *arg)
460 {
461 struct vop_remove_args /* {
462 struct vnodeop_desc *a_desc;
463 struct vnode * a_dvp;
464 struct vnode * a_vp;
465 struct componentname * a_cnp;
466 } */ *ap = arg;
467 struct vnode *vp = ap->a_vp;
468 struct vnode *dvp = ap->a_dvp;
469 struct sysvbfs_node *bnode = vp->v_data;
470 struct sysvbfs_mount *bmp = bnode->bmp;
471 struct bfs *bfs = bmp->bfs;
472 int err;
473
474 DPRINTF("%s: delete %s\n", __FUNCTION__, ap->a_cnp->cn_nameptr);
475
476 if (vp->v_type == VDIR)
477 return EPERM;
478
479 if ((err = bfs_file_delete(bfs, ap->a_cnp->cn_nameptr)) != 0)
480 DPRINTF("%s: bfs_file_delete failed.\n", __FUNCTION__);
481
482 VN_KNOTE(ap->a_vp, NOTE_DELETE);
483 VN_KNOTE(ap->a_dvp, NOTE_WRITE);
484 if (dvp == vp)
485 vrele(vp);
486 else
487 vput(vp);
488 vput(dvp);
489
490 return err;
491 }
492
493 int
494 sysvbfs_rename(void *arg)
495 {
496 struct vop_rename_args /* {
497 struct vnode *a_fdvp; from parent-directory v-node
498 struct vnode *a_fvp; from file v-node
499 struct componentname *a_fcnp;
500 struct vnode *a_tdvp; to parent-directory
501 struct vnode *a_tvp; to file v-node
502 struct componentname *a_tcnp;
503 } */ *ap = arg;
504 struct vnode *fvp = ap->a_fvp;
505 struct vnode *tvp = ap->a_tvp;
506 struct sysvbfs_node *bnode = fvp->v_data;
507 struct bfs *bfs = bnode->bmp->bfs;
508 const char *from_name = ap->a_fcnp->cn_nameptr;
509 const char *to_name = ap->a_tcnp->cn_nameptr;
510 int error;
511
512 DPRINTF("%s: %s->%s\n", __FUNCTION__, from_name, to_name);
513 if ((fvp->v_mount != ap->a_tdvp->v_mount) ||
514 (tvp && (fvp->v_mount != tvp->v_mount))) {
515 error = EXDEV;
516 printf("cross-device link\n");
517 goto out;
518 }
519
520 KDASSERT(fvp->v_type == VREG);
521 KDASSERT(tvp == NULL ? TRUE : tvp->v_type == VREG);
522
523 error = bfs_file_rename(bfs, from_name, to_name);
524 out:
525 vput(ap->a_tdvp);
526 if (ap->a_tdvp != ap->a_fdvp)
527 vrele(ap->a_fdvp);
528 vrele(ap->a_fvp); /* unlocked and refcnt is incremented on entry. */
529 if (tvp)
530 vput(ap->a_tvp); /* locked on entry */
531
532 return 0;
533 }
534
535 int
536 sysvbfs_readdir(void *v)
537 {
538 struct vop_readdir_args /* {
539 struct vnode *a_vp;
540 struct uio *a_uio;
541 kauth_cred_t a_cred;
542 int *a_eofflag;
543 off_t **a_cookies;
544 int *a_ncookies;
545 } */ *ap = v;
546 struct uio *uio = ap->a_uio;
547 struct vnode *vp = ap->a_vp;
548 struct sysvbfs_node *bnode = vp->v_data;
549 struct bfs *bfs = bnode->bmp->bfs;
550 struct dirent d;
551 struct bfs_dirent *file;
552 int i, n, error;
553
554 DPRINTF("%s: offset=%lld residue=%d\n", __FUNCTION__,
555 uio->uio_offset, uio->uio_resid);
556
557 KDASSERT(vp->v_type == VDIR);
558 KDASSERT(uio->uio_offset >= 0);
559
560 i = uio->uio_offset / sizeof(struct dirent);
561 n = uio->uio_resid / sizeof(struct dirent);
562 if ((i + n) > bfs->n_dirent)
563 n = bfs->n_dirent - i;
564
565 for (file = &bfs->dirent[i]; i < n; file++) {
566 if (file->inode == 0)
567 continue;
568 if (i == bfs->max_dirent) {
569 DPRINTF("%s: file system inconsistent.\n",
570 __FUNCTION__);
571 break;
572 }
573 i++;
574 memset(&d, 0, sizeof d);
575 d.d_fileno = file->inode;
576 d.d_type = file->inode == BFS_ROOT_INODE ? DT_DIR : DT_REG;
577 d.d_namlen = strlen(file->name);
578 strncpy(d.d_name, file->name, BFS_FILENAME_MAXLEN);
579 d.d_reclen = sizeof(struct dirent);
580 if ((error = uiomove(&d, d.d_reclen, uio)) != 0) {
581 DPRINTF("%s: uiomove failed.\n", __FUNCTION__);
582 return error;
583 }
584 }
585 DPRINTF("%s: %d %d %d\n", __FUNCTION__, i, n, bfs->n_dirent);
586 *ap->a_eofflag = i == bfs->n_dirent;
587
588 return 0;
589 }
590
591 int
592 sysvbfs_inactive(void *arg)
593 {
594 struct vop_inactive_args /* {
595 struct vnode *a_vp;
596 struct lwp *a_l;
597 } */ *a = arg;
598 struct vnode *v = a->a_vp;
599 struct lwp *l = a->a_l;
600
601 DPRINTF("%s:\n", __FUNCTION__);
602 VOP_UNLOCK(v, 0);
603 vrecycle(v, NULL, l);
604
605 return 0;
606 }
607
608 int
609 sysvbfs_reclaim(void *v)
610 {
611 extern struct pool sysvbfs_node_pool;
612 struct vop_reclaim_args /* {
613 struct vnode *a_vp;
614 } */ *ap = v;
615 struct vnode *vp = ap->a_vp;
616 struct sysvbfs_node *bnode = vp->v_data;
617
618 DPRINTF("%s:\n", __FUNCTION__);
619 simple_lock(&mntvnode_slock);
620 LIST_REMOVE(bnode, link);
621 simple_unlock(&mntvnode_slock);
622 cache_purge(vp);
623 pool_put(&sysvbfs_node_pool, bnode);
624 vp->v_data = NULL;
625
626 return 0;
627 }
628
629 int
630 sysvbfs_bmap(void *arg)
631 {
632 struct vop_bmap_args /* {
633 struct vnode *a_vp;
634 daddr_t a_bn;
635 struct vnode **a_vpp;
636 daddr_t *a_bnp;
637 int *a_runp;
638 } */ *a = arg;
639 struct vnode *v = a->a_vp;
640 struct sysvbfs_node *bnode = v->v_data;
641 struct sysvbfs_mount *bmp = bnode->bmp;
642 struct bfs_inode *inode = bnode->inode;
643 daddr_t blk;
644
645 DPRINTF("%s:\n", __FUNCTION__);
646 /* BFS algorythm is contiguous allocation */
647 blk = inode->start_sector + a->a_bn;
648
649 if (blk * BFS_BSIZE > bmp->bfs->data_end)
650 return ENOSPC;
651
652 *a->a_vpp = bmp->devvp;
653 *a->a_runp = 0;
654 DPRINTF("%s: %d + %lld\n", __FUNCTION__, inode->start_sector, a->a_bn);
655
656 *a->a_bnp = blk;
657
658
659 return 0;
660 }
661
662 int
663 sysvbfs_strategy(void *arg)
664 {
665 struct vop_strategy_args /* {
666 struct vnode *a_vp;
667 struct buf *a_bp;
668 } */ *a = arg;
669 struct buf *b = a->a_bp;
670 struct vnode *v = a->a_vp;
671 struct sysvbfs_node *bnode = v->v_data;
672 struct sysvbfs_mount *bmp = bnode->bmp;
673 int error;
674
675 DPRINTF("%s:\n", __FUNCTION__);
676 KDASSERT(v->v_type == VREG);
677 if (b->b_blkno == b->b_lblkno) {
678 error = VOP_BMAP(v, b->b_lblkno, NULL, &b->b_blkno, NULL);
679 if (error) {
680 b->b_error = error;
681 b->b_flags |= B_ERROR;
682 biodone(b);
683 return error;
684 }
685 if ((long)b->b_blkno == -1)
686 clrbuf(b);
687 }
688 if ((long)b->b_blkno == -1) {
689 biodone(b);
690 return 0;
691 }
692
693 return VOP_STRATEGY(bmp->devvp, b);
694 }
695
696 int
697 sysvbfs_print(void *v)
698 {
699 struct vop_print_args /* {
700 struct vnode *a_vp;
701 } */ *ap = v;
702 struct sysvbfs_node *bnode = ap->a_vp->v_data;
703
704 DPRINTF("%s:\n", __FUNCTION__);
705 bfs_dump(bnode->bmp->bfs);
706
707 return 0;
708 }
709
710 int
711 sysvbfs_advlock(void *v)
712 {
713 struct vop_advlock_args /* {
714 struct vnode *a_vp;
715 void *a_id;
716 int a_op;
717 struct flock *a_fl;
718 int a_flags;
719 } */ *ap = v;
720 struct sysvbfs_node *bnode = ap->a_vp->v_data;
721
722 DPRINTF("%s: op=%d\n", __FUNCTION__, ap->a_op);
723
724 return lf_advlock(ap, &bnode->lockf, bfs_file_size(bnode->inode));
725 }
726
727 int
728 sysvbfs_pathconf(void *v)
729 {
730 struct vop_pathconf_args /* {
731 struct vnode *a_vp;
732 int a_name;
733 register_t *a_retval;
734 } */ *ap = v;
735 int err = 0;
736
737 DPRINTF("%s:\n", __FUNCTION__);
738
739 switch (ap->a_name) {
740 case _PC_LINK_MAX:
741 *ap->a_retval = 1;
742 break;;
743 case _PC_NAME_MAX:
744 *ap->a_retval = BFS_FILENAME_MAXLEN;
745 break;;
746 case _PC_PATH_MAX:
747 *ap->a_retval = BFS_FILENAME_MAXLEN;
748 break;;
749 case _PC_CHOWN_RESTRICTED:
750 *ap->a_retval = 1;
751 break;;
752 case _PC_NO_TRUNC:
753 *ap->a_retval = 0;
754 break;;
755 case _PC_SYNC_IO:
756 *ap->a_retval = 1;
757 break;;
758 case _PC_FILESIZEBITS:
759 *ap->a_retval = 32;
760 break;;
761 default:
762 err = EINVAL;
763 break;
764 }
765
766 return err;
767 }
768
769 int
770 sysvbfs_fsync(void *v)
771 {
772 struct vop_fsync_args /* {
773 struct vnode *a_vp;
774 kauth_cred_t a_cred;
775 int a_flags;
776 off_t offlo;
777 off_t offhi;
778 struct lwp *a_l;
779 } */ *ap = v;
780 struct vnode *vp = ap->a_vp;
781 int error, wait;
782
783 if (ap->a_flags & FSYNC_CACHE) {
784 return EOPNOTSUPP;
785 }
786
787 wait = (ap->a_flags & FSYNC_WAIT) != 0;
788 vflushbuf(vp, wait);
789
790 if ((ap->a_flags & FSYNC_DATAONLY) != 0)
791 error = 0;
792 else
793 error = sysvbfs_update(vp, NULL, NULL, wait ? UPDATE_WAIT : 0);
794
795 return error;
796 }
797
798 int
799 sysvbfs_update(struct vnode *vp, const struct timespec *acc,
800 const struct timespec *mod, int flags)
801 {
802 struct sysvbfs_node *bnode = vp->v_data;
803 struct bfs_fileattr attr;
804 struct timespec ts;
805
806 DPRINTF("%s:\n", __FUNCTION__);
807 memset(&attr, 0xff, sizeof attr); /* Set VNOVAL all */
808 getnanotime(&ts);
809 if (bnode->update_atime) {
810 attr.atime = acc ? acc->tv_sec : ts.tv_sec;
811 bnode->update_atime = FALSE;
812 }
813 if (bnode->update_ctime) {
814 attr.ctime = ts.tv_sec;
815 bnode->update_ctime = FALSE;
816 }
817 if (bnode->update_mtime) {
818 attr.mtime = mod ? mod->tv_sec : ts.tv_sec;
819 bnode->update_mtime = FALSE;
820 }
821 bfs_inode_set_attr(bnode->bmp->bfs, bnode->inode, &attr);
822
823 return 0;
824 }
825