ulfs_vnops.c revision 1.11 1 /* $NetBSD: ulfs_vnops.c,v 1.11 2013/06/08 21:40:27 dholland Exp $ */
2 /* from NetBSD: ufs_vnops.c,v 1.213 2013/06/08 05:47:02 kardel Exp */
3
4 /*-
5 * Copyright (c) 2008 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Wasabi Systems, Inc.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*
34 * Copyright (c) 1982, 1986, 1989, 1993, 1995
35 * The Regents of the University of California. All rights reserved.
36 * (c) UNIX System Laboratories, Inc.
37 * All or some portions of this file are derived from material licensed
38 * to the University of California by American Telephone and Telegraph
39 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
40 * the permission of UNIX System Laboratories, Inc.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution.
50 * 3. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * SUCH DAMAGE.
65 *
66 * @(#)ufs_vnops.c 8.28 (Berkeley) 7/31/95
67 */
68
69 #include <sys/cdefs.h>
70 __KERNEL_RCSID(0, "$NetBSD: ulfs_vnops.c,v 1.11 2013/06/08 21:40:27 dholland Exp $");
71
72 #if defined(_KERNEL_OPT)
73 #include "opt_lfs.h"
74 #include "opt_quota.h"
75 #endif
76
77 #include <sys/param.h>
78 #include <sys/systm.h>
79 #include <sys/namei.h>
80 #include <sys/resourcevar.h>
81 #include <sys/kernel.h>
82 #include <sys/file.h>
83 #include <sys/stat.h>
84 #include <sys/buf.h>
85 #include <sys/proc.h>
86 #include <sys/mount.h>
87 #include <sys/vnode.h>
88 #include <sys/kmem.h>
89 #include <sys/malloc.h>
90 #include <sys/dirent.h>
91 #include <sys/lockf.h>
92 #include <sys/kauth.h>
93 #include <sys/wapbl.h>
94 #include <sys/fstrans.h>
95
96 #include <miscfs/specfs/specdev.h>
97 #include <miscfs/fifofs/fifo.h>
98 #include <miscfs/genfs/genfs.h>
99
100 #include <ufs/lfs/ulfs_inode.h>
101 #include <ufs/lfs/ulfs_dir.h>
102 #include <ufs/lfs/ulfsmount.h>
103 #include <ufs/lfs/ulfs_bswap.h>
104 #include <ufs/lfs/ulfs_extern.h>
105 #include <ufs/lfs/ulfs_wapbl.h>
106 #ifdef LFS_DIRHASH
107 #include <ufs/lfs/ulfs_dirhash.h>
108 #endif
109 #include <ufs/lfs/lfs_extern.h>
110 #include <ufs/lfs/lfs.h>
111
112 #include <uvm/uvm.h>
113
114 static int ulfs_chmod(struct vnode *, int, kauth_cred_t, struct lwp *);
115 static int ulfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t,
116 struct lwp *);
117
118 /*
119 * A virgin directory (no blushing please).
120 */
121 static const struct lfs_dirtemplate mastertemplate = {
122 0, 12, LFS_DT_DIR, 1, ".",
123 0, LFS_DIRBLKSIZ - 12, LFS_DT_DIR, 2, ".."
124 };
125
126 /*
127 * Create a regular file
128 */
129 int
130 ulfs_create(void *v)
131 {
132 struct vop_create_args /* {
133 struct vnode *a_dvp;
134 struct vnode **a_vpp;
135 struct componentname *a_cnp;
136 struct vattr *a_vap;
137 } */ *ap = v;
138 int error;
139 struct vnode *dvp = ap->a_dvp;
140 struct ulfs_lookup_results *ulr;
141
142 /* XXX should handle this material another way */
143 ulr = &VTOI(dvp)->i_crap;
144 ULFS_CHECK_CRAPCOUNTER(VTOI(dvp));
145
146 /*
147 * ULFS_WAPBL_BEGIN1(dvp->v_mount, dvp) performed by successful
148 * ulfs_makeinode
149 */
150 fstrans_start(dvp->v_mount, FSTRANS_SHARED);
151 error =
152 ulfs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
153 dvp, ulr, ap->a_vpp, ap->a_cnp);
154 if (error) {
155 fstrans_done(dvp->v_mount);
156 return (error);
157 }
158 ULFS_WAPBL_END1(dvp->v_mount, dvp);
159 fstrans_done(dvp->v_mount);
160 VN_KNOTE(dvp, NOTE_WRITE);
161 return (0);
162 }
163
164 /*
165 * Mknod vnode call
166 */
167 /* ARGSUSED */
168 int
169 ulfs_mknod(void *v)
170 {
171 struct vop_mknod_args /* {
172 struct vnode *a_dvp;
173 struct vnode **a_vpp;
174 struct componentname *a_cnp;
175 struct vattr *a_vap;
176 } */ *ap = v;
177 struct vattr *vap;
178 struct vnode **vpp;
179 struct inode *ip;
180 int error;
181 struct mount *mp;
182 ino_t ino;
183 struct ulfs_lookup_results *ulr;
184
185 vap = ap->a_vap;
186 vpp = ap->a_vpp;
187
188 /* XXX should handle this material another way */
189 ulr = &VTOI(ap->a_dvp)->i_crap;
190 ULFS_CHECK_CRAPCOUNTER(VTOI(ap->a_dvp));
191
192 /*
193 * ULFS_WAPBL_BEGIN1(dvp->v_mount, dvp) performed by successful
194 * ulfs_makeinode
195 */
196 fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED);
197 if ((error =
198 ulfs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
199 ap->a_dvp, ulr, vpp, ap->a_cnp)) != 0)
200 goto out;
201 VN_KNOTE(ap->a_dvp, NOTE_WRITE);
202 ip = VTOI(*vpp);
203 mp = (*vpp)->v_mount;
204 ino = ip->i_number;
205 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
206 if (vap->va_rdev != VNOVAL) {
207 struct ulfsmount *ump = ip->i_ump;
208 /*
209 * Want to be able to use this to make badblock
210 * inodes, so don't truncate the dev number.
211 */
212 if (ump->um_fstype == ULFS1)
213 ip->i_ffs1_rdev = ulfs_rw32(vap->va_rdev,
214 ULFS_MPNEEDSWAP(ump));
215 else
216 ip->i_ffs2_rdev = ulfs_rw64(vap->va_rdev,
217 ULFS_MPNEEDSWAP(ump));
218 }
219 ULFS_WAPBL_UPDATE(*vpp, NULL, NULL, 0);
220 ULFS_WAPBL_END1(ap->a_dvp->v_mount, ap->a_dvp);
221 /*
222 * Remove inode so that it will be reloaded by VFS_VGET and
223 * checked to see if it is an alias of an existing entry in
224 * the inode cache.
225 */
226 (*vpp)->v_type = VNON;
227 VOP_UNLOCK(*vpp);
228 vgone(*vpp);
229 error = VFS_VGET(mp, ino, vpp);
230 out:
231 fstrans_done(ap->a_dvp->v_mount);
232 if (error != 0) {
233 *vpp = NULL;
234 return (error);
235 }
236 return (0);
237 }
238
239 /*
240 * Open called.
241 *
242 * Nothing to do.
243 */
244 /* ARGSUSED */
245 int
246 ulfs_open(void *v)
247 {
248 struct vop_open_args /* {
249 struct vnode *a_vp;
250 int a_mode;
251 kauth_cred_t a_cred;
252 } */ *ap = v;
253
254 /*
255 * Files marked append-only must be opened for appending.
256 */
257 if ((VTOI(ap->a_vp)->i_flags & APPEND) &&
258 (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
259 return (EPERM);
260 return (0);
261 }
262
263 /*
264 * Close called.
265 *
266 * Update the times on the inode.
267 */
268 /* ARGSUSED */
269 int
270 ulfs_close(void *v)
271 {
272 struct vop_close_args /* {
273 struct vnode *a_vp;
274 int a_fflag;
275 kauth_cred_t a_cred;
276 } */ *ap = v;
277 struct vnode *vp;
278 struct inode *ip;
279
280 vp = ap->a_vp;
281 ip = VTOI(vp);
282 fstrans_start(vp->v_mount, FSTRANS_SHARED);
283 if (vp->v_usecount > 1)
284 ULFS_ITIMES(vp, NULL, NULL, NULL);
285 fstrans_done(vp->v_mount);
286 return (0);
287 }
288
289 static int
290 ulfs_check_possible(struct vnode *vp, struct inode *ip, mode_t mode,
291 kauth_cred_t cred)
292 {
293 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
294 int error;
295 #endif
296
297 /*
298 * Disallow write attempts on read-only file systems;
299 * unless the file is a socket, fifo, or a block or
300 * character device resident on the file system.
301 */
302 if (mode & VWRITE) {
303 switch (vp->v_type) {
304 case VDIR:
305 case VLNK:
306 case VREG:
307 if (vp->v_mount->mnt_flag & MNT_RDONLY)
308 return (EROFS);
309 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
310 fstrans_start(vp->v_mount, FSTRANS_SHARED);
311 error = lfs_chkdq(ip, 0, cred, 0);
312 fstrans_done(vp->v_mount);
313 if (error != 0)
314 return error;
315 #endif
316 break;
317 case VBAD:
318 case VBLK:
319 case VCHR:
320 case VSOCK:
321 case VFIFO:
322 case VNON:
323 default:
324 break;
325 }
326 }
327
328 /* If it is a snapshot, nobody gets access to it. */
329 if ((ip->i_flags & SF_SNAPSHOT))
330 return (EPERM);
331 /* If immutable bit set, nobody gets to write it. */
332 if ((mode & VWRITE) && (ip->i_flags & IMMUTABLE))
333 return (EPERM);
334
335 return 0;
336 }
337
338 static int
339 ulfs_check_permitted(struct vnode *vp, struct inode *ip, mode_t mode,
340 kauth_cred_t cred)
341 {
342
343 return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, vp->v_type,
344 ip->i_mode & ALLPERMS), vp, NULL, genfs_can_access(vp->v_type,
345 ip->i_mode & ALLPERMS, ip->i_uid, ip->i_gid, mode, cred));
346 }
347
348 int
349 ulfs_access(void *v)
350 {
351 struct vop_access_args /* {
352 struct vnode *a_vp;
353 int a_mode;
354 kauth_cred_t a_cred;
355 } */ *ap = v;
356 struct vnode *vp;
357 struct inode *ip;
358 mode_t mode;
359 int error;
360
361 vp = ap->a_vp;
362 ip = VTOI(vp);
363 mode = ap->a_mode;
364
365 error = ulfs_check_possible(vp, ip, mode, ap->a_cred);
366 if (error)
367 return error;
368
369 error = ulfs_check_permitted(vp, ip, mode, ap->a_cred);
370
371 return error;
372 }
373
374 /* ARGSUSED */
375 int
376 ulfs_getattr(void *v)
377 {
378 struct vop_getattr_args /* {
379 struct vnode *a_vp;
380 struct vattr *a_vap;
381 kauth_cred_t a_cred;
382 } */ *ap = v;
383 struct vnode *vp;
384 struct inode *ip;
385 struct vattr *vap;
386
387 vp = ap->a_vp;
388 ip = VTOI(vp);
389 vap = ap->a_vap;
390 fstrans_start(vp->v_mount, FSTRANS_SHARED);
391 ULFS_ITIMES(vp, NULL, NULL, NULL);
392
393 /*
394 * Copy from inode table
395 */
396 vap->va_fsid = ip->i_dev;
397 vap->va_fileid = ip->i_number;
398 vap->va_mode = ip->i_mode & ALLPERMS;
399 vap->va_nlink = ip->i_nlink;
400 vap->va_uid = ip->i_uid;
401 vap->va_gid = ip->i_gid;
402 vap->va_size = vp->v_size;
403 if (ip->i_ump->um_fstype == ULFS1) {
404 vap->va_rdev = (dev_t)ulfs_rw32(ip->i_ffs1_rdev,
405 ULFS_MPNEEDSWAP(ip->i_ump));
406 vap->va_atime.tv_sec = ip->i_ffs1_atime;
407 vap->va_atime.tv_nsec = ip->i_ffs1_atimensec;
408 vap->va_mtime.tv_sec = ip->i_ffs1_mtime;
409 vap->va_mtime.tv_nsec = ip->i_ffs1_mtimensec;
410 vap->va_ctime.tv_sec = ip->i_ffs1_ctime;
411 vap->va_ctime.tv_nsec = ip->i_ffs1_ctimensec;
412 vap->va_birthtime.tv_sec = 0;
413 vap->va_birthtime.tv_nsec = 0;
414 vap->va_bytes = dbtob((u_quad_t)ip->i_ffs1_blocks);
415 } else {
416 vap->va_rdev = (dev_t)ulfs_rw64(ip->i_ffs2_rdev,
417 ULFS_MPNEEDSWAP(ip->i_ump));
418 vap->va_atime.tv_sec = ip->i_ffs2_atime;
419 vap->va_atime.tv_nsec = ip->i_ffs2_atimensec;
420 vap->va_mtime.tv_sec = ip->i_ffs2_mtime;
421 vap->va_mtime.tv_nsec = ip->i_ffs2_mtimensec;
422 vap->va_ctime.tv_sec = ip->i_ffs2_ctime;
423 vap->va_ctime.tv_nsec = ip->i_ffs2_ctimensec;
424 vap->va_birthtime.tv_sec = ip->i_ffs2_birthtime;
425 vap->va_birthtime.tv_nsec = ip->i_ffs2_birthnsec;
426 vap->va_bytes = dbtob(ip->i_ffs2_blocks);
427 }
428 vap->va_gen = ip->i_gen;
429 vap->va_flags = ip->i_flags;
430
431 /* this doesn't belong here */
432 if (vp->v_type == VBLK)
433 vap->va_blocksize = BLKDEV_IOSIZE;
434 else if (vp->v_type == VCHR)
435 vap->va_blocksize = MAXBSIZE;
436 else
437 vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
438 vap->va_type = vp->v_type;
439 vap->va_filerev = ip->i_modrev;
440 fstrans_done(vp->v_mount);
441 return (0);
442 }
443
444 /*
445 * Set attribute vnode op. called from several syscalls
446 */
447 int
448 ulfs_setattr(void *v)
449 {
450 struct vop_setattr_args /* {
451 struct vnode *a_vp;
452 struct vattr *a_vap;
453 kauth_cred_t a_cred;
454 } */ *ap = v;
455 struct vattr *vap;
456 struct vnode *vp;
457 struct inode *ip;
458 kauth_cred_t cred;
459 struct lwp *l;
460 int error;
461 kauth_action_t action;
462 bool changing_sysflags;
463
464 vap = ap->a_vap;
465 vp = ap->a_vp;
466 ip = VTOI(vp);
467 cred = ap->a_cred;
468 l = curlwp;
469 action = KAUTH_VNODE_WRITE_FLAGS;
470 changing_sysflags = false;
471
472 /*
473 * Check for unsettable attributes.
474 */
475 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
476 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
477 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
478 ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
479 return (EINVAL);
480 }
481
482 fstrans_start(vp->v_mount, FSTRANS_SHARED);
483
484 if (vap->va_flags != VNOVAL) {
485 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
486 error = EROFS;
487 goto out;
488 }
489
490 /* Snapshot flag cannot be set or cleared */
491 if ((vap->va_flags & (SF_SNAPSHOT | SF_SNAPINVAL)) !=
492 (ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL))) {
493 error = EPERM;
494 goto out;
495 }
496
497 if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) {
498 action |= KAUTH_VNODE_HAS_SYSFLAGS;
499 }
500
501 if ((vap->va_flags & SF_SETTABLE) != (ip->i_flags & SF_SETTABLE)) {
502 action |= KAUTH_VNODE_WRITE_SYSFLAGS;
503 changing_sysflags = true;
504 }
505
506 error = kauth_authorize_vnode(cred, action, vp, NULL,
507 genfs_can_chflags(cred, vp->v_type, ip->i_uid,
508 changing_sysflags));
509 if (error)
510 goto out;
511
512 if (changing_sysflags) {
513 error = ULFS_WAPBL_BEGIN(vp->v_mount);
514 if (error)
515 goto out;
516 ip->i_flags = vap->va_flags;
517 DIP_ASSIGN(ip, flags, ip->i_flags);
518 } else {
519 error = ULFS_WAPBL_BEGIN(vp->v_mount);
520 if (error)
521 goto out;
522 ip->i_flags &= SF_SETTABLE;
523 ip->i_flags |= (vap->va_flags & UF_SETTABLE);
524 DIP_ASSIGN(ip, flags, ip->i_flags);
525 }
526 ip->i_flag |= IN_CHANGE;
527 ULFS_WAPBL_UPDATE(vp, NULL, NULL, 0);
528 ULFS_WAPBL_END(vp->v_mount);
529 if (vap->va_flags & (IMMUTABLE | APPEND)) {
530 error = 0;
531 goto out;
532 }
533 }
534 if (ip->i_flags & (IMMUTABLE | APPEND)) {
535 error = EPERM;
536 goto out;
537 }
538 /*
539 * Go through the fields and update iff not VNOVAL.
540 */
541 if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
542 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
543 error = EROFS;
544 goto out;
545 }
546 error = ULFS_WAPBL_BEGIN(vp->v_mount);
547 if (error)
548 goto out;
549 error = ulfs_chown(vp, vap->va_uid, vap->va_gid, cred, l);
550 ULFS_WAPBL_END(vp->v_mount);
551 if (error)
552 goto out;
553 }
554 if (vap->va_size != VNOVAL) {
555 /*
556 * Disallow write attempts on read-only file systems;
557 * unless the file is a socket, fifo, or a block or
558 * character device resident on the file system.
559 */
560 switch (vp->v_type) {
561 case VDIR:
562 error = EISDIR;
563 goto out;
564 case VCHR:
565 case VBLK:
566 case VFIFO:
567 break;
568 case VREG:
569 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
570 error = EROFS;
571 goto out;
572 }
573 if ((ip->i_flags & SF_SNAPSHOT) != 0) {
574 error = EPERM;
575 goto out;
576 }
577 error = ULFS_WAPBL_BEGIN(vp->v_mount);
578 if (error)
579 goto out;
580 if (!error)
581 error = ULFS_TRUNCATE(vp, vap->va_size, 0, cred);
582 ULFS_WAPBL_END(vp->v_mount);
583 if (error)
584 goto out;
585 break;
586 default:
587 error = EOPNOTSUPP;
588 goto out;
589 }
590 }
591 ip = VTOI(vp);
592 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
593 vap->va_birthtime.tv_sec != VNOVAL) {
594 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
595 error = EROFS;
596 goto out;
597 }
598 if ((ip->i_flags & SF_SNAPSHOT) != 0) {
599 error = EPERM;
600 goto out;
601 }
602 error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
603 NULL, genfs_can_chtimes(vp, vap->va_vaflags, ip->i_uid, cred));
604 if (error)
605 goto out;
606 error = ULFS_WAPBL_BEGIN(vp->v_mount);
607 if (error)
608 goto out;
609 if (vap->va_atime.tv_sec != VNOVAL)
610 if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
611 ip->i_flag |= IN_ACCESS;
612 if (vap->va_mtime.tv_sec != VNOVAL) {
613 ip->i_flag |= IN_CHANGE | IN_UPDATE;
614 if (vp->v_mount->mnt_flag & MNT_RELATIME)
615 ip->i_flag |= IN_ACCESS;
616 }
617 if (vap->va_birthtime.tv_sec != VNOVAL &&
618 ip->i_ump->um_fstype == ULFS2) {
619 ip->i_ffs2_birthtime = vap->va_birthtime.tv_sec;
620 ip->i_ffs2_birthnsec = vap->va_birthtime.tv_nsec;
621 }
622 error = ULFS_UPDATE(vp, &vap->va_atime, &vap->va_mtime, 0);
623 ULFS_WAPBL_END(vp->v_mount);
624 if (error)
625 goto out;
626 }
627 error = 0;
628 if (vap->va_mode != (mode_t)VNOVAL) {
629 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
630 error = EROFS;
631 goto out;
632 }
633 if ((ip->i_flags & SF_SNAPSHOT) != 0 &&
634 (vap->va_mode & (S_IXUSR | S_IWUSR | S_IXGRP | S_IWGRP |
635 S_IXOTH | S_IWOTH))) {
636 error = EPERM;
637 goto out;
638 }
639 error = ULFS_WAPBL_BEGIN(vp->v_mount);
640 if (error)
641 goto out;
642 error = ulfs_chmod(vp, (int)vap->va_mode, cred, l);
643 ULFS_WAPBL_END(vp->v_mount);
644 }
645 VN_KNOTE(vp, NOTE_ATTRIB);
646 out:
647 fstrans_done(vp->v_mount);
648 return (error);
649 }
650
651 /*
652 * Change the mode on a file.
653 * Inode must be locked before calling.
654 */
655 static int
656 ulfs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct lwp *l)
657 {
658 struct inode *ip;
659 int error;
660
661 ULFS_WAPBL_JLOCK_ASSERT(vp->v_mount);
662
663 ip = VTOI(vp);
664
665 error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp,
666 NULL, genfs_can_chmod(vp->v_type, cred, ip->i_uid, ip->i_gid, mode));
667 if (error)
668 return (error);
669
670 fstrans_start(vp->v_mount, FSTRANS_SHARED);
671 ip->i_mode &= ~ALLPERMS;
672 ip->i_mode |= (mode & ALLPERMS);
673 ip->i_flag |= IN_CHANGE;
674 DIP_ASSIGN(ip, mode, ip->i_mode);
675 ULFS_WAPBL_UPDATE(vp, NULL, NULL, 0);
676 fstrans_done(vp->v_mount);
677 return (0);
678 }
679
680 /*
681 * Perform chown operation on inode ip;
682 * inode must be locked prior to call.
683 */
684 static int
685 ulfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
686 struct lwp *l)
687 {
688 struct inode *ip;
689 int error = 0;
690 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
691 uid_t ouid;
692 gid_t ogid;
693 int64_t change;
694 #endif
695 ip = VTOI(vp);
696 error = 0;
697
698 if (uid == (uid_t)VNOVAL)
699 uid = ip->i_uid;
700 if (gid == (gid_t)VNOVAL)
701 gid = ip->i_gid;
702
703 error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp,
704 NULL, genfs_can_chown(cred, ip->i_uid, ip->i_gid, uid, gid));
705 if (error)
706 return (error);
707
708 fstrans_start(vp->v_mount, FSTRANS_SHARED);
709 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
710 ogid = ip->i_gid;
711 ouid = ip->i_uid;
712 change = DIP(ip, blocks);
713 (void) lfs_chkdq(ip, -change, cred, 0);
714 (void) lfs_chkiq(ip, -1, cred, 0);
715 #endif
716 ip->i_gid = gid;
717 DIP_ASSIGN(ip, gid, gid);
718 ip->i_uid = uid;
719 DIP_ASSIGN(ip, uid, uid);
720 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
721 if ((error = lfs_chkdq(ip, change, cred, 0)) == 0) {
722 if ((error = lfs_chkiq(ip, 1, cred, 0)) == 0)
723 goto good;
724 else
725 (void) lfs_chkdq(ip, -change, cred, FORCE);
726 }
727 ip->i_gid = ogid;
728 DIP_ASSIGN(ip, gid, ogid);
729 ip->i_uid = ouid;
730 DIP_ASSIGN(ip, uid, ouid);
731 (void) lfs_chkdq(ip, change, cred, FORCE);
732 (void) lfs_chkiq(ip, 1, cred, FORCE);
733 fstrans_done(vp->v_mount);
734 return (error);
735 good:
736 #endif /* LFS_QUOTA || LFS_QUOTA2 */
737 ip->i_flag |= IN_CHANGE;
738 ULFS_WAPBL_UPDATE(vp, NULL, NULL, 0);
739 fstrans_done(vp->v_mount);
740 return (0);
741 }
742
743 int
744 ulfs_remove(void *v)
745 {
746 struct vop_remove_args /* {
747 struct vnode *a_dvp;
748 struct vnode *a_vp;
749 struct componentname *a_cnp;
750 } */ *ap = v;
751 struct vnode *vp, *dvp;
752 struct inode *ip;
753 int error;
754 struct ulfs_lookup_results *ulr;
755
756 vp = ap->a_vp;
757 dvp = ap->a_dvp;
758 ip = VTOI(vp);
759
760 /* XXX should handle this material another way */
761 ulr = &VTOI(dvp)->i_crap;
762 ULFS_CHECK_CRAPCOUNTER(VTOI(dvp));
763
764 fstrans_start(dvp->v_mount, FSTRANS_SHARED);
765 if (vp->v_type == VDIR || (ip->i_flags & (IMMUTABLE | APPEND)) ||
766 (VTOI(dvp)->i_flags & APPEND))
767 error = EPERM;
768 else {
769 error = ULFS_WAPBL_BEGIN(dvp->v_mount);
770 if (error == 0) {
771 error = ulfs_dirremove(dvp, ulr,
772 ip, ap->a_cnp->cn_flags, 0);
773 ULFS_WAPBL_END(dvp->v_mount);
774 }
775 }
776 VN_KNOTE(vp, NOTE_DELETE);
777 VN_KNOTE(dvp, NOTE_WRITE);
778 if (dvp == vp)
779 vrele(vp);
780 else
781 vput(vp);
782 vput(dvp);
783 fstrans_done(dvp->v_mount);
784 return (error);
785 }
786
787 /*
788 * ulfs_link: create hard link.
789 */
790 int
791 ulfs_link(void *v)
792 {
793 struct vop_link_args /* {
794 struct vnode *a_dvp;
795 struct vnode *a_vp;
796 struct componentname *a_cnp;
797 } */ *ap = v;
798 struct vnode *dvp = ap->a_dvp;
799 struct vnode *vp = ap->a_vp;
800 struct componentname *cnp = ap->a_cnp;
801 struct inode *ip;
802 struct lfs_direct *newdir;
803 int error;
804 struct ulfs_lookup_results *ulr;
805
806 KASSERT(dvp != vp);
807 KASSERT(vp->v_type != VDIR);
808 KASSERT(dvp->v_mount == vp->v_mount);
809
810 /* XXX should handle this material another way */
811 ulr = &VTOI(dvp)->i_crap;
812 ULFS_CHECK_CRAPCOUNTER(VTOI(dvp));
813
814 fstrans_start(dvp->v_mount, FSTRANS_SHARED);
815 error = vn_lock(vp, LK_EXCLUSIVE);
816 if (error) {
817 VOP_ABORTOP(dvp, cnp);
818 goto out2;
819 }
820 ip = VTOI(vp);
821 if ((nlink_t)ip->i_nlink >= LINK_MAX) {
822 VOP_ABORTOP(dvp, cnp);
823 error = EMLINK;
824 goto out1;
825 }
826 if (ip->i_flags & (IMMUTABLE | APPEND)) {
827 VOP_ABORTOP(dvp, cnp);
828 error = EPERM;
829 goto out1;
830 }
831 error = ULFS_WAPBL_BEGIN(vp->v_mount);
832 if (error) {
833 VOP_ABORTOP(dvp, cnp);
834 goto out1;
835 }
836 ip->i_nlink++;
837 DIP_ASSIGN(ip, nlink, ip->i_nlink);
838 ip->i_flag |= IN_CHANGE;
839 error = ULFS_UPDATE(vp, NULL, NULL, UPDATE_DIROP);
840 if (!error) {
841 newdir = pool_cache_get(ulfs_direct_cache, PR_WAITOK);
842 ulfs_makedirentry(ip, cnp, newdir);
843 error = ulfs_direnter(dvp, ulr, vp, newdir, cnp, NULL);
844 pool_cache_put(ulfs_direct_cache, newdir);
845 }
846 if (error) {
847 ip->i_nlink--;
848 DIP_ASSIGN(ip, nlink, ip->i_nlink);
849 ip->i_flag |= IN_CHANGE;
850 ULFS_WAPBL_UPDATE(vp, NULL, NULL, UPDATE_DIROP);
851 }
852 ULFS_WAPBL_END(vp->v_mount);
853 out1:
854 VOP_UNLOCK(vp);
855 out2:
856 VN_KNOTE(vp, NOTE_LINK);
857 VN_KNOTE(dvp, NOTE_WRITE);
858 vput(dvp);
859 fstrans_done(dvp->v_mount);
860 return (error);
861 }
862
863 /*
864 * whiteout vnode call
865 */
866 int
867 ulfs_whiteout(void *v)
868 {
869 struct vop_whiteout_args /* {
870 struct vnode *a_dvp;
871 struct componentname *a_cnp;
872 int a_flags;
873 } */ *ap = v;
874 struct vnode *dvp = ap->a_dvp;
875 struct componentname *cnp = ap->a_cnp;
876 struct lfs_direct *newdir;
877 int error;
878 struct ulfsmount *ump = VFSTOULFS(dvp->v_mount);
879 struct ulfs_lookup_results *ulr;
880
881 /* XXX should handle this material another way */
882 ulr = &VTOI(dvp)->i_crap;
883 ULFS_CHECK_CRAPCOUNTER(VTOI(dvp));
884
885 error = 0;
886 switch (ap->a_flags) {
887 case LOOKUP:
888 /* 4.4 format directories support whiteout operations */
889 if (ump->um_maxsymlinklen > 0)
890 return (0);
891 return (EOPNOTSUPP);
892
893 case CREATE:
894 /* create a new directory whiteout */
895 fstrans_start(dvp->v_mount, FSTRANS_SHARED);
896 error = ULFS_WAPBL_BEGIN(dvp->v_mount);
897 if (error)
898 break;
899 #ifdef DIAGNOSTIC
900 if (ump->um_maxsymlinklen <= 0)
901 panic("ulfs_whiteout: old format filesystem");
902 #endif
903
904 newdir = pool_cache_get(ulfs_direct_cache, PR_WAITOK);
905 newdir->d_ino = ULFS_WINO;
906 newdir->d_namlen = cnp->cn_namelen;
907 memcpy(newdir->d_name, cnp->cn_nameptr,
908 (size_t)cnp->cn_namelen);
909 newdir->d_name[cnp->cn_namelen] = '\0';
910 newdir->d_type = LFS_DT_WHT;
911 error = ulfs_direnter(dvp, ulr, NULL, newdir, cnp, NULL);
912 pool_cache_put(ulfs_direct_cache, newdir);
913 break;
914
915 case DELETE:
916 /* remove an existing directory whiteout */
917 fstrans_start(dvp->v_mount, FSTRANS_SHARED);
918 error = ULFS_WAPBL_BEGIN(dvp->v_mount);
919 if (error)
920 break;
921 #ifdef DIAGNOSTIC
922 if (ump->um_maxsymlinklen <= 0)
923 panic("ulfs_whiteout: old format filesystem");
924 #endif
925
926 cnp->cn_flags &= ~DOWHITEOUT;
927 error = ulfs_dirremove(dvp, ulr, NULL, cnp->cn_flags, 0);
928 break;
929 default:
930 panic("ulfs_whiteout: unknown op");
931 /* NOTREACHED */
932 }
933 ULFS_WAPBL_END(dvp->v_mount);
934 fstrans_done(dvp->v_mount);
935 return (error);
936 }
937
938 int
939 ulfs_mkdir(void *v)
940 {
941 struct vop_mkdir_args /* {
942 struct vnode *a_dvp;
943 struct vnode **a_vpp;
944 struct componentname *a_cnp;
945 struct vattr *a_vap;
946 } */ *ap = v;
947 struct vnode *dvp = ap->a_dvp, *tvp;
948 struct vattr *vap = ap->a_vap;
949 struct componentname *cnp = ap->a_cnp;
950 struct inode *ip, *dp = VTOI(dvp);
951 struct buf *bp;
952 struct lfs_dirtemplate dirtemplate;
953 struct lfs_direct *newdir;
954 int error, dmode;
955 struct ulfsmount *ump = dp->i_ump;
956 int dirblksiz = ump->um_dirblksiz;
957 struct ulfs_lookup_results *ulr;
958
959 fstrans_start(dvp->v_mount, FSTRANS_SHARED);
960
961 /* XXX should handle this material another way */
962 ulr = &dp->i_crap;
963 ULFS_CHECK_CRAPCOUNTER(dp);
964
965 if ((nlink_t)dp->i_nlink >= LINK_MAX) {
966 error = EMLINK;
967 goto out;
968 }
969 dmode = vap->va_mode & ACCESSPERMS;
970 dmode |= LFS_IFDIR;
971 /*
972 * Must simulate part of ulfs_makeinode here to acquire the inode,
973 * but not have it entered in the parent directory. The entry is
974 * made later after writing "." and ".." entries.
975 */
976 if ((error = ULFS_VALLOC(dvp, dmode, cnp->cn_cred, ap->a_vpp)) != 0)
977 goto out;
978
979 tvp = *ap->a_vpp;
980 ip = VTOI(tvp);
981
982 error = ULFS_WAPBL_BEGIN(ap->a_dvp->v_mount);
983 if (error) {
984 ULFS_VFREE(tvp, ip->i_number, dmode);
985 vput(tvp);
986 goto out;
987 }
988 ip->i_uid = kauth_cred_geteuid(cnp->cn_cred);
989 DIP_ASSIGN(ip, uid, ip->i_uid);
990 ip->i_gid = dp->i_gid;
991 DIP_ASSIGN(ip, gid, ip->i_gid);
992 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
993 if ((error = lfs_chkiq(ip, 1, cnp->cn_cred, 0))) {
994 ULFS_VFREE(tvp, ip->i_number, dmode);
995 ULFS_WAPBL_END(dvp->v_mount);
996 fstrans_done(dvp->v_mount);
997 vput(tvp);
998 vput(dvp);
999 return (error);
1000 }
1001 #endif
1002 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1003 ip->i_mode = dmode;
1004 DIP_ASSIGN(ip, mode, dmode);
1005 tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */
1006 ip->i_nlink = 2;
1007 DIP_ASSIGN(ip, nlink, 2);
1008 if (cnp->cn_flags & ISWHITEOUT) {
1009 ip->i_flags |= UF_OPAQUE;
1010 DIP_ASSIGN(ip, flags, ip->i_flags);
1011 }
1012
1013 /*
1014 * Bump link count in parent directory to reflect work done below.
1015 * Should be done before reference is created so cleanup is
1016 * possible if we crash.
1017 */
1018 dp->i_nlink++;
1019 DIP_ASSIGN(dp, nlink, dp->i_nlink);
1020 dp->i_flag |= IN_CHANGE;
1021 if ((error = ULFS_UPDATE(dvp, NULL, NULL, UPDATE_DIROP)) != 0)
1022 goto bad;
1023
1024 /*
1025 * Initialize directory with "." and ".." from static template.
1026 */
1027 dirtemplate = mastertemplate;
1028 dirtemplate.dotdot_reclen = dirblksiz - dirtemplate.dot_reclen;
1029 dirtemplate.dot_ino = ulfs_rw32(ip->i_number, ULFS_MPNEEDSWAP(ump));
1030 dirtemplate.dotdot_ino = ulfs_rw32(dp->i_number, ULFS_MPNEEDSWAP(ump));
1031 dirtemplate.dot_reclen = ulfs_rw16(dirtemplate.dot_reclen,
1032 ULFS_MPNEEDSWAP(ump));
1033 dirtemplate.dotdot_reclen = ulfs_rw16(dirtemplate.dotdot_reclen,
1034 ULFS_MPNEEDSWAP(ump));
1035 if (ump->um_maxsymlinklen <= 0) {
1036 #if BYTE_ORDER == LITTLE_ENDIAN
1037 if (ULFS_MPNEEDSWAP(ump) == 0)
1038 #else
1039 if (ULFS_MPNEEDSWAP(ump) != 0)
1040 #endif
1041 {
1042 dirtemplate.dot_type = dirtemplate.dot_namlen;
1043 dirtemplate.dotdot_type = dirtemplate.dotdot_namlen;
1044 dirtemplate.dot_namlen = dirtemplate.dotdot_namlen = 0;
1045 } else
1046 dirtemplate.dot_type = dirtemplate.dotdot_type = 0;
1047 }
1048 if ((error = ULFS_BALLOC(tvp, (off_t)0, dirblksiz, cnp->cn_cred,
1049 B_CLRBUF, &bp)) != 0)
1050 goto bad;
1051 ip->i_size = dirblksiz;
1052 DIP_ASSIGN(ip, size, dirblksiz);
1053 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1054 uvm_vnp_setsize(tvp, ip->i_size);
1055 memcpy((void *)bp->b_data, (void *)&dirtemplate, sizeof dirtemplate);
1056
1057 /*
1058 * Directory set up, now install it's entry in the parent directory.
1059 * We must write out the buffer containing the new directory body
1060 * before entering the new name in the parent.
1061 */
1062 if ((error = VOP_BWRITE(bp->b_vp, bp)) != 0)
1063 goto bad;
1064 if ((error = ULFS_UPDATE(tvp, NULL, NULL, UPDATE_DIROP)) != 0) {
1065 goto bad;
1066 }
1067 newdir = pool_cache_get(ulfs_direct_cache, PR_WAITOK);
1068 ulfs_makedirentry(ip, cnp, newdir);
1069 error = ulfs_direnter(dvp, ulr, tvp, newdir, cnp, bp);
1070 pool_cache_put(ulfs_direct_cache, newdir);
1071 bad:
1072 if (error == 0) {
1073 VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1074 ULFS_WAPBL_END(dvp->v_mount);
1075 } else {
1076 dp->i_nlink--;
1077 DIP_ASSIGN(dp, nlink, dp->i_nlink);
1078 dp->i_flag |= IN_CHANGE;
1079 ULFS_WAPBL_UPDATE(dvp, NULL, NULL, UPDATE_DIROP);
1080 /*
1081 * No need to do an explicit ULFS_TRUNCATE here, vrele will
1082 * do this for us because we set the link count to 0.
1083 */
1084 ip->i_nlink = 0;
1085 DIP_ASSIGN(ip, nlink, 0);
1086 ip->i_flag |= IN_CHANGE;
1087 /* If IN_ADIROP, account for it */
1088 ULFS_UNMARK_VNODE(tvp);
1089 ULFS_WAPBL_UPDATE(tvp, NULL, NULL, UPDATE_DIROP);
1090 ULFS_WAPBL_END(dvp->v_mount);
1091 vput(tvp);
1092 }
1093 out:
1094 fstrans_done(dvp->v_mount);
1095 vput(dvp);
1096 return (error);
1097 }
1098
1099 int
1100 ulfs_rmdir(void *v)
1101 {
1102 struct vop_rmdir_args /* {
1103 struct vnode *a_dvp;
1104 struct vnode *a_vp;
1105 struct componentname *a_cnp;
1106 } */ *ap = v;
1107 struct vnode *vp, *dvp;
1108 struct componentname *cnp;
1109 struct inode *ip, *dp;
1110 int error;
1111 struct ulfs_lookup_results *ulr;
1112
1113 vp = ap->a_vp;
1114 dvp = ap->a_dvp;
1115 cnp = ap->a_cnp;
1116 ip = VTOI(vp);
1117 dp = VTOI(dvp);
1118
1119 /* XXX should handle this material another way */
1120 ulr = &dp->i_crap;
1121 ULFS_CHECK_CRAPCOUNTER(dp);
1122
1123 /*
1124 * No rmdir "." or of mounted directories please.
1125 */
1126 if (dp == ip || vp->v_mountedhere != NULL) {
1127 if (dp == ip)
1128 vrele(dvp);
1129 else
1130 vput(dvp);
1131 vput(vp);
1132 return (EINVAL);
1133 }
1134
1135 fstrans_start(dvp->v_mount, FSTRANS_SHARED);
1136
1137 /*
1138 * Do not remove a directory that is in the process of being renamed.
1139 * Verify that the directory is empty (and valid). (Rmdir ".." won't
1140 * be valid since ".." will contain a reference to the current
1141 * directory and thus be non-empty.)
1142 */
1143 error = 0;
1144 if (ip->i_nlink != 2 ||
1145 !ulfs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
1146 error = ENOTEMPTY;
1147 goto out;
1148 }
1149 if ((dp->i_flags & APPEND) ||
1150 (ip->i_flags & (IMMUTABLE | APPEND))) {
1151 error = EPERM;
1152 goto out;
1153 }
1154 error = ULFS_WAPBL_BEGIN(dvp->v_mount);
1155 if (error)
1156 goto out;
1157 /*
1158 * Delete reference to directory before purging
1159 * inode. If we crash in between, the directory
1160 * will be reattached to lost+found,
1161 */
1162 error = ulfs_dirremove(dvp, ulr, ip, cnp->cn_flags, 1);
1163 if (error) {
1164 ULFS_WAPBL_END(dvp->v_mount);
1165 goto out;
1166 }
1167 VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1168 cache_purge(dvp);
1169 /*
1170 * Truncate inode. The only stuff left in the directory is "." and
1171 * "..". The "." reference is inconsequential since we're quashing
1172 * it.
1173 */
1174 dp->i_nlink--;
1175 DIP_ASSIGN(dp, nlink, dp->i_nlink);
1176 dp->i_flag |= IN_CHANGE;
1177 ULFS_WAPBL_UPDATE(dvp, NULL, NULL, UPDATE_DIROP);
1178 ip->i_nlink--;
1179 DIP_ASSIGN(ip, nlink, ip->i_nlink);
1180 ip->i_flag |= IN_CHANGE;
1181 error = ULFS_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred);
1182 cache_purge(vp);
1183 /*
1184 * Unlock the log while we still have reference to unlinked
1185 * directory vp so that it will not get locked for recycling
1186 */
1187 ULFS_WAPBL_END(dvp->v_mount);
1188 #ifdef LFS_DIRHASH
1189 if (ip->i_dirhash != NULL)
1190 ulfsdirhash_free(ip);
1191 #endif
1192 out:
1193 VN_KNOTE(vp, NOTE_DELETE);
1194 vput(vp);
1195 fstrans_done(dvp->v_mount);
1196 vput(dvp);
1197 return (error);
1198 }
1199
1200 /*
1201 * symlink -- make a symbolic link
1202 */
1203 int
1204 ulfs_symlink(void *v)
1205 {
1206 struct vop_symlink_args /* {
1207 struct vnode *a_dvp;
1208 struct vnode **a_vpp;
1209 struct componentname *a_cnp;
1210 struct vattr *a_vap;
1211 char *a_target;
1212 } */ *ap = v;
1213 struct vnode *vp, **vpp;
1214 struct inode *ip;
1215 int len, error;
1216 struct ulfs_lookup_results *ulr;
1217
1218 vpp = ap->a_vpp;
1219
1220 /* XXX should handle this material another way */
1221 ulr = &VTOI(ap->a_dvp)->i_crap;
1222 ULFS_CHECK_CRAPCOUNTER(VTOI(ap->a_dvp));
1223
1224 /*
1225 * ULFS_WAPBL_BEGIN1(dvp->v_mount, dvp) performed by successful
1226 * ulfs_makeinode
1227 */
1228 fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED);
1229 error = ulfs_makeinode(LFS_IFLNK | ap->a_vap->va_mode, ap->a_dvp, ulr,
1230 vpp, ap->a_cnp);
1231 if (error)
1232 goto out;
1233 VN_KNOTE(ap->a_dvp, NOTE_WRITE);
1234 vp = *vpp;
1235 len = strlen(ap->a_target);
1236 ip = VTOI(vp);
1237 if (len < ip->i_ump->um_maxsymlinklen) {
1238 memcpy((char *)SHORTLINK(ip), ap->a_target, len);
1239 ip->i_size = len;
1240 DIP_ASSIGN(ip, size, len);
1241 uvm_vnp_setsize(vp, ip->i_size);
1242 ip->i_flag |= IN_CHANGE | IN_UPDATE;
1243 if (vp->v_mount->mnt_flag & MNT_RELATIME)
1244 ip->i_flag |= IN_ACCESS;
1245 ULFS_WAPBL_UPDATE(vp, NULL, NULL, 0);
1246 } else
1247 error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
1248 UIO_SYSSPACE, IO_NODELOCKED | IO_JOURNALLOCKED,
1249 ap->a_cnp->cn_cred, NULL, NULL);
1250 ULFS_WAPBL_END1(ap->a_dvp->v_mount, ap->a_dvp);
1251 if (error)
1252 vput(vp);
1253 out:
1254 fstrans_done(ap->a_dvp->v_mount);
1255 return (error);
1256 }
1257
1258 /*
1259 * Vnode op for reading directories.
1260 *
1261 * This routine handles converting from the on-disk directory format
1262 * "struct lfs_direct" to the in-memory format "struct dirent" as well as
1263 * byte swapping the entries if necessary.
1264 */
1265 int
1266 ulfs_readdir(void *v)
1267 {
1268 struct vop_readdir_args /* {
1269 struct vnode *a_vp;
1270 struct uio *a_uio;
1271 kauth_cred_t a_cred;
1272 int *a_eofflag;
1273 off_t **a_cookies;
1274 int *ncookies;
1275 } */ *ap = v;
1276 struct vnode *vp = ap->a_vp;
1277 struct lfs_direct *cdp, *ecdp;
1278 struct dirent *ndp;
1279 char *cdbuf, *ndbuf, *endp;
1280 struct uio auio, *uio;
1281 struct iovec aiov;
1282 int error;
1283 size_t count, ccount, rcount, cdbufsz, ndbufsz;
1284 off_t off, *ccp;
1285 off_t startoff;
1286 size_t skipbytes;
1287 struct ulfsmount *ump = VFSTOULFS(vp->v_mount);
1288 int nswap = ULFS_MPNEEDSWAP(ump);
1289 #if BYTE_ORDER == LITTLE_ENDIAN
1290 int needswap = ump->um_maxsymlinklen <= 0 && nswap == 0;
1291 #else
1292 int needswap = ump->um_maxsymlinklen <= 0 && nswap != 0;
1293 #endif
1294 uio = ap->a_uio;
1295 count = uio->uio_resid;
1296 rcount = count - ((uio->uio_offset + count) & (ump->um_dirblksiz - 1));
1297
1298 if (rcount < _DIRENT_MINSIZE(cdp) || count < _DIRENT_MINSIZE(ndp))
1299 return EINVAL;
1300
1301 startoff = uio->uio_offset & ~(ump->um_dirblksiz - 1);
1302 skipbytes = uio->uio_offset - startoff;
1303 rcount += skipbytes;
1304
1305 auio.uio_iov = &aiov;
1306 auio.uio_iovcnt = 1;
1307 auio.uio_offset = startoff;
1308 auio.uio_resid = rcount;
1309 UIO_SETUP_SYSSPACE(&auio);
1310 auio.uio_rw = UIO_READ;
1311 cdbufsz = rcount;
1312 cdbuf = kmem_alloc(cdbufsz, KM_SLEEP);
1313 aiov.iov_base = cdbuf;
1314 aiov.iov_len = rcount;
1315 error = VOP_READ(vp, &auio, 0, ap->a_cred);
1316 if (error != 0) {
1317 kmem_free(cdbuf, cdbufsz);
1318 return error;
1319 }
1320
1321 rcount -= auio.uio_resid;
1322
1323 cdp = (struct lfs_direct *)(void *)cdbuf;
1324 ecdp = (struct lfs_direct *)(void *)&cdbuf[rcount];
1325
1326 ndbufsz = count;
1327 ndbuf = kmem_alloc(ndbufsz, KM_SLEEP);
1328 ndp = (struct dirent *)(void *)ndbuf;
1329 endp = &ndbuf[count];
1330
1331 off = uio->uio_offset;
1332 if (ap->a_cookies) {
1333 ccount = rcount / _DIRENT_RECLEN(cdp, 1);
1334 ccp = *(ap->a_cookies) = malloc(ccount * sizeof(*ccp),
1335 M_TEMP, M_WAITOK);
1336 } else {
1337 /* XXX: GCC */
1338 ccount = 0;
1339 ccp = NULL;
1340 }
1341
1342 while (cdp < ecdp) {
1343 cdp->d_reclen = ulfs_rw16(cdp->d_reclen, nswap);
1344 if (skipbytes > 0) {
1345 if (cdp->d_reclen <= skipbytes) {
1346 skipbytes -= cdp->d_reclen;
1347 cdp = _DIRENT_NEXT(cdp);
1348 continue;
1349 }
1350 /*
1351 * invalid cookie.
1352 */
1353 error = EINVAL;
1354 goto out;
1355 }
1356 if (cdp->d_reclen == 0) {
1357 struct dirent *ondp = ndp;
1358 ndp->d_reclen = _DIRENT_MINSIZE(ndp);
1359 ndp = _DIRENT_NEXT(ndp);
1360 ondp->d_reclen = 0;
1361 cdp = ecdp;
1362 break;
1363 }
1364 if (needswap) {
1365 ndp->d_type = cdp->d_namlen;
1366 ndp->d_namlen = cdp->d_type;
1367 } else {
1368 ndp->d_type = cdp->d_type;
1369 ndp->d_namlen = cdp->d_namlen;
1370 }
1371 ndp->d_reclen = _DIRENT_RECLEN(ndp, ndp->d_namlen);
1372 if ((char *)(void *)ndp + ndp->d_reclen +
1373 _DIRENT_MINSIZE(ndp) > endp)
1374 break;
1375 ndp->d_fileno = ulfs_rw32(cdp->d_ino, nswap);
1376 (void)memcpy(ndp->d_name, cdp->d_name, ndp->d_namlen);
1377 memset(&ndp->d_name[ndp->d_namlen], 0,
1378 ndp->d_reclen - _DIRENT_NAMEOFF(ndp) - ndp->d_namlen);
1379 off += cdp->d_reclen;
1380 if (ap->a_cookies) {
1381 KASSERT(ccp - *(ap->a_cookies) < ccount);
1382 *(ccp++) = off;
1383 }
1384 ndp = _DIRENT_NEXT(ndp);
1385 cdp = _DIRENT_NEXT(cdp);
1386 }
1387
1388 count = ((char *)(void *)ndp - ndbuf);
1389 error = uiomove(ndbuf, count, uio);
1390 out:
1391 if (ap->a_cookies) {
1392 if (error) {
1393 free(*(ap->a_cookies), M_TEMP);
1394 *(ap->a_cookies) = NULL;
1395 *(ap->a_ncookies) = 0;
1396 } else {
1397 *ap->a_ncookies = ccp - *(ap->a_cookies);
1398 }
1399 }
1400 uio->uio_offset = off;
1401 kmem_free(ndbuf, ndbufsz);
1402 kmem_free(cdbuf, cdbufsz);
1403 *ap->a_eofflag = VTOI(vp)->i_size <= uio->uio_offset;
1404 return error;
1405 }
1406
1407 /*
1408 * Return target name of a symbolic link
1409 */
1410 int
1411 ulfs_readlink(void *v)
1412 {
1413 struct vop_readlink_args /* {
1414 struct vnode *a_vp;
1415 struct uio *a_uio;
1416 kauth_cred_t a_cred;
1417 } */ *ap = v;
1418 struct vnode *vp = ap->a_vp;
1419 struct inode *ip = VTOI(vp);
1420 struct ulfsmount *ump = VFSTOULFS(vp->v_mount);
1421 int isize;
1422
1423 isize = ip->i_size;
1424 if (isize < ump->um_maxsymlinklen ||
1425 (ump->um_maxsymlinklen == 0 && DIP(ip, blocks) == 0)) {
1426 uiomove((char *)SHORTLINK(ip), isize, ap->a_uio);
1427 return (0);
1428 }
1429 return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
1430 }
1431
1432 /*
1433 * Calculate the logical to physical mapping if not done already,
1434 * then call the device strategy routine.
1435 */
1436 int
1437 ulfs_strategy(void *v)
1438 {
1439 struct vop_strategy_args /* {
1440 struct vnode *a_vp;
1441 struct buf *a_bp;
1442 } */ *ap = v;
1443 struct buf *bp;
1444 struct vnode *vp;
1445 struct inode *ip;
1446 int error;
1447
1448 bp = ap->a_bp;
1449 vp = ap->a_vp;
1450 ip = VTOI(vp);
1451 if (vp->v_type == VBLK || vp->v_type == VCHR)
1452 panic("ulfs_strategy: spec");
1453 KASSERT(bp->b_bcount != 0);
1454 if (bp->b_blkno == bp->b_lblkno) {
1455 error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno,
1456 NULL);
1457 if (error) {
1458 bp->b_error = error;
1459 biodone(bp);
1460 return (error);
1461 }
1462 if (bp->b_blkno == -1) /* no valid data */
1463 clrbuf(bp);
1464 }
1465 if (bp->b_blkno < 0) { /* block is not on disk */
1466 biodone(bp);
1467 return (0);
1468 }
1469 vp = ip->i_devvp;
1470
1471 error = VOP_STRATEGY(vp, bp);
1472 if (error)
1473 return error;
1474
1475 return 0;
1476 }
1477
1478 /*
1479 * Print out the contents of an inode.
1480 */
1481 int
1482 ulfs_print(void *v)
1483 {
1484 struct vop_print_args /* {
1485 struct vnode *a_vp;
1486 } */ *ap = v;
1487 struct vnode *vp;
1488 struct inode *ip;
1489
1490 vp = ap->a_vp;
1491 ip = VTOI(vp);
1492 printf("tag VT_ULFS, ino %llu, on dev %llu, %llu",
1493 (unsigned long long)ip->i_number,
1494 (unsigned long long)major(ip->i_dev),
1495 (unsigned long long)minor(ip->i_dev));
1496 printf(" flags 0x%x, nlink %d\n",
1497 ip->i_flag, ip->i_nlink);
1498 printf("\tmode 0%o, owner %d, group %d, size %qd",
1499 ip->i_mode, ip->i_uid, ip->i_gid,
1500 (long long)ip->i_size);
1501 if (vp->v_type == VFIFO)
1502 VOCALL(fifo_vnodeop_p, VOFFSET(vop_print), v);
1503 printf("\n");
1504 return (0);
1505 }
1506
1507 /*
1508 * Read wrapper for special devices.
1509 */
1510 int
1511 ulfsspec_read(void *v)
1512 {
1513 struct vop_read_args /* {
1514 struct vnode *a_vp;
1515 struct uio *a_uio;
1516 int a_ioflag;
1517 kauth_cred_t a_cred;
1518 } */ *ap = v;
1519
1520 /*
1521 * Set access flag.
1522 */
1523 if ((ap->a_vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0)
1524 VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
1525 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap));
1526 }
1527
1528 /*
1529 * Write wrapper for special devices.
1530 */
1531 int
1532 ulfsspec_write(void *v)
1533 {
1534 struct vop_write_args /* {
1535 struct vnode *a_vp;
1536 struct uio *a_uio;
1537 int a_ioflag;
1538 kauth_cred_t a_cred;
1539 } */ *ap = v;
1540
1541 /*
1542 * Set update and change flags.
1543 */
1544 if ((ap->a_vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0)
1545 VTOI(ap->a_vp)->i_flag |= IN_MODIFY;
1546 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap));
1547 }
1548
1549 /*
1550 * Close wrapper for special devices.
1551 *
1552 * Update the times on the inode then do device close.
1553 */
1554 int
1555 ulfsspec_close(void *v)
1556 {
1557 struct vop_close_args /* {
1558 struct vnode *a_vp;
1559 int a_fflag;
1560 kauth_cred_t a_cred;
1561 } */ *ap = v;
1562 struct vnode *vp;
1563 struct inode *ip;
1564
1565 vp = ap->a_vp;
1566 ip = VTOI(vp);
1567 if (vp->v_usecount > 1)
1568 ULFS_ITIMES(vp, NULL, NULL, NULL);
1569 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap));
1570 }
1571
1572 /*
1573 * Read wrapper for fifo's
1574 */
1575 int
1576 ulfsfifo_read(void *v)
1577 {
1578 struct vop_read_args /* {
1579 struct vnode *a_vp;
1580 struct uio *a_uio;
1581 int a_ioflag;
1582 kauth_cred_t a_cred;
1583 } */ *ap = v;
1584
1585 /*
1586 * Set access flag.
1587 */
1588 VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
1589 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap));
1590 }
1591
1592 /*
1593 * Write wrapper for fifo's.
1594 */
1595 int
1596 ulfsfifo_write(void *v)
1597 {
1598 struct vop_write_args /* {
1599 struct vnode *a_vp;
1600 struct uio *a_uio;
1601 int a_ioflag;
1602 kauth_cred_t a_cred;
1603 } */ *ap = v;
1604
1605 /*
1606 * Set update and change flags.
1607 */
1608 VTOI(ap->a_vp)->i_flag |= IN_MODIFY;
1609 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap));
1610 }
1611
1612 /*
1613 * Close wrapper for fifo's.
1614 *
1615 * Update the times on the inode then do device close.
1616 */
1617 int
1618 ulfsfifo_close(void *v)
1619 {
1620 struct vop_close_args /* {
1621 struct vnode *a_vp;
1622 int a_fflag;
1623 kauth_cred_t a_cred;
1624 } */ *ap = v;
1625 struct vnode *vp;
1626 struct inode *ip;
1627
1628 vp = ap->a_vp;
1629 ip = VTOI(vp);
1630 if (ap->a_vp->v_usecount > 1)
1631 ULFS_ITIMES(vp, NULL, NULL, NULL);
1632 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_close), ap));
1633 }
1634
1635 /*
1636 * Return POSIX pathconf information applicable to ulfs filesystems.
1637 */
1638 int
1639 ulfs_pathconf(void *v)
1640 {
1641 struct vop_pathconf_args /* {
1642 struct vnode *a_vp;
1643 int a_name;
1644 register_t *a_retval;
1645 } */ *ap = v;
1646
1647 switch (ap->a_name) {
1648 case _PC_LINK_MAX:
1649 *ap->a_retval = LINK_MAX;
1650 return (0);
1651 case _PC_NAME_MAX:
1652 *ap->a_retval = LFS_MAXNAMLEN;
1653 return (0);
1654 case _PC_PATH_MAX:
1655 *ap->a_retval = PATH_MAX;
1656 return (0);
1657 case _PC_PIPE_BUF:
1658 *ap->a_retval = PIPE_BUF;
1659 return (0);
1660 case _PC_CHOWN_RESTRICTED:
1661 *ap->a_retval = 1;
1662 return (0);
1663 case _PC_NO_TRUNC:
1664 *ap->a_retval = 1;
1665 return (0);
1666 case _PC_SYNC_IO:
1667 *ap->a_retval = 1;
1668 return (0);
1669 case _PC_FILESIZEBITS:
1670 *ap->a_retval = 42;
1671 return (0);
1672 case _PC_SYMLINK_MAX:
1673 *ap->a_retval = MAXPATHLEN;
1674 return (0);
1675 case _PC_2_SYMLINKS:
1676 *ap->a_retval = 1;
1677 return (0);
1678 default:
1679 return (EINVAL);
1680 }
1681 /* NOTREACHED */
1682 }
1683
1684 /*
1685 * Advisory record locking support
1686 */
1687 int
1688 ulfs_advlock(void *v)
1689 {
1690 struct vop_advlock_args /* {
1691 struct vnode *a_vp;
1692 void * a_id;
1693 int a_op;
1694 struct flock *a_fl;
1695 int a_flags;
1696 } */ *ap = v;
1697 struct inode *ip;
1698
1699 ip = VTOI(ap->a_vp);
1700 return lf_advlock(ap, &ip->i_lockf, ip->i_size);
1701 }
1702
1703 /*
1704 * Initialize the vnode associated with a new inode, handle aliased
1705 * vnodes.
1706 */
1707 void
1708 ulfs_vinit(struct mount *mntp, int (**specops)(void *), int (**fifoops)(void *),
1709 struct vnode **vpp)
1710 {
1711 struct timeval tv;
1712 struct inode *ip;
1713 struct vnode *vp;
1714 dev_t rdev;
1715 struct ulfsmount *ump;
1716
1717 vp = *vpp;
1718 ip = VTOI(vp);
1719 switch(vp->v_type = IFTOVT(ip->i_mode)) {
1720 case VCHR:
1721 case VBLK:
1722 vp->v_op = specops;
1723 ump = ip->i_ump;
1724 if (ump->um_fstype == ULFS1)
1725 rdev = (dev_t)ulfs_rw32(ip->i_ffs1_rdev,
1726 ULFS_MPNEEDSWAP(ump));
1727 else
1728 rdev = (dev_t)ulfs_rw64(ip->i_ffs2_rdev,
1729 ULFS_MPNEEDSWAP(ump));
1730 spec_node_init(vp, rdev);
1731 break;
1732 case VFIFO:
1733 vp->v_op = fifoops;
1734 break;
1735 case VNON:
1736 case VBAD:
1737 case VSOCK:
1738 case VLNK:
1739 case VDIR:
1740 case VREG:
1741 break;
1742 }
1743 if (ip->i_number == ULFS_ROOTINO)
1744 vp->v_vflag |= VV_ROOT;
1745 /*
1746 * Initialize modrev times
1747 */
1748 getmicrouptime(&tv);
1749 ip->i_modrev = (uint64_t)(uint)tv.tv_sec << 32
1750 | tv.tv_usec * 4294u;
1751 *vpp = vp;
1752 }
1753
1754 /*
1755 * Allocate a new inode.
1756 */
1757 int
1758 ulfs_makeinode(int mode, struct vnode *dvp, const struct ulfs_lookup_results *ulr,
1759 struct vnode **vpp, struct componentname *cnp)
1760 {
1761 struct inode *ip, *pdir;
1762 struct lfs_direct *newdir;
1763 struct vnode *tvp;
1764 int error;
1765
1766 ULFS_WAPBL_JUNLOCK_ASSERT(dvp->v_mount);
1767
1768 pdir = VTOI(dvp);
1769
1770 if ((mode & LFS_IFMT) == 0)
1771 mode |= LFS_IFREG;
1772
1773 if ((error = ULFS_VALLOC(dvp, mode, cnp->cn_cred, vpp)) != 0) {
1774 vput(dvp);
1775 return (error);
1776 }
1777 tvp = *vpp;
1778 ip = VTOI(tvp);
1779 ip->i_gid = pdir->i_gid;
1780 DIP_ASSIGN(ip, gid, ip->i_gid);
1781 ip->i_uid = kauth_cred_geteuid(cnp->cn_cred);
1782 DIP_ASSIGN(ip, uid, ip->i_uid);
1783 error = ULFS_WAPBL_BEGIN1(dvp->v_mount, dvp);
1784 if (error) {
1785 /*
1786 * Note, we can't VOP_VFREE(tvp) here like we should
1787 * because we can't write to the disk. Instead, we leave
1788 * the vnode dangling from the journal.
1789 */
1790 vput(tvp);
1791 vput(dvp);
1792 return (error);
1793 }
1794 #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
1795 if ((error = lfs_chkiq(ip, 1, cnp->cn_cred, 0))) {
1796 ULFS_VFREE(tvp, ip->i_number, mode);
1797 ULFS_WAPBL_END1(dvp->v_mount, dvp);
1798 vput(tvp);
1799 vput(dvp);
1800 return (error);
1801 }
1802 #endif
1803 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1804 ip->i_mode = mode;
1805 DIP_ASSIGN(ip, mode, mode);
1806 tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */
1807 ip->i_nlink = 1;
1808 DIP_ASSIGN(ip, nlink, 1);
1809
1810 /* Authorize setting SGID if needed. */
1811 if (ip->i_mode & ISGID) {
1812 error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_WRITE_SECURITY,
1813 tvp, NULL, genfs_can_chmod(tvp->v_type, cnp->cn_cred, ip->i_uid,
1814 ip->i_gid, mode));
1815 if (error) {
1816 ip->i_mode &= ~ISGID;
1817 DIP_ASSIGN(ip, mode, ip->i_mode);
1818 }
1819 }
1820
1821 if (cnp->cn_flags & ISWHITEOUT) {
1822 ip->i_flags |= UF_OPAQUE;
1823 DIP_ASSIGN(ip, flags, ip->i_flags);
1824 }
1825
1826 /*
1827 * Make sure inode goes to disk before directory entry.
1828 */
1829 if ((error = ULFS_UPDATE(tvp, NULL, NULL, UPDATE_DIROP)) != 0)
1830 goto bad;
1831 newdir = pool_cache_get(ulfs_direct_cache, PR_WAITOK);
1832 ulfs_makedirentry(ip, cnp, newdir);
1833 error = ulfs_direnter(dvp, ulr, tvp, newdir, cnp, NULL);
1834 pool_cache_put(ulfs_direct_cache, newdir);
1835 if (error)
1836 goto bad;
1837 vput(dvp);
1838 *vpp = tvp;
1839 return (0);
1840
1841 bad:
1842 /*
1843 * Write error occurred trying to update the inode
1844 * or the directory so must deallocate the inode.
1845 */
1846 ip->i_nlink = 0;
1847 DIP_ASSIGN(ip, nlink, 0);
1848 ip->i_flag |= IN_CHANGE;
1849 /* If IN_ADIROP, account for it */
1850 ULFS_UNMARK_VNODE(tvp);
1851 ULFS_WAPBL_UPDATE(tvp, NULL, NULL, 0);
1852 tvp->v_type = VNON; /* explodes later if VBLK */
1853 ULFS_WAPBL_END1(dvp->v_mount, dvp);
1854 vput(tvp);
1855 vput(dvp);
1856 return (error);
1857 }
1858
1859 /*
1860 * Allocate len bytes at offset off.
1861 */
1862 int
1863 ulfs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags,
1864 kauth_cred_t cred)
1865 {
1866 struct inode *ip = VTOI(vp);
1867 int error, delta, bshift, bsize;
1868 UVMHIST_FUNC("ulfs_gop_alloc"); UVMHIST_CALLED(ubchist);
1869
1870 error = 0;
1871 bshift = vp->v_mount->mnt_fs_bshift;
1872 bsize = 1 << bshift;
1873
1874 delta = off & (bsize - 1);
1875 off -= delta;
1876 len += delta;
1877
1878 while (len > 0) {
1879 bsize = MIN(bsize, len);
1880
1881 error = ULFS_BALLOC(vp, off, bsize, cred, flags, NULL);
1882 if (error) {
1883 goto out;
1884 }
1885
1886 /*
1887 * increase file size now, ULFS_BALLOC() requires that
1888 * EOF be up-to-date before each call.
1889 */
1890
1891 if (ip->i_size < off + bsize) {
1892 UVMHIST_LOG(ubchist, "vp %p old 0x%x new 0x%x",
1893 vp, ip->i_size, off + bsize, 0);
1894 ip->i_size = off + bsize;
1895 DIP_ASSIGN(ip, size, ip->i_size);
1896 }
1897
1898 off += bsize;
1899 len -= bsize;
1900 }
1901
1902 out:
1903 ULFS_WAPBL_UPDATE(vp, NULL, NULL, 0);
1904 return error;
1905 }
1906
1907 void
1908 ulfs_gop_markupdate(struct vnode *vp, int flags)
1909 {
1910 u_int32_t mask = 0;
1911
1912 if ((flags & GOP_UPDATE_ACCESSED) != 0) {
1913 mask = IN_ACCESS;
1914 }
1915 if ((flags & GOP_UPDATE_MODIFIED) != 0) {
1916 if (vp->v_type == VREG) {
1917 mask |= IN_CHANGE | IN_UPDATE;
1918 } else {
1919 mask |= IN_MODIFY;
1920 }
1921 }
1922 if (mask) {
1923 struct inode *ip = VTOI(vp);
1924
1925 ip->i_flag |= mask;
1926 }
1927 }
1928