1 /*        $NetBSD: ffs_vnops.c,v 1.138 2021/12/14 11:06:12 chs Exp $  */
2 
3 /*-
4  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Wasabi Systems, Inc, and by Andrew Doran.
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  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1982, 1986, 1989, 1993
34  *        The Regents of the University of California.  All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 3. Neither the name of the University nor the names of its contributors
45  *    may be used to endorse or promote products derived from this software
46  *    without specific prior written permission.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58  * SUCH DAMAGE.
59  *
60  *        @(#)ffs_vnops.c     8.15 (Berkeley) 5/14/95
61  */
62 
63 #include <sys/cdefs.h>
64 __KERNEL_RCSID(0, "$NetBSD: ffs_vnops.c,v 1.138 2021/12/14 11:06:12 chs Exp $");
65 
66 #if defined(_KERNEL_OPT)
67 #include "opt_ffs.h"
68 #include "opt_wapbl.h"
69 #endif
70 
71 #include <sys/param.h>
72 #include <sys/systm.h>
73 #include <sys/resourcevar.h>
74 #include <sys/kernel.h>
75 #include <sys/file.h>
76 #include <sys/stat.h>
77 #include <sys/buf.h>
78 #include <sys/event.h>
79 #include <sys/proc.h>
80 #include <sys/mount.h>
81 #include <sys/vnode.h>
82 #include <sys/pool.h>
83 #include <sys/signalvar.h>
84 #include <sys/kauth.h>
85 #include <sys/wapbl.h>
86 
87 #include <miscfs/fifofs/fifo.h>
88 #include <miscfs/genfs/genfs.h>
89 #include <miscfs/specfs/specdev.h>
90 
91 #include <ufs/ufs/acl.h>
92 #include <ufs/ufs/inode.h>
93 #include <ufs/ufs/dir.h>
94 #include <ufs/ufs/ufs_extern.h>
95 #include <ufs/ufs/ufsmount.h>
96 #include <ufs/ufs/ufs_wapbl.h>
97 
98 #include <ufs/ffs/fs.h>
99 #include <ufs/ffs/ffs_extern.h>
100 
101 /* Global vfs data structures for ufs. */
102 int (**ffs_vnodeop_p)(void *);
103 const struct vnodeopv_entry_desc ffs_vnodeop_entries[] = {
104           { &vop_default_desc, vn_default_error },
105           { &vop_parsepath_desc, genfs_parsepath },         /* parsepath */
106           { &vop_lookup_desc, ufs_lookup },                 /* lookup */
107           { &vop_create_desc, ufs_create },                 /* create */
108           { &vop_whiteout_desc, ufs_whiteout },             /* whiteout */
109           { &vop_mknod_desc, ufs_mknod },                             /* mknod */
110           { &vop_open_desc, ufs_open },                     /* open */
111           { &vop_close_desc, ufs_close },                             /* close */
112           { &vop_access_desc, genfs_access },               /* access */
113           { &vop_accessx_desc, ufs_accessx },               /* accessx */
114           { &vop_getattr_desc, ufs_getattr },               /* getattr */
115           { &vop_setattr_desc, ufs_setattr },               /* setattr */
116           { &vop_read_desc, ffs_read },                     /* read */
117           { &vop_write_desc, ffs_write },                             /* write */
118           { &vop_fallocate_desc, genfs_eopnotsupp },        /* fallocate */
119           { &vop_fdiscard_desc, genfs_eopnotsupp },         /* fdiscard */
120           { &vop_ioctl_desc, genfs_enoioctl },              /* ioctl */
121           { &vop_fcntl_desc, genfs_fcntl },                 /* fcntl */
122           { &vop_poll_desc, genfs_poll },                             /* poll */
123           { &vop_kqfilter_desc, genfs_kqfilter },           /* kqfilter */
124           { &vop_revoke_desc, genfs_revoke },               /* revoke */
125           { &vop_mmap_desc, genfs_mmap },                             /* mmap */
126           { &vop_fsync_desc, ffs_fsync },                             /* fsync */
127           { &vop_seek_desc, genfs_seek },                             /* seek */
128           { &vop_remove_desc, ufs_remove },                 /* remove */
129           { &vop_link_desc, ufs_link },                     /* link */
130           { &vop_rename_desc, ufs_rename },                 /* rename */
131           { &vop_mkdir_desc, ufs_mkdir },                             /* mkdir */
132           { &vop_rmdir_desc, ufs_rmdir },                             /* rmdir */
133           { &vop_symlink_desc, ufs_symlink },               /* symlink */
134           { &vop_readdir_desc, ufs_readdir },               /* readdir */
135           { &vop_readlink_desc, ufs_readlink },             /* readlink */
136           { &vop_abortop_desc, genfs_abortop },             /* abortop */
137           { &vop_inactive_desc, ufs_inactive },             /* inactive */
138           { &vop_reclaim_desc, ffs_reclaim },               /* reclaim */
139           { &vop_lock_desc, genfs_lock },                             /* lock */
140           { &vop_unlock_desc, genfs_unlock },               /* unlock */
141           { &vop_bmap_desc, ufs_bmap },                     /* bmap */
142           { &vop_strategy_desc, ufs_strategy },             /* strategy */
143           { &vop_print_desc, ufs_print },                             /* print */
144           { &vop_islocked_desc, genfs_islocked },           /* islocked */
145           { &vop_pathconf_desc, ufs_pathconf },             /* pathconf */
146           { &vop_advlock_desc, ufs_advlock },               /* advlock */
147           { &vop_bwrite_desc, vn_bwrite },                  /* bwrite */
148           { &vop_getpages_desc, genfs_getpages },           /* getpages */
149           { &vop_putpages_desc, genfs_putpages },           /* putpages */
150           { &vop_openextattr_desc, ffs_openextattr },       /* openextattr */
151           { &vop_closeextattr_desc, ffs_closeextattr },     /* closeextattr */
152           { &vop_getextattr_desc, ffs_getextattr },         /* getextattr */
153           { &vop_setextattr_desc, ffs_setextattr },         /* setextattr */
154           { &vop_listextattr_desc, ffs_listextattr },       /* listextattr */
155           { &vop_deleteextattr_desc, ffs_deleteextattr },   /* deleteextattr */
156           { &vop_getacl_desc, ufs_getacl },                 /* getacl */
157           { &vop_setacl_desc, ufs_setacl },                 /* setacl */
158           { &vop_aclcheck_desc, ufs_aclcheck },             /* aclcheck */
159           { NULL, NULL }
160 };
161 const struct vnodeopv_desc ffs_vnodeop_opv_desc =
162           { &ffs_vnodeop_p, ffs_vnodeop_entries };
163 
164 int (**ffs_specop_p)(void *);
165 const struct vnodeopv_entry_desc ffs_specop_entries[] = {
166           { &vop_default_desc, vn_default_error },
167           GENFS_SPECOP_ENTRIES,
168           { &vop_close_desc, ufsspec_close },               /* close */
169           { &vop_access_desc, genfs_access },               /* access */
170           { &vop_accessx_desc, ufs_accessx },               /* accessx */
171           { &vop_getattr_desc, ufs_getattr },               /* getattr */
172           { &vop_setattr_desc, ufs_setattr },               /* setattr */
173           { &vop_read_desc, ufsspec_read },                 /* read */
174           { &vop_write_desc, ufsspec_write },               /* write */
175           { &vop_fcntl_desc, genfs_fcntl },                 /* fcntl */
176           { &vop_fsync_desc, ffs_spec_fsync },              /* fsync */
177           { &vop_inactive_desc, ufs_inactive },             /* inactive */
178           { &vop_reclaim_desc, ffs_reclaim },               /* reclaim */
179           { &vop_lock_desc, genfs_lock },                             /* lock */
180           { &vop_unlock_desc, genfs_unlock },               /* unlock */
181           { &vop_print_desc, ufs_print },                             /* print */
182           { &vop_islocked_desc, genfs_islocked },           /* islocked */
183           { &vop_bwrite_desc, vn_bwrite },                  /* bwrite */
184           { &vop_openextattr_desc, ffs_openextattr },       /* openextattr */
185           { &vop_closeextattr_desc, ffs_closeextattr },     /* closeextattr */
186           { &vop_getextattr_desc, ffs_getextattr },         /* getextattr */
187           { &vop_setextattr_desc, ffs_setextattr },         /* setextattr */
188           { &vop_listextattr_desc, ffs_listextattr },       /* listextattr */
189           { &vop_deleteextattr_desc, ffs_deleteextattr },   /* deleteextattr */
190           { &vop_getacl_desc, ufs_getacl },                 /* getacl */
191           { &vop_setacl_desc, ufs_setacl },                 /* setacl */
192           { &vop_aclcheck_desc, ufs_aclcheck },             /* aclcheck */
193           { NULL, NULL }
194 };
195 const struct vnodeopv_desc ffs_specop_opv_desc =
196           { &ffs_specop_p, ffs_specop_entries };
197 
198 int (**ffs_fifoop_p)(void *);
199 const struct vnodeopv_entry_desc ffs_fifoop_entries[] = {
200           { &vop_default_desc, vn_default_error },
201           GENFS_FIFOOP_ENTRIES,
202           { &vop_close_desc, ufsfifo_close },               /* close */
203           { &vop_access_desc, genfs_access },               /* access */
204           { &vop_accessx_desc, ufs_accessx },               /* accessx */
205           { &vop_getattr_desc, ufs_getattr },               /* getattr */
206           { &vop_setattr_desc, ufs_setattr },               /* setattr */
207           { &vop_read_desc, ufsfifo_read },                 /* read */
208           { &vop_write_desc, ufsfifo_write },               /* write */
209           { &vop_fcntl_desc, genfs_fcntl },                 /* fcntl */
210           { &vop_fsync_desc, ffs_fsync },                             /* fsync */
211           { &vop_inactive_desc, ufs_inactive },             /* inactive */
212           { &vop_reclaim_desc, ffs_reclaim },               /* reclaim */
213           { &vop_lock_desc, genfs_lock },                             /* lock */
214           { &vop_unlock_desc, genfs_unlock },               /* unlock */
215           { &vop_bmap_desc, ufs_bmap },                     /* bmap */
216           { &vop_strategy_desc, ffsext_strategy },          /* strategy */
217           { &vop_print_desc, ufs_print },                             /* print */
218           { &vop_islocked_desc, genfs_islocked },           /* islocked */
219           { &vop_pathconf_desc, ufs_pathconf },             /* pathconf */
220           { &vop_bwrite_desc, vn_bwrite },                  /* bwrite */
221           { &vop_openextattr_desc, ffs_openextattr },       /* openextattr */
222           { &vop_closeextattr_desc, ffs_closeextattr },     /* closeextattr */
223           { &vop_getextattr_desc, ffs_getextattr },         /* getextattr */
224           { &vop_setextattr_desc, ffs_setextattr },         /* setextattr */
225           { &vop_listextattr_desc, ffs_listextattr },       /* listextattr */
226           { &vop_deleteextattr_desc, ffs_deleteextattr },   /* deleteextattr */
227           { &vop_getacl_desc, ufs_getacl },                 /* getacl */
228           { &vop_setacl_desc, ufs_setacl },                 /* setacl */
229           { &vop_aclcheck_desc, ufs_aclcheck },             /* aclcheck */
230           { NULL, NULL }
231 };
232 const struct vnodeopv_desc ffs_fifoop_opv_desc =
233           { &ffs_fifoop_p, ffs_fifoop_entries };
234 
235 #include <ufs/ufs/ufs_readwrite.c>
236 
237 int
ffs_spec_fsync(void * v)238 ffs_spec_fsync(void *v)
239 {
240           struct vop_fsync_args /* {
241                     struct vnode *a_vp;
242                     kauth_cred_t a_cred;
243                     int a_flags;
244                     off_t a_offlo;
245                     off_t a_offhi;
246                     struct lwp *a_l;
247           } */ *ap = v;
248           int error, flags, uflags;
249           struct vnode *vp;
250 
251           flags = ap->a_flags;
252           uflags = UPDATE_CLOSE | ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0);
253           vp = ap->a_vp;
254 
255           error = spec_fsync(v);
256           if (error)
257                     goto out;
258 
259 #ifdef WAPBL
260           struct mount *mp = vp->v_mount;
261 
262           if (mp && mp->mnt_wapbl) {
263                     /*
264                      * Don't bother writing out metadata if the syncer is
265                      * making the request.  We will let the sync vnode
266                      * write it out in a single burst through a call to
267                      * VFS_SYNC().
268                      */
269                     if ((flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0)
270                               goto out;
271                     if ((VTOI(vp)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE
272                         | IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) != 0) {
273                               error = UFS_WAPBL_BEGIN(mp);
274                               if (error != 0)
275                                         goto out;
276                               error = ffs_update(vp, NULL, NULL, uflags);
277                               UFS_WAPBL_END(mp);
278                     }
279                     goto out;
280           }
281 #endif /* WAPBL */
282 
283           error = ffs_update(vp, NULL, NULL, uflags);
284 
285 out:
286           return error;
287 }
288 
289 int
ffs_fsync(void * v)290 ffs_fsync(void *v)
291 {
292           struct vop_fsync_args /* {
293                     struct vnode *a_vp;
294                     kauth_cred_t a_cred;
295                     int a_flags;
296                     off_t a_offlo;
297                     off_t a_offhi;
298                     struct lwp *a_l;
299           } */ *ap = v;
300           struct buf *bp;
301           int num, error, i;
302           struct indir ia[UFS_NIADDR + 1];
303           int bsize;
304           daddr_t blk_high;
305           struct vnode *vp;
306           struct mount *mp;
307 
308           vp = ap->a_vp;
309           mp = vp->v_mount;
310 
311           if ((ap->a_offlo == 0 && ap->a_offhi == 0) || (vp->v_type != VREG)) {
312                     error = ffs_full_fsync(vp, ap->a_flags);
313                     goto out;
314           }
315 
316           bsize = mp->mnt_stat.f_iosize;
317           blk_high = ap->a_offhi / bsize;
318           if (ap->a_offhi % bsize != 0)
319                     blk_high++;
320 
321           /*
322            * First, flush all pages in range.
323            */
324 
325           rw_enter(vp->v_uobj.vmobjlock, RW_WRITER);
326           error = VOP_PUTPAGES(vp, trunc_page(ap->a_offlo),
327               round_page(ap->a_offhi), PGO_CLEANIT |
328               ((ap->a_flags & FSYNC_WAIT) ? PGO_SYNCIO : 0));
329           if (error) {
330                     goto out;
331           }
332 
333 #ifdef WAPBL
334           KASSERT(vp->v_type == VREG);
335           if (mp->mnt_wapbl) {
336                     /*
337                      * Don't bother writing out metadata if the syncer is
338                      * making the request.  We will let the sync vnode
339                      * write it out in a single burst through a call to
340                      * VFS_SYNC().
341                      */
342                     if ((ap->a_flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0) {
343                               return 0;
344                     }
345                     error = 0;
346                     if (vp->v_tag == VT_UFS && VTOI(vp)->i_flag &
347                         (IN_ACCESS | IN_CHANGE | IN_UPDATE | IN_MODIFY |
348                                          IN_MODIFIED | IN_ACCESSED)) {
349                               error = UFS_WAPBL_BEGIN(mp);
350                               if (error) {
351                                         return error;
352                               }
353                               error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE |
354                                   ((ap->a_flags & FSYNC_WAIT) ? UPDATE_WAIT : 0));
355                               UFS_WAPBL_END(mp);
356                     }
357                     if (error || (ap->a_flags & FSYNC_NOLOG) != 0) {
358                               return error;
359                     }
360                     error = wapbl_flush(mp->mnt_wapbl, 0);
361                     return error;
362           }
363 #endif /* WAPBL */
364 
365           /*
366            * Then, flush indirect blocks.
367            */
368 
369           if (blk_high >= UFS_NDADDR) {
370                     error = ufs_getlbns(vp, blk_high, ia, &num);
371                     if (error)
372                               goto out;
373 
374                     mutex_enter(&bufcache_lock);
375                     for (i = 0; i < num; i++) {
376                               if ((bp = incore(vp, ia[i].in_lbn)) == NULL)
377                                         continue;
378                               if ((bp->b_cflags & BC_BUSY) != 0 ||
379                                   (bp->b_oflags & BO_DELWRI) == 0)
380                                         continue;
381                               bp->b_cflags |= BC_BUSY | BC_VFLUSH;
382                               mutex_exit(&bufcache_lock);
383                               bawrite(bp);
384                               mutex_enter(&bufcache_lock);
385                     }
386                     mutex_exit(&bufcache_lock);
387           }
388 
389           if (ap->a_flags & FSYNC_WAIT) {
390                     mutex_enter(vp->v_interlock);
391                     while (vp->v_numoutput > 0)
392                               cv_wait(&vp->v_cv, vp->v_interlock);
393                     mutex_exit(vp->v_interlock);
394           }
395 
396           error = ffs_update(vp, NULL, NULL, UPDATE_CLOSE |
397               (((ap->a_flags & (FSYNC_WAIT | FSYNC_DATAONLY)) == FSYNC_WAIT)
398               ? UPDATE_WAIT : 0));
399 
400           if (error == 0 && ap->a_flags & FSYNC_CACHE) {
401                     int l = 0;
402                     VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &l, FWRITE,
403                               curlwp->l_cred);
404           }
405 
406 out:
407           return error;
408 }
409 
410 /*
411  * Synch an open file.  Called for VOP_FSYNC().
412  */
413 /* ARGSUSED */
414 int
ffs_full_fsync(struct vnode * vp,int flags)415 ffs_full_fsync(struct vnode *vp, int flags)
416 {
417           int error, i, uflags;
418 
419           KASSERT(vp->v_tag == VT_UFS);
420           KASSERT(VTOI(vp) != NULL);
421           KASSERT(vp->v_type != VCHR && vp->v_type != VBLK);
422 
423           uflags = UPDATE_CLOSE | ((flags & FSYNC_WAIT) ? UPDATE_WAIT : 0);
424 
425 #ifdef WAPBL
426           struct mount *mp = vp->v_mount;
427 
428           if (mp && mp->mnt_wapbl) {
429 
430                     /*
431                      * Flush all dirty data associated with the vnode.
432                      */
433                     if (vp->v_type == VREG) {
434                               int pflags = PGO_ALLPAGES | PGO_CLEANIT;
435 
436                               if ((flags & FSYNC_LAZY))
437                                         pflags |= PGO_LAZY;
438                               if ((flags & FSYNC_WAIT))
439                                         pflags |= PGO_SYNCIO;
440                               rw_enter(vp->v_uobj.vmobjlock, RW_WRITER);
441                               error = VOP_PUTPAGES(vp, 0, 0, pflags);
442                               if (error)
443                                         return error;
444                     }
445 
446                     /*
447                      * Don't bother writing out metadata if the syncer is
448                      * making the request.  We will let the sync vnode
449                      * write it out in a single burst through a call to
450                      * VFS_SYNC().
451                      */
452                     if ((flags & (FSYNC_DATAONLY | FSYNC_LAZY)) != 0)
453                               return 0;
454 
455                     if ((VTOI(vp)->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE
456                         | IN_MODIFY | IN_MODIFIED | IN_ACCESSED)) != 0) {
457                               error = UFS_WAPBL_BEGIN(mp);
458                               if (error)
459                                         return error;
460                               error = ffs_update(vp, NULL, NULL, uflags);
461                               UFS_WAPBL_END(mp);
462                     } else {
463                               error = 0;
464                     }
465                     if (error || (flags & FSYNC_NOLOG) != 0)
466                               return error;
467 
468                     /*
469                      * Don't flush the log if the vnode being flushed
470                      * contains no dirty buffers that could be in the log.
471                      */
472                     if (!LIST_EMPTY(&vp->v_dirtyblkhd)) {
473                               error = wapbl_flush(mp->mnt_wapbl, 0);
474                               if (error)
475                                         return error;
476                     }
477 
478                     if ((flags & FSYNC_WAIT) != 0) {
479                               mutex_enter(vp->v_interlock);
480                               while (vp->v_numoutput != 0)
481                                         cv_wait(&vp->v_cv, vp->v_interlock);
482                               mutex_exit(vp->v_interlock);
483                     }
484 
485                     return error;
486           }
487 #endif /* WAPBL */
488 
489           error = vflushbuf(vp, flags);
490           if (error == 0)
491                     error = ffs_update(vp, NULL, NULL, uflags);
492           if (error == 0 && (flags & FSYNC_CACHE) != 0) {
493                     i = 1;
494                     (void)VOP_IOCTL(VTOI(vp)->i_devvp, DIOCCACHESYNC, &i, FWRITE,
495                         kauth_cred_get());
496           }
497 
498           return error;
499 }
500 
501 /*
502  * Reclaim an inode so that it can be used for other purposes.
503  */
504 int
ffs_reclaim(void * v)505 ffs_reclaim(void *v)
506 {
507           struct vop_reclaim_v2_args /* {
508                     struct vnode *a_vp;
509                     struct lwp *a_l;
510           } */ *ap = v;
511           struct vnode *vp = ap->a_vp;
512           struct inode *ip = VTOI(vp);
513           struct mount *mp = vp->v_mount;
514           struct ufsmount *ump = ip->i_ump;
515           void *data;
516           int error;
517 
518           VOP_UNLOCK(vp);
519 
520           /*
521            * The inode must be freed and updated before being removed
522            * from its hash chain.  Other threads trying to gain a hold
523            * or lock on the inode will be stalled.
524            */
525           error = UFS_WAPBL_BEGIN(mp);
526           if (error) {
527                     return error;
528           }
529           if (ip->i_nlink <= 0 && ip->i_omode != 0 &&
530               (vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
531                     ffs_vfree(vp, ip->i_number, ip->i_omode);
532           UFS_WAPBL_END(mp);
533           if ((error = ufs_reclaim(vp)) != 0) {
534                     return (error);
535           }
536           if (ip->i_din.ffs1_din != NULL) {
537                     if (ump->um_fstype == UFS1)
538                               pool_cache_put(ffs_dinode1_cache, ip->i_din.ffs1_din);
539                     else
540                               pool_cache_put(ffs_dinode2_cache, ip->i_din.ffs2_din);
541           }
542           /*
543            * To interlock with ffs_sync().
544            */
545           genfs_node_destroy(vp);
546           mutex_enter(vp->v_interlock);
547           data = vp->v_data;
548           vp->v_data = NULL;
549           mutex_exit(vp->v_interlock);
550 
551           /*
552            * XXX MFS ends up here, too, to free an inode.  Should we create
553            * XXX a separate pool for MFS inodes?
554            */
555           pool_cache_put(ffs_inode_cache, data);
556           return (0);
557 }
558 
559 /*
560  * Return the last logical file offset that should be written for this file
561  * if we're doing a write that ends at "size".
562  */
563 
564 void
ffs_gop_size(struct vnode * vp,off_t size,off_t * eobp,int flags)565 ffs_gop_size(struct vnode *vp, off_t size, off_t *eobp, int flags)
566 {
567           struct inode *ip = VTOI(vp);
568           struct fs *fs = ip->i_fs;
569           daddr_t olbn, nlbn;
570 
571           olbn = ffs_lblkno(fs, ip->i_size);
572           nlbn = ffs_lblkno(fs, size);
573           if (nlbn < UFS_NDADDR && olbn <= nlbn) {
574                     *eobp = ffs_fragroundup(fs, size);
575           } else {
576                     *eobp = ffs_blkroundup(fs, size);
577           }
578 }
579