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