ffs_vnops.c revision 1.98 1 /* $NetBSD: ffs_vnops.c,v 1.98 2008/01/30 09:50:25 ad Exp $ */
2
3 /*
4 * Copyright (c) 1982, 1986, 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * @(#)ffs_vnops.c 8.15 (Berkeley) 5/14/95
32 */
33
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.98 2008/01/30 09:50:25 ad Exp $");
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/resourcevar.h>
40 #include <sys/kernel.h>
41 #include <sys/file.h>
42 #include <sys/stat.h>
43 #include <sys/buf.h>
44 #include <sys/event.h>
45 #include <sys/proc.h>
46 #include <sys/mount.h>
47 #include <sys/vnode.h>
48 #include <sys/pool.h>
49 #include <sys/signalvar.h>
50 #include <sys/kauth.h>
51 #include <sys/fstrans.h>
52
53 #include <miscfs/fifofs/fifo.h>
54 #include <miscfs/genfs/genfs.h>
55 #include <miscfs/specfs/specdev.h>
56
57 #include <ufs/ufs/inode.h>
58 #include <ufs/ufs/dir.h>
59 #include <ufs/ufs/ufs_extern.h>
60 #include <ufs/ufs/ufsmount.h>
61
62 #include <ufs/ffs/fs.h>
63 #include <ufs/ffs/ffs_extern.h>
64
65 #include <uvm/uvm.h>
66
67 /* Global vfs data structures for ufs. */
68 int (**ffs_vnodeop_p)(void *);
69 const struct vnodeopv_entry_desc ffs_vnodeop_entries[] = {
70 { &vop_default_desc, vn_default_error },
71 { &vop_lookup_desc, ufs_lookup }, /* lookup */
72 { &vop_create_desc, ufs_create }, /* create */
73 { &vop_whiteout_desc, ufs_whiteout }, /* whiteout */
74 { &vop_mknod_desc, ufs_mknod }, /* mknod */
75 { &vop_open_desc, ufs_open }, /* open */
76 { &vop_close_desc, ufs_close }, /* close */
77 { &vop_access_desc, ufs_access }, /* access */
78 { &vop_getattr_desc, ufs_getattr }, /* getattr */
79 { &vop_setattr_desc, ufs_setattr }, /* setattr */
80 { &vop_read_desc, ffs_read }, /* read */
81 { &vop_write_desc, ffs_write }, /* write */
82 { &vop_ioctl_desc, ufs_ioctl }, /* ioctl */
83 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */
84 { &vop_poll_desc, ufs_poll }, /* poll */
85 { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */
86 { &vop_revoke_desc, ufs_revoke }, /* revoke */
87 { &vop_mmap_desc, ufs_mmap }, /* mmap */
88 { &vop_fsync_desc, ffs_fsync }, /* fsync */
89 { &vop_seek_desc, ufs_seek }, /* seek */
90 { &vop_remove_desc, ufs_remove }, /* remove */
91 { &vop_link_desc, ufs_link }, /* link */
92 { &vop_rename_desc, ufs_rename }, /* rename */
93 { &vop_mkdir_desc, ufs_mkdir }, /* mkdir */
94 { &vop_rmdir_desc, ufs_rmdir }, /* rmdir */
95 { &vop_symlink_desc, ufs_symlink }, /* symlink */
96 { &vop_readdir_desc, ufs_readdir }, /* readdir */
97 { &vop_readlink_desc, ufs_readlink }, /* readlink */
98 { &vop_abortop_desc, ufs_abortop }, /* abortop */
99 { &vop_inactive_desc, ufs_inactive }, /* inactive */
100 { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */
101 { &vop_lock_desc, ffs_lock }, /* lock */
102 { &vop_unlock_desc, ffs_unlock }, /* unlock */
103 { &vop_bmap_desc, ufs_bmap }, /* bmap */
104 { &vop_strategy_desc, ufs_strategy }, /* strategy */
105 { &vop_print_desc, ufs_print }, /* print */
106 { &vop_islocked_desc, ffs_islocked }, /* islocked */
107 { &vop_pathconf_desc, ufs_pathconf }, /* pathconf */
108 { &vop_advlock_desc, ufs_advlock }, /* advlock */
109 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
110 { &vop_getpages_desc, genfs_getpages }, /* getpages */
111 { &vop_putpages_desc, genfs_putpages }, /* putpages */
112 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */
113 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */
114 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */
115 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */
116 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */
117 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */
118 { NULL, NULL }
119 };
120 const struct vnodeopv_desc ffs_vnodeop_opv_desc =
121 { &ffs_vnodeop_p, ffs_vnodeop_entries };
122
123 int (**ffs_specop_p)(void *);
124 const struct vnodeopv_entry_desc ffs_specop_entries[] = {
125 { &vop_default_desc, vn_default_error },
126 { &vop_lookup_desc, spec_lookup }, /* lookup */
127 { &vop_create_desc, spec_create }, /* create */
128 { &vop_mknod_desc, spec_mknod }, /* mknod */
129 { &vop_open_desc, spec_open }, /* open */
130 { &vop_close_desc, ufsspec_close }, /* close */
131 { &vop_access_desc, ufs_access }, /* access */
132 { &vop_getattr_desc, ufs_getattr }, /* getattr */
133 { &vop_setattr_desc, ufs_setattr }, /* setattr */
134 { &vop_read_desc, ufsspec_read }, /* read */
135 { &vop_write_desc, ufsspec_write }, /* write */
136 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */
137 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */
138 { &vop_poll_desc, spec_poll }, /* poll */
139 { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */
140 { &vop_revoke_desc, spec_revoke }, /* revoke */
141 { &vop_mmap_desc, spec_mmap }, /* mmap */
142 { &vop_fsync_desc, ffs_fsync }, /* fsync */
143 { &vop_seek_desc, spec_seek }, /* seek */
144 { &vop_remove_desc, spec_remove }, /* remove */
145 { &vop_link_desc, spec_link }, /* link */
146 { &vop_rename_desc, spec_rename }, /* rename */
147 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */
148 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */
149 { &vop_symlink_desc, spec_symlink }, /* symlink */
150 { &vop_readdir_desc, spec_readdir }, /* readdir */
151 { &vop_readlink_desc, spec_readlink }, /* readlink */
152 { &vop_abortop_desc, spec_abortop }, /* abortop */
153 { &vop_inactive_desc, ufs_inactive }, /* inactive */
154 { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */
155 { &vop_lock_desc, ffs_lock }, /* lock */
156 { &vop_unlock_desc, ffs_unlock }, /* unlock */
157 { &vop_bmap_desc, spec_bmap }, /* bmap */
158 { &vop_strategy_desc, spec_strategy }, /* strategy */
159 { &vop_print_desc, ufs_print }, /* print */
160 { &vop_islocked_desc, ffs_islocked }, /* islocked */
161 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */
162 { &vop_advlock_desc, spec_advlock }, /* advlock */
163 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
164 { &vop_getpages_desc, spec_getpages }, /* getpages */
165 { &vop_putpages_desc, spec_putpages }, /* putpages */
166 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */
167 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */
168 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */
169 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */
170 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */
171 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */
172 { NULL, NULL }
173 };
174 const struct vnodeopv_desc ffs_specop_opv_desc =
175 { &ffs_specop_p, ffs_specop_entries };
176
177 int (**ffs_fifoop_p)(void *);
178 const struct vnodeopv_entry_desc ffs_fifoop_entries[] = {
179 { &vop_default_desc, vn_default_error },
180 { &vop_lookup_desc, fifo_lookup }, /* lookup */
181 { &vop_create_desc, fifo_create }, /* create */
182 { &vop_mknod_desc, fifo_mknod }, /* mknod */
183 { &vop_open_desc, fifo_open }, /* open */
184 { &vop_close_desc, ufsfifo_close }, /* close */
185 { &vop_access_desc, ufs_access }, /* access */
186 { &vop_getattr_desc, ufs_getattr }, /* getattr */
187 { &vop_setattr_desc, ufs_setattr }, /* setattr */
188 { &vop_read_desc, ufsfifo_read }, /* read */
189 { &vop_write_desc, ufsfifo_write }, /* write */
190 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */
191 { &vop_fcntl_desc, ufs_fcntl }, /* fcntl */
192 { &vop_poll_desc, fifo_poll }, /* poll */
193 { &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */
194 { &vop_revoke_desc, fifo_revoke }, /* revoke */
195 { &vop_mmap_desc, fifo_mmap }, /* mmap */
196 { &vop_fsync_desc, ffs_fsync }, /* fsync */
197 { &vop_seek_desc, fifo_seek }, /* seek */
198 { &vop_remove_desc, fifo_remove }, /* remove */
199 { &vop_link_desc, fifo_link }, /* link */
200 { &vop_rename_desc, fifo_rename }, /* rename */
201 { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */
202 { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */
203 { &vop_symlink_desc, fifo_symlink }, /* symlink */
204 { &vop_readdir_desc, fifo_readdir }, /* readdir */
205 { &vop_readlink_desc, fifo_readlink }, /* readlink */
206 { &vop_abortop_desc, fifo_abortop }, /* abortop */
207 { &vop_inactive_desc, ufs_inactive }, /* inactive */
208 { &vop_reclaim_desc, ffs_reclaim }, /* reclaim */
209 { &vop_lock_desc, ffs_lock }, /* lock */
210 { &vop_unlock_desc, ffs_unlock }, /* unlock */
211 { &vop_bmap_desc, fifo_bmap }, /* bmap */
212 { &vop_strategy_desc, fifo_strategy }, /* strategy */
213 { &vop_print_desc, ufs_print }, /* print */
214 { &vop_islocked_desc, ffs_islocked }, /* islocked */
215 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */
216 { &vop_advlock_desc, fifo_advlock }, /* advlock */
217 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */
218 { &vop_putpages_desc, fifo_putpages }, /* putpages */
219 { &vop_openextattr_desc, ffs_openextattr }, /* openextattr */
220 { &vop_closeextattr_desc, ffs_closeextattr }, /* closeextattr */
221 { &vop_getextattr_desc, ffs_getextattr }, /* getextattr */
222 { &vop_setextattr_desc, ffs_setextattr }, /* setextattr */
223 { &vop_listextattr_desc, ffs_listextattr }, /* listextattr */
224 { &vop_deleteextattr_desc, ffs_deleteextattr }, /* deleteextattr */
225 { NULL, NULL }
226 };
227 const struct vnodeopv_desc ffs_fifoop_opv_desc =
228 { &ffs_fifoop_p, ffs_fifoop_entries };
229
230 #include <ufs/ufs/ufs_readwrite.c>
231
232 int
233 ffs_fsync(void *v)
234 {
235 struct vop_fsync_args /* {
236 struct vnode *a_vp;
237 kauth_cred_t a_cred;
238 int a_flags;
239 off_t a_offlo;
240 off_t a_offhi;
241 struct lwp *a_l;
242 } */ *ap = v;
243 struct buf *bp;
244 int num, error, i;
245 struct indir ia[NIADDR + 1];
246 int bsize;
247 daddr_t blk_high;
248 struct vnode *vp;
249
250 vp = ap->a_vp;
251
252 fstrans_start(vp->v_mount, FSTRANS_LAZY);
253 /*
254 * XXX no easy way to sync a range in a file with softdep.
255 */
256 if ((ap->a_offlo == 0 && ap->a_offhi == 0) || DOINGSOFTDEP(vp) ||
257 (vp->v_type != VREG)) {
258 error = ffs_full_fsync(vp, ap->a_flags);
259 goto out;
260 }
261
262 bsize = vp->v_mount->mnt_stat.f_iosize;
263 blk_high = ap->a_offhi / bsize;
264 if (ap->a_offhi % bsize != 0)
265 blk_high++;
266
267 /*
268 * First, flush all pages in range.
269 */
270
271 mutex_enter(&vp->v_interlock);
272 error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo),
273 round_page(ap->a_offhi), PGO_CLEANIT |
274 ((ap->a_flags & FSYNC_WAIT) ? PGO_SYNCIO : 0));
275 if (error) {
276 goto out;
277 }
278
279 /*
280 * Then, flush indirect blocks.
281 */
282
283 if (blk_high >= NDADDR) {
284 error = ufs_getlbns(vp, blk_high, ia, &num);
285 if (error)
286 goto out;
287
288 mutex_enter(&bufcache_lock);
289 for (i = 0; i < num; i++) {
290 if ((bp = incore(vp, ia[i].in_lbn)) == NULL)
291 continue;
292 if ((bp->b_cflags & BC_BUSY) != 0 ||
293 (bp->b_oflags & BO_DELWRI) == 0)
294 continue;
295 bp->b_cflags |= BC_BUSY | BC_VFLUSH;
296 mutex_exit(&bufcache_lock);
297 bawrite(bp);
298 mutex_enter(&bufcache_lock);
299 }
300 mutex_exit(&bufcache_lock);
301 }
302
303 if (ap->a_flags & FSYNC_WAIT) {
304 mutex_enter(&vp->v_interlock);
305 while (vp->v_numoutput > 0)
306 cv_wait(&vp->v_cv, &vp->v_interlock);
307 mutex_exit(&vp->v_interlock);
308 }
309
310 error = ffs_update(vp, NULL, NULL,
311 ((ap->a_flags & (FSYNC_WAIT | FSYNC_DATAONLY)) == FSYNC_WAIT)
312 ? UPDATE_WAIT : 0);
313
314 if (error == 0 && ap->a_flags & FSYNC_CACHE) {
315 int l = 0;
316 VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &l, FWRITE,
317 curlwp->l_cred);
318 }
319
320 out:
321 fstrans_done(vp->v_mount);
322 return error;
323 }
324
325 /*
326 * Synch an open file.
327 */
328 /* ARGSUSED */
329 int
330 ffs_full_fsync(struct vnode *vp, int flags)
331 {
332 struct buf *bp, *nbp;
333 int error, passes, skipmeta, inodedeps_only, waitfor;
334
335 if (vp->v_type == VBLK &&
336 vp->v_specmountpoint != NULL &&
337 (vp->v_specmountpoint->mnt_flag & MNT_SOFTDEP))
338 softdep_fsync_mountdev(vp);
339
340 mutex_enter(&vp->v_interlock);
341
342 inodedeps_only = DOINGSOFTDEP(vp) && (flags & FSYNC_RECLAIM)
343 && UVM_OBJ_IS_CLEAN(&vp->v_uobj) && LIST_EMPTY(&vp->v_dirtyblkhd);
344
345 /*
346 * Flush all dirty data associated with a vnode.
347 */
348
349 if (vp->v_type == VREG || vp->v_type == VBLK) {
350 error = VOP_PUTPAGES(vp, 0, 0, PGO_ALLPAGES | PGO_CLEANIT |
351 ((flags & FSYNC_WAIT) ? PGO_SYNCIO : 0) |
352 (fstrans_getstate(vp->v_mount) == FSTRANS_SUSPENDING ?
353 PGO_FREE : 0));
354 if (error) {
355 return error;
356 }
357 } else
358 mutex_exit(&vp->v_interlock);
359
360 passes = NIADDR + 1;
361 skipmeta = 0;
362 if (flags & FSYNC_WAIT)
363 skipmeta = 1;
364
365 loop:
366 mutex_enter(&bufcache_lock);
367 LIST_FOREACH(bp, &vp->v_dirtyblkhd, b_vnbufs) {
368 bp->b_cflags &= ~BC_SCANNED;
369 }
370 for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
371 nbp = LIST_NEXT(bp, b_vnbufs);
372 if (bp->b_cflags & (BC_BUSY | BC_SCANNED))
373 continue;
374 if ((bp->b_oflags & BO_DELWRI) == 0)
375 panic("ffs_fsync: not dirty");
376 if (skipmeta && bp->b_lblkno < 0)
377 continue;
378 bp->b_cflags |= BC_BUSY | BC_VFLUSH | BC_SCANNED;
379 mutex_exit(&bufcache_lock);
380 /*
381 * On our final pass through, do all I/O synchronously
382 * so that we can find out if our flush is failing
383 * because of write errors.
384 */
385 if (passes > 0 || !(flags & FSYNC_WAIT))
386 (void) bawrite(bp);
387 else if ((error = bwrite(bp)) != 0)
388 return (error);
389 /*
390 * Since we unlocked during the I/O, we need
391 * to start from a known point.
392 */
393 mutex_enter(&bufcache_lock);
394 nbp = LIST_FIRST(&vp->v_dirtyblkhd);
395 }
396 mutex_exit(&bufcache_lock);
397 if (skipmeta) {
398 skipmeta = 0;
399 goto loop;
400 }
401
402 if (flags & FSYNC_WAIT) {
403 mutex_enter(&vp->v_interlock);
404 while (vp->v_numoutput) {
405 cv_wait(&vp->v_cv, &vp->v_interlock);
406 }
407 mutex_exit(&vp->v_interlock);
408
409 /*
410 * Ensure that any filesystem metadata associated
411 * with the vnode has been written.
412 */
413 if ((error = softdep_sync_metadata(vp)) != 0)
414 return (error);
415
416 if (!LIST_EMPTY(&vp->v_dirtyblkhd)) {
417 /*
418 * Block devices associated with filesystems may
419 * have new I/O requests posted for them even if
420 * the vnode is locked, so no amount of trying will
421 * get them clean. Thus we give block devices a
422 * good effort, then just give up. For all other file
423 * types, go around and try again until it is clean.
424 */
425 if (passes > 0) {
426 passes--;
427 goto loop;
428 }
429 #ifdef DIAGNOSTIC
430 if (vp->v_type != VBLK)
431 vprint("ffs_fsync: dirty", vp);
432 #endif
433 }
434 }
435
436 if (inodedeps_only)
437 waitfor = 0;
438 else
439 waitfor = (flags & FSYNC_WAIT) ? UPDATE_WAIT : 0;
440 error = ffs_update(vp, NULL, NULL, waitfor);
441
442 if (error == 0 && flags & FSYNC_CACHE) {
443 int i = 0;
444 VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &i, FWRITE,
445 curlwp->l_cred);
446 }
447
448 return error;
449 }
450
451 /*
452 * Reclaim an inode so that it can be used for other purposes.
453 */
454 int
455 ffs_reclaim(void *v)
456 {
457 struct vop_reclaim_args /* {
458 struct vnode *a_vp;
459 struct lwp *a_l;
460 } */ *ap = v;
461 struct vnode *vp = ap->a_vp;
462 struct inode *ip = VTOI(vp);
463 struct mount *mp = vp->v_mount;
464 struct ufsmount *ump = ip->i_ump;
465 void *data;
466 int error;
467
468 fstrans_start(mp, FSTRANS_LAZY);
469 if ((error = ufs_reclaim(vp)) != 0) {
470 fstrans_done(mp);
471 return (error);
472 }
473 if (ip->i_din.ffs1_din != NULL) {
474 if (ump->um_fstype == UFS1)
475 pool_cache_put(ffs_dinode1_cache, ip->i_din.ffs1_din);
476 else
477 pool_cache_put(ffs_dinode2_cache, ip->i_din.ffs2_din);
478 }
479 /*
480 * To interlock with ffs_sync().
481 */
482 genfs_node_destroy(vp);
483 mutex_enter(&vp->v_interlock);
484 data = vp->v_data;
485 vp->v_data = NULL;
486 mutex_exit(&vp->v_interlock);
487
488 /*
489 * XXX MFS ends up here, too, to free an inode. Should we create
490 * XXX a separate pool for MFS inodes?
491 */
492 pool_cache_put(ffs_inode_cache, data);
493 fstrans_done(mp);
494 return (0);
495 }
496
497 #if 0
498 int
499 ffs_getpages(void *v)
500 {
501 struct vop_getpages_args /* {
502 struct vnode *a_vp;
503 voff_t a_offset;
504 struct vm_page **a_m;
505 int *a_count;
506 int a_centeridx;
507 vm_prot_t a_access_type;
508 int a_advice;
509 int a_flags;
510 } */ *ap = v;
511 struct vnode *vp = ap->a_vp;
512 struct inode *ip = VTOI(vp);
513 struct fs *fs = ip->i_fs;
514
515 /*
516 * don't allow a softdep write to create pages for only part of a block.
517 * the dependency tracking requires that all pages be in memory for
518 * a block involved in a dependency.
519 */
520
521 if (ap->a_flags & PGO_OVERWRITE &&
522 (blkoff(fs, ap->a_offset) != 0 ||
523 blkoff(fs, *ap->a_count << PAGE_SHIFT) != 0) &&
524 DOINGSOFTDEP(ap->a_vp)) {
525 if ((ap->a_flags & PGO_LOCKED) == 0) {
526 mutex_exit(&vp->v_interlock);
527 }
528 return EINVAL;
529 }
530 return genfs_getpages(v);
531 }
532 #endif
533
534 /*
535 * Return the last logical file offset that should be written for this file
536 * if we're doing a write that ends at "size".
537 */
538
539 void
540 ffs_gop_size(struct vnode *vp, off_t size, off_t *eobp, int flags)
541 {
542 struct inode *ip = VTOI(vp);
543 struct fs *fs = ip->i_fs;
544 daddr_t olbn, nlbn;
545
546 olbn = lblkno(fs, ip->i_size);
547 nlbn = lblkno(fs, size);
548 if (nlbn < NDADDR && olbn <= nlbn) {
549 *eobp = fragroundup(fs, size);
550 } else {
551 *eobp = blkroundup(fs, size);
552 }
553 }
554
555 int
556 ffs_openextattr(void *v)
557 {
558 struct vop_openextattr_args /* {
559 struct vnode *a_vp;
560 kauth_cred_t a_cred;
561 struct proc *a_p;
562 } */ *ap = v;
563 struct inode *ip = VTOI(ap->a_vp);
564 struct fs *fs = ip->i_fs;
565
566 /* Not supported for UFS1 file systems. */
567 if (fs->fs_magic == FS_UFS1_MAGIC)
568 return (EOPNOTSUPP);
569
570 /* XXX Not implemented for UFS2 file systems. */
571 return (EOPNOTSUPP);
572 }
573
574 int
575 ffs_closeextattr(void *v)
576 {
577 struct vop_closeextattr_args /* {
578 struct vnode *a_vp;
579 int a_commit;
580 kauth_cred_t a_cred;
581 struct proc *a_p;
582 } */ *ap = v;
583 struct inode *ip = VTOI(ap->a_vp);
584 struct fs *fs = ip->i_fs;
585
586 /* Not supported for UFS1 file systems. */
587 if (fs->fs_magic == FS_UFS1_MAGIC)
588 return (EOPNOTSUPP);
589
590 /* XXX Not implemented for UFS2 file systems. */
591 return (EOPNOTSUPP);
592 }
593
594 int
595 ffs_getextattr(void *v)
596 {
597 struct vop_getextattr_args /* {
598 struct vnode *a_vp;
599 int a_attrnamespace;
600 const char *a_name;
601 struct uio *a_uio;
602 size_t *a_size;
603 kauth_cred_t a_cred;
604 struct proc *a_p;
605 } */ *ap = v;
606 struct vnode *vp = ap->a_vp;
607 struct inode *ip = VTOI(vp);
608 struct fs *fs = ip->i_fs;
609
610 if (fs->fs_magic == FS_UFS1_MAGIC) {
611 #ifdef UFS_EXTATTR
612 int error;
613
614 fstrans_start(vp->v_mount, FSTRANS_SHARED);
615 error = ufs_getextattr(ap);
616 fstrans_done(vp->v_mount);
617 return error;
618 #else
619 return (EOPNOTSUPP);
620 #endif
621 }
622
623 /* XXX Not implemented for UFS2 file systems. */
624 return (EOPNOTSUPP);
625 }
626
627 int
628 ffs_setextattr(void *v)
629 {
630 struct vop_setextattr_args /* {
631 struct vnode *a_vp;
632 int a_attrnamespace;
633 const char *a_name;
634 struct uio *a_uio;
635 kauth_cred_t a_cred;
636 struct proc *a_p;
637 } */ *ap = v;
638 struct vnode *vp = ap->a_vp;
639 struct inode *ip = VTOI(vp);
640 struct fs *fs = ip->i_fs;
641
642 if (fs->fs_magic == FS_UFS1_MAGIC) {
643 #ifdef UFS_EXTATTR
644 int error;
645
646 fstrans_start(vp->v_mount, FSTRANS_SHARED);
647 error = ufs_setextattr(ap);
648 fstrans_done(vp->v_mount);
649 return error;
650 #else
651 return (EOPNOTSUPP);
652 #endif
653 }
654
655 /* XXX Not implemented for UFS2 file systems. */
656 return (EOPNOTSUPP);
657 }
658
659 int
660 ffs_listextattr(void *v)
661 {
662 struct vop_listextattr_args /* {
663 struct vnode *a_vp;
664 int a_attrnamespace;
665 struct uio *a_uio;
666 size_t *a_size;
667 kauth_cred_t a_cred;
668 struct proc *a_p;
669 } */ *ap = v;
670 struct inode *ip = VTOI(ap->a_vp);
671 struct fs *fs = ip->i_fs;
672
673 /* Not supported for UFS1 file systems. */
674 if (fs->fs_magic == FS_UFS1_MAGIC)
675 return (EOPNOTSUPP);
676
677 /* XXX Not implemented for UFS2 file systems. */
678 return (EOPNOTSUPP);
679 }
680
681 int
682 ffs_deleteextattr(void *v)
683 {
684 struct vop_deleteextattr_args /* {
685 struct vnode *a_vp;
686 int a_attrnamespace;
687 kauth_cred_t a_cred;
688 struct proc *a_p;
689 } */ *ap = v;
690 struct vnode *vp = ap->a_vp;
691 struct inode *ip = VTOI(vp);
692 struct fs *fs = ip->i_fs;
693
694 if (fs->fs_magic == FS_UFS1_MAGIC) {
695 #ifdef UFS_EXTATTR
696 int error;
697
698 fstrans_start(vp->v_mount, FSTRANS_SHARED);
699 error = ufs_deleteextattr(ap);
700 fstrans_done(vp->v_mount);
701 return error;
702 #else
703 return (EOPNOTSUPP);
704 #endif
705 }
706
707 /* XXX Not implemented for UFS2 file systems. */
708 return (EOPNOTSUPP);
709 }
710
711 /*
712 * Lock the node.
713 */
714 int
715 ffs_lock(void *v)
716 {
717 struct vop_lock_args /* {
718 struct vnode *a_vp;
719 int a_flags;
720 } */ *ap = v;
721 struct vnode *vp = ap->a_vp;
722 struct mount *mp = vp->v_mount;
723 struct vnlock *lkp;
724 int flags = ap->a_flags;
725 int result;
726
727 if ((flags & LK_INTERLOCK) != 0) {
728 mutex_exit(&vp->v_interlock);
729 flags &= ~LK_INTERLOCK;
730 }
731
732 /*
733 * Fake lock during file system suspension.
734 */
735 if ((vp->v_type == VREG || vp->v_type == VDIR) &&
736 fstrans_is_owner(mp) &&
737 fstrans_getstate(mp) == FSTRANS_SUSPENDING) {
738 return 0;
739 }
740
741 for (;;) {
742 lkp = vp->v_vnlock;
743 result = vlockmgr(lkp, flags);
744 if (lkp == vp->v_vnlock || result != 0)
745 return result;
746 /*
747 * Apparent success, except that the vnode mutated between
748 * snapshot file vnode and regular file vnode while this
749 * thread slept. The lock currently held is not the right
750 * lock. Release it, and try to get the new lock.
751 */
752 (void) vlockmgr(lkp, LK_RELEASE);
753 }
754 }
755
756 /*
757 * Unlock the node.
758 */
759 int
760 ffs_unlock(void *v)
761 {
762 struct vop_unlock_args /* {
763 struct vnode *a_vp;
764 int a_flags;
765 } */ *ap = v;
766 struct vnode *vp = ap->a_vp;
767 struct mount *mp = vp->v_mount;
768
769 KASSERT(ap->a_flags == 0);
770
771 /*
772 * Fake unlock during file system suspension.
773 */
774 if ((vp->v_type == VREG || vp->v_type == VDIR) &&
775 fstrans_is_owner(mp) &&
776 fstrans_getstate(mp) == FSTRANS_SUSPENDING) {
777 return 0;
778 }
779 return (vlockmgr(vp->v_vnlock, LK_RELEASE));
780 }
781
782 /*
783 * Return whether or not the node is locked.
784 */
785 int
786 ffs_islocked(void *v)
787 {
788 struct vop_islocked_args /* {
789 struct vnode *a_vp;
790 } */ *ap = v;
791 struct vnode *vp = ap->a_vp;
792
793 return (vlockstatus(vp->v_vnlock));
794 }
795