Annotation of src/sys/ufs/lfs/ulfs_vnops.c, Revision 1.55
1.55 ! thorpej 1: /* $NetBSD: ulfs_vnops.c,v 1.54 2020/09/05 16:30:13 riastradh Exp $ */
1.44 dholland 2: /* from NetBSD: ufs_vnops.c,v 1.232 2016/05/19 18:32:03 riastradh Exp */
1.1 dholland 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>
1.55 ! thorpej 70: __KERNEL_RCSID(0, "$NetBSD: ulfs_vnops.c,v 1.54 2020/09/05 16:30:13 riastradh Exp $");
1.1 dholland 71:
72: #if defined(_KERNEL_OPT)
1.3 dholland 73: #include "opt_lfs.h"
1.1 dholland 74: #include "opt_quota.h"
1.54 riastrad 75: #include "opt_uvmhist.h"
1.1 dholland 76: #endif
77:
78: #include <sys/param.h>
79: #include <sys/systm.h>
80: #include <sys/namei.h>
81: #include <sys/resourcevar.h>
82: #include <sys/kernel.h>
83: #include <sys/file.h>
84: #include <sys/stat.h>
85: #include <sys/buf.h>
86: #include <sys/proc.h>
87: #include <sys/mount.h>
88: #include <sys/vnode.h>
89: #include <sys/kmem.h>
90: #include <sys/malloc.h>
91: #include <sys/dirent.h>
92: #include <sys/lockf.h>
93: #include <sys/kauth.h>
94:
95: #include <miscfs/specfs/specdev.h>
96: #include <miscfs/fifofs/fifo.h>
97: #include <miscfs/genfs/genfs.h>
98:
1.28 dholland 99: #include <ufs/lfs/lfs_extern.h>
100: #include <ufs/lfs/lfs.h>
101: #include <ufs/lfs/lfs_accessors.h>
102:
1.2 dholland 103: #include <ufs/lfs/ulfs_inode.h>
104: #include <ufs/lfs/ulfsmount.h>
105: #include <ufs/lfs/ulfs_bswap.h>
106: #include <ufs/lfs/ulfs_extern.h>
1.3 dholland 107: #ifdef LFS_DIRHASH
1.2 dholland 108: #include <ufs/lfs/ulfs_dirhash.h>
1.1 dholland 109: #endif
110:
1.54 riastrad 111: #ifdef UVMHIST
1.1 dholland 112: #include <uvm/uvm.h>
1.54 riastrad 113: #endif
114: #include <uvm/uvm_stat.h>
1.1 dholland 115:
1.4 dholland 116: static int ulfs_chmod(struct vnode *, int, kauth_cred_t, struct lwp *);
117: static int ulfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t,
1.1 dholland 118: struct lwp *);
119:
120: /*
121: * Open called.
122: *
123: * Nothing to do.
124: */
125: /* ARGSUSED */
126: int
1.4 dholland 127: ulfs_open(void *v)
1.1 dholland 128: {
129: struct vop_open_args /* {
130: struct vnode *a_vp;
131: int a_mode;
132: kauth_cred_t a_cred;
133: } */ *ap = v;
134:
1.47 riastrad 135: KASSERT(VOP_ISLOCKED(ap->a_vp) == LK_EXCLUSIVE);
136:
1.1 dholland 137: /*
138: * Files marked append-only must be opened for appending.
139: */
140: if ((VTOI(ap->a_vp)->i_flags & APPEND) &&
141: (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
142: return (EPERM);
143: return (0);
144: }
145:
146: static int
1.53 christos 147: ulfs_check_possible(struct vnode *vp, struct inode *ip, accmode_t accmode,
1.1 dholland 148: kauth_cred_t cred)
149: {
1.3 dholland 150: #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
1.1 dholland 151: int error;
152: #endif
153:
154: /*
155: * Disallow write attempts on read-only file systems;
156: * unless the file is a socket, fifo, or a block or
157: * character device resident on the file system.
158: */
1.53 christos 159: if (accmode & VWRITE) {
1.1 dholland 160: switch (vp->v_type) {
161: case VDIR:
162: case VLNK:
163: case VREG:
164: if (vp->v_mount->mnt_flag & MNT_RDONLY)
165: return (EROFS);
1.3 dholland 166: #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
1.5 dholland 167: error = lfs_chkdq(ip, 0, cred, 0);
1.1 dholland 168: if (error != 0)
169: return error;
170: #endif
171: break;
172: case VBAD:
173: case VBLK:
174: case VCHR:
175: case VSOCK:
176: case VFIFO:
177: case VNON:
178: default:
179: break;
180: }
181: }
182:
183: /* If it is a snapshot, nobody gets access to it. */
184: if ((ip->i_flags & SF_SNAPSHOT))
185: return (EPERM);
186: /* If immutable bit set, nobody gets to write it. */
1.53 christos 187: if ((accmode & VWRITE) && (ip->i_flags & IMMUTABLE))
1.1 dholland 188: return (EPERM);
189:
190: return 0;
191: }
192:
193: static int
1.53 christos 194: ulfs_check_permitted(struct vnode *vp, struct inode *ip, accmode_t accmode,
1.1 dholland 195: kauth_cred_t cred)
196: {
197:
1.53 christos 198: return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
199: vp->v_type, ip->i_mode & ALLPERMS), vp, NULL, genfs_can_access(
200: vp, cred, ip->i_uid, ip->i_gid, ip->i_mode & ALLPERMS,
201: NULL, accmode));
1.1 dholland 202: }
203:
204: int
1.4 dholland 205: ulfs_access(void *v)
1.1 dholland 206: {
207: struct vop_access_args /* {
208: struct vnode *a_vp;
1.53 christos 209: accmode_t a_accmode;
1.1 dholland 210: kauth_cred_t a_cred;
211: } */ *ap = v;
212: struct vnode *vp;
213: struct inode *ip;
1.53 christos 214: accmode_t accmode;
1.1 dholland 215: int error;
216:
217: vp = ap->a_vp;
1.53 christos 218: accmode = ap->a_accmode;
1.47 riastrad 219:
220: KASSERT(VOP_ISLOCKED(vp));
221:
1.1 dholland 222: ip = VTOI(vp);
223:
1.53 christos 224: error = ulfs_check_possible(vp, ip, accmode, ap->a_cred);
1.1 dholland 225: if (error)
226: return error;
227:
1.53 christos 228: error = ulfs_check_permitted(vp, ip, accmode, ap->a_cred);
1.1 dholland 229:
230: return error;
231: }
232:
233: /*
234: * Set attribute vnode op. called from several syscalls
235: */
236: int
1.4 dholland 237: ulfs_setattr(void *v)
1.1 dholland 238: {
239: struct vop_setattr_args /* {
240: struct vnode *a_vp;
241: struct vattr *a_vap;
242: kauth_cred_t a_cred;
243: } */ *ap = v;
244: struct vattr *vap;
245: struct vnode *vp;
246: struct inode *ip;
1.27 dholland 247: struct lfs *fs;
1.1 dholland 248: kauth_cred_t cred;
249: struct lwp *l;
250: int error;
251: kauth_action_t action;
252: bool changing_sysflags;
253:
254: vap = ap->a_vap;
255: vp = ap->a_vp;
256: cred = ap->a_cred;
257: l = curlwp;
258: action = KAUTH_VNODE_WRITE_FLAGS;
259: changing_sysflags = false;
260:
1.47 riastrad 261: KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
262:
263: ip = VTOI(vp);
264: fs = ip->i_lfs;
265:
1.1 dholland 266: /*
267: * Check for unsettable attributes.
268: */
269: if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
270: (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
271: (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
272: ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
273: return (EINVAL);
274: }
275:
276: if (vap->va_flags != VNOVAL) {
277: if (vp->v_mount->mnt_flag & MNT_RDONLY) {
278: error = EROFS;
279: goto out;
280: }
281:
282: /* Snapshot flag cannot be set or cleared */
283: if ((vap->va_flags & (SF_SNAPSHOT | SF_SNAPINVAL)) !=
284: (ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL))) {
285: error = EPERM;
286: goto out;
287: }
288:
289: if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) {
290: action |= KAUTH_VNODE_HAS_SYSFLAGS;
291: }
292:
1.36 dholland 293: if ((vap->va_flags & SF_SETTABLE) !=
294: (ip->i_flags & SF_SETTABLE)) {
1.1 dholland 295: action |= KAUTH_VNODE_WRITE_SYSFLAGS;
296: changing_sysflags = true;
297: }
298:
299: error = kauth_authorize_vnode(cred, action, vp, NULL,
1.53 christos 300: genfs_can_chflags(vp, cred, ip->i_uid,
1.1 dholland 301: changing_sysflags));
302: if (error)
303: goto out;
304:
305: if (changing_sysflags) {
306: ip->i_flags = vap->va_flags;
307: DIP_ASSIGN(ip, flags, ip->i_flags);
308: } else {
309: ip->i_flags &= SF_SETTABLE;
310: ip->i_flags |= (vap->va_flags & UF_SETTABLE);
311: DIP_ASSIGN(ip, flags, ip->i_flags);
312: }
1.49 maya 313: ip->i_state |= IN_CHANGE;
1.1 dholland 314: if (vap->va_flags & (IMMUTABLE | APPEND)) {
315: error = 0;
316: goto out;
317: }
318: }
319: if (ip->i_flags & (IMMUTABLE | APPEND)) {
320: error = EPERM;
321: goto out;
322: }
323: /*
324: * Go through the fields and update iff not VNOVAL.
325: */
326: if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
327: if (vp->v_mount->mnt_flag & MNT_RDONLY) {
328: error = EROFS;
329: goto out;
330: }
1.4 dholland 331: error = ulfs_chown(vp, vap->va_uid, vap->va_gid, cred, l);
1.1 dholland 332: if (error)
333: goto out;
334: }
335: if (vap->va_size != VNOVAL) {
336: /*
337: * Disallow write attempts on read-only file systems;
338: * unless the file is a socket, fifo, or a block or
339: * character device resident on the file system.
340: */
341: switch (vp->v_type) {
342: case VDIR:
343: error = EISDIR;
344: goto out;
345: case VCHR:
346: case VBLK:
347: case VFIFO:
348: break;
349: case VREG:
350: if (vp->v_mount->mnt_flag & MNT_RDONLY) {
351: error = EROFS;
352: goto out;
353: }
354: if ((ip->i_flags & SF_SNAPSHOT) != 0) {
355: error = EPERM;
356: goto out;
357: }
1.17 dholland 358: error = lfs_truncate(vp, vap->va_size, 0, cred);
1.1 dholland 359: if (error)
360: goto out;
361: break;
362: default:
363: error = EOPNOTSUPP;
364: goto out;
365: }
366: }
367: ip = VTOI(vp);
368: if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
369: vap->va_birthtime.tv_sec != VNOVAL) {
370: if (vp->v_mount->mnt_flag & MNT_RDONLY) {
371: error = EROFS;
372: goto out;
373: }
374: if ((ip->i_flags & SF_SNAPSHOT) != 0) {
375: error = EPERM;
376: goto out;
377: }
378: error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
1.53 christos 379: NULL, genfs_can_chtimes(vp, cred, ip->i_uid,
380: vap->va_vaflags));
1.1 dholland 381: if (error)
382: goto out;
383: if (vap->va_atime.tv_sec != VNOVAL)
384: if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
1.49 maya 385: ip->i_state |= IN_ACCESS;
1.1 dholland 386: if (vap->va_mtime.tv_sec != VNOVAL) {
1.49 maya 387: ip->i_state |= IN_CHANGE | IN_UPDATE;
1.1 dholland 388: if (vp->v_mount->mnt_flag & MNT_RELATIME)
1.49 maya 389: ip->i_state |= IN_ACCESS;
1.1 dholland 390: }
1.27 dholland 391: if (vap->va_birthtime.tv_sec != VNOVAL) {
392: lfs_dino_setbirthtime(fs, ip->i_din,
393: &vap->va_birthtime);
1.1 dholland 394: }
1.17 dholland 395: error = lfs_update(vp, &vap->va_atime, &vap->va_mtime, 0);
1.1 dholland 396: if (error)
397: goto out;
398: }
399: error = 0;
400: if (vap->va_mode != (mode_t)VNOVAL) {
401: if (vp->v_mount->mnt_flag & MNT_RDONLY) {
402: error = EROFS;
403: goto out;
404: }
405: if ((ip->i_flags & SF_SNAPSHOT) != 0 &&
406: (vap->va_mode & (S_IXUSR | S_IWUSR | S_IXGRP | S_IWGRP |
407: S_IXOTH | S_IWOTH))) {
408: error = EPERM;
409: goto out;
410: }
1.4 dholland 411: error = ulfs_chmod(vp, (int)vap->va_mode, cred, l);
1.1 dholland 412: }
413: out:
414: return (error);
415: }
416:
417: /*
418: * Change the mode on a file.
419: * Inode must be locked before calling.
420: */
421: static int
1.4 dholland 422: ulfs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct lwp *l)
1.1 dholland 423: {
424: struct inode *ip;
425: int error;
426:
1.47 riastrad 427: KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
428:
1.1 dholland 429: ip = VTOI(vp);
430:
431: error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp,
1.53 christos 432: NULL, genfs_can_chmod(vp, cred, ip->i_uid, ip->i_gid, mode));
1.1 dholland 433: if (error)
434: return (error);
435:
436: ip->i_mode &= ~ALLPERMS;
437: ip->i_mode |= (mode & ALLPERMS);
1.49 maya 438: ip->i_state |= IN_CHANGE;
1.1 dholland 439: DIP_ASSIGN(ip, mode, ip->i_mode);
440: return (0);
441: }
442:
443: /*
444: * Perform chown operation on inode ip;
445: * inode must be locked prior to call.
446: */
447: static int
1.4 dholland 448: ulfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
1.1 dholland 449: struct lwp *l)
450: {
451: struct inode *ip;
452: int error = 0;
1.3 dholland 453: #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
1.1 dholland 454: uid_t ouid;
455: gid_t ogid;
456: int64_t change;
457: #endif
1.47 riastrad 458:
459: KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
460:
1.1 dholland 461: ip = VTOI(vp);
462: error = 0;
463:
464: if (uid == (uid_t)VNOVAL)
465: uid = ip->i_uid;
466: if (gid == (gid_t)VNOVAL)
467: gid = ip->i_gid;
468:
469: error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp,
1.53 christos 470: NULL, genfs_can_chown(vp, cred, ip->i_uid, ip->i_gid, uid, gid));
1.1 dholland 471: if (error)
472: return (error);
473:
1.3 dholland 474: #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
1.1 dholland 475: ogid = ip->i_gid;
476: ouid = ip->i_uid;
477: change = DIP(ip, blocks);
1.5 dholland 478: (void) lfs_chkdq(ip, -change, cred, 0);
479: (void) lfs_chkiq(ip, -1, cred, 0);
1.1 dholland 480: #endif
481: ip->i_gid = gid;
482: DIP_ASSIGN(ip, gid, gid);
483: ip->i_uid = uid;
484: DIP_ASSIGN(ip, uid, uid);
1.3 dholland 485: #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
1.5 dholland 486: if ((error = lfs_chkdq(ip, change, cred, 0)) == 0) {
487: if ((error = lfs_chkiq(ip, 1, cred, 0)) == 0)
1.1 dholland 488: goto good;
489: else
1.5 dholland 490: (void) lfs_chkdq(ip, -change, cred, FORCE);
1.1 dholland 491: }
492: ip->i_gid = ogid;
493: DIP_ASSIGN(ip, gid, ogid);
494: ip->i_uid = ouid;
495: DIP_ASSIGN(ip, uid, ouid);
1.5 dholland 496: (void) lfs_chkdq(ip, change, cred, FORCE);
497: (void) lfs_chkiq(ip, 1, cred, FORCE);
1.1 dholland 498: return (error);
499: good:
1.3 dholland 500: #endif /* LFS_QUOTA || LFS_QUOTA2 */
1.49 maya 501: ip->i_state |= IN_CHANGE;
1.1 dholland 502: return (0);
503: }
504:
505: int
1.4 dholland 506: ulfs_remove(void *v)
1.1 dholland 507: {
1.55 ! thorpej 508: struct vop_remove_v3_args /* {
1.1 dholland 509: struct vnode *a_dvp;
510: struct vnode *a_vp;
511: struct componentname *a_cnp;
1.55 ! thorpej 512: nlink_t ctx_vp_new_nlink;
1.1 dholland 513: } */ *ap = v;
514: struct vnode *vp, *dvp;
515: struct inode *ip;
516: int error;
1.4 dholland 517: struct ulfs_lookup_results *ulr;
1.1 dholland 518:
1.47 riastrad 519: dvp = ap->a_dvp;
1.1 dholland 520: vp = ap->a_vp;
1.47 riastrad 521:
522: KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
523: KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
524: KASSERT(dvp->v_mount == vp->v_mount);
525:
1.1 dholland 526: ip = VTOI(vp);
527:
528: /* XXX should handle this material another way */
529: ulr = &VTOI(dvp)->i_crap;
1.4 dholland 530: ULFS_CHECK_CRAPCOUNTER(VTOI(dvp));
1.1 dholland 531:
532: if (vp->v_type == VDIR || (ip->i_flags & (IMMUTABLE | APPEND)) ||
533: (VTOI(dvp)->i_flags & APPEND))
534: error = EPERM;
535: else {
1.12 dholland 536: error = ulfs_dirremove(dvp, ulr,
537: ip, ap->a_cnp->cn_flags, 0);
1.55 ! thorpej 538: if (error == 0) {
! 539: ap->ctx_vp_new_nlink = ip->i_nlink;
! 540: }
1.1 dholland 541: }
542: if (dvp == vp)
543: vrele(vp);
544: else
545: vput(vp);
546: return (error);
547: }
548:
549: /*
1.4 dholland 550: * ulfs_link: create hard link.
1.1 dholland 551: */
552: int
1.4 dholland 553: ulfs_link(void *v)
1.1 dholland 554: {
1.25 riastrad 555: struct vop_link_v2_args /* {
1.1 dholland 556: struct vnode *a_dvp;
557: struct vnode *a_vp;
558: struct componentname *a_cnp;
559: } */ *ap = v;
560: struct vnode *dvp = ap->a_dvp;
561: struct vnode *vp = ap->a_vp;
562: struct componentname *cnp = ap->a_cnp;
563: struct inode *ip;
564: int error;
1.4 dholland 565: struct ulfs_lookup_results *ulr;
1.1 dholland 566:
1.47 riastrad 567: KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
1.1 dholland 568: KASSERT(dvp != vp);
569: KASSERT(vp->v_type != VDIR);
570:
571: /* XXX should handle this material another way */
572: ulr = &VTOI(dvp)->i_crap;
1.4 dholland 573: ULFS_CHECK_CRAPCOUNTER(VTOI(dvp));
1.1 dholland 574:
575: error = vn_lock(vp, LK_EXCLUSIVE);
576: if (error) {
577: VOP_ABORTOP(dvp, cnp);
578: goto out2;
579: }
1.47 riastrad 580: if (vp->v_mount != dvp->v_mount) {
581: error = ENOENT;
582: VOP_ABORTOP(dvp, cnp);
583: goto out2;
584: }
1.1 dholland 585: ip = VTOI(vp);
586: if ((nlink_t)ip->i_nlink >= LINK_MAX) {
587: VOP_ABORTOP(dvp, cnp);
588: error = EMLINK;
589: goto out1;
590: }
591: if (ip->i_flags & (IMMUTABLE | APPEND)) {
592: VOP_ABORTOP(dvp, cnp);
593: error = EPERM;
594: goto out1;
595: }
596: ip->i_nlink++;
597: DIP_ASSIGN(ip, nlink, ip->i_nlink);
1.49 maya 598: ip->i_state |= IN_CHANGE;
1.17 dholland 599: error = lfs_update(vp, NULL, NULL, UPDATE_DIROP);
1.1 dholland 600: if (!error) {
1.30 dholland 601: error = ulfs_direnter(dvp, ulr, vp,
602: cnp, ip->i_number, LFS_IFTODT(ip->i_mode), NULL);
1.1 dholland 603: }
604: if (error) {
605: ip->i_nlink--;
606: DIP_ASSIGN(ip, nlink, ip->i_nlink);
1.49 maya 607: ip->i_state |= IN_CHANGE;
1.1 dholland 608: }
609: out1:
610: VOP_UNLOCK(vp);
611: out2:
612: return (error);
613: }
614:
615: /*
616: * whiteout vnode call
617: */
618: int
1.4 dholland 619: ulfs_whiteout(void *v)
1.1 dholland 620: {
621: struct vop_whiteout_args /* {
622: struct vnode *a_dvp;
623: struct componentname *a_cnp;
624: int a_flags;
625: } */ *ap = v;
626: struct vnode *dvp = ap->a_dvp;
627: struct componentname *cnp = ap->a_cnp;
628: int error;
1.4 dholland 629: struct ulfsmount *ump = VFSTOULFS(dvp->v_mount);
1.18 dholland 630: struct lfs *fs = ump->um_lfs;
1.4 dholland 631: struct ulfs_lookup_results *ulr;
1.1 dholland 632:
1.47 riastrad 633: KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
634:
1.1 dholland 635: /* XXX should handle this material another way */
636: ulr = &VTOI(dvp)->i_crap;
1.4 dholland 637: ULFS_CHECK_CRAPCOUNTER(VTOI(dvp));
1.1 dholland 638:
639: error = 0;
640: switch (ap->a_flags) {
641: case LOOKUP:
642: /* 4.4 format directories support whiteout operations */
1.18 dholland 643: if (fs->um_maxsymlinklen > 0)
1.1 dholland 644: return (0);
645: return (EOPNOTSUPP);
646:
647: case CREATE:
648: /* create a new directory whiteout */
1.45 riastrad 649: KASSERTMSG((fs->um_maxsymlinklen > 0),
650: "ulfs_whiteout: old format filesystem");
1.1 dholland 651:
1.30 dholland 652: error = ulfs_direnter(dvp, ulr, NULL,
653: cnp, ULFS_WINO, LFS_DT_WHT, NULL);
1.1 dholland 654: break;
655:
656: case DELETE:
657: /* remove an existing directory whiteout */
1.45 riastrad 658: KASSERTMSG((fs->um_maxsymlinklen > 0),
659: "ulfs_whiteout: old format filesystem");
1.1 dholland 660:
661: cnp->cn_flags &= ~DOWHITEOUT;
1.4 dholland 662: error = ulfs_dirremove(dvp, ulr, NULL, cnp->cn_flags, 0);
1.1 dholland 663: break;
664: default:
1.4 dholland 665: panic("ulfs_whiteout: unknown op");
1.1 dholland 666: /* NOTREACHED */
667: }
668: return (error);
669: }
670:
671: int
1.4 dholland 672: ulfs_rmdir(void *v)
1.1 dholland 673: {
1.48 riastrad 674: struct vop_rmdir_v2_args /* {
1.1 dholland 675: struct vnode *a_dvp;
676: struct vnode *a_vp;
677: struct componentname *a_cnp;
678: } */ *ap = v;
679: struct vnode *vp, *dvp;
680: struct componentname *cnp;
681: struct inode *ip, *dp;
682: int error;
1.4 dholland 683: struct ulfs_lookup_results *ulr;
1.1 dholland 684:
1.47 riastrad 685: dvp = ap->a_dvp;
1.1 dholland 686: vp = ap->a_vp;
687: cnp = ap->a_cnp;
1.47 riastrad 688:
689: KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
690: KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
691:
692: dp = VTOI(dvp);
1.1 dholland 693: ip = VTOI(vp);
694:
695: /* XXX should handle this material another way */
696: ulr = &dp->i_crap;
1.4 dholland 697: ULFS_CHECK_CRAPCOUNTER(dp);
1.1 dholland 698:
699: /*
700: * No rmdir "." or of mounted directories please.
701: */
702: if (dp == ip || vp->v_mountedhere != NULL) {
703: if (dp == ip)
1.48 riastrad 704: vrele(vp);
1.1 dholland 705: else
1.48 riastrad 706: vput(vp);
1.1 dholland 707: return (EINVAL);
708: }
709:
710: /*
711: * Do not remove a directory that is in the process of being renamed.
712: * Verify that the directory is empty (and valid). (Rmdir ".." won't
713: * be valid since ".." will contain a reference to the current
714: * directory and thus be non-empty.)
715: */
716: error = 0;
717: if (ip->i_nlink != 2 ||
1.4 dholland 718: !ulfs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
1.1 dholland 719: error = ENOTEMPTY;
720: goto out;
721: }
722: if ((dp->i_flags & APPEND) ||
723: (ip->i_flags & (IMMUTABLE | APPEND))) {
724: error = EPERM;
725: goto out;
726: }
727: /*
728: * Delete reference to directory before purging
729: * inode. If we crash in between, the directory
730: * will be reattached to lost+found,
731: */
1.4 dholland 732: error = ulfs_dirremove(dvp, ulr, ip, cnp->cn_flags, 1);
1.1 dholland 733: if (error) {
734: goto out;
735: }
736: cache_purge(dvp);
737: /*
738: * Truncate inode. The only stuff left in the directory is "." and
739: * "..". The "." reference is inconsequential since we're quashing
740: * it.
741: */
742: dp->i_nlink--;
743: DIP_ASSIGN(dp, nlink, dp->i_nlink);
1.49 maya 744: dp->i_state |= IN_CHANGE;
1.1 dholland 745: ip->i_nlink--;
746: DIP_ASSIGN(ip, nlink, ip->i_nlink);
1.49 maya 747: ip->i_state |= IN_CHANGE;
1.17 dholland 748: error = lfs_truncate(vp, (off_t)0, IO_SYNC, cnp->cn_cred);
1.1 dholland 749: cache_purge(vp);
1.3 dholland 750: #ifdef LFS_DIRHASH
1.1 dholland 751: if (ip->i_dirhash != NULL)
1.4 dholland 752: ulfsdirhash_free(ip);
1.1 dholland 753: #endif
754: out:
755: vput(vp);
756: return (error);
757: }
758:
759: /*
760: * Vnode op for reading directories.
761: *
762: * This routine handles converting from the on-disk directory format
1.8 dholland 763: * "struct lfs_direct" to the in-memory format "struct dirent" as well as
1.1 dholland 764: * byte swapping the entries if necessary.
765: */
766: int
1.4 dholland 767: ulfs_readdir(void *v)
1.1 dholland 768: {
769: struct vop_readdir_args /* {
770: struct vnode *a_vp;
771: struct uio *a_uio;
772: kauth_cred_t a_cred;
773: int *a_eofflag;
774: off_t **a_cookies;
1.51 dholland 775: int *a_ncookies;
1.1 dholland 776: } */ *ap = v;
1.51 dholland 777:
778: /* vnode and fs */
1.1 dholland 779: struct vnode *vp = ap->a_vp;
1.4 dholland 780: struct ulfsmount *ump = VFSTOULFS(vp->v_mount);
1.18 dholland 781: struct lfs *fs = ump->um_lfs;
1.51 dholland 782: /* caller's buffer */
783: struct uio *calleruio = ap->a_uio;
784: off_t startoffset, endoffset;
785: size_t callerbytes;
786: off_t curoffset;
787: /* dirent production buffer */
788: char *direntbuf;
789: size_t direntbufmax;
790: struct dirent *dirent, *stopdirent;
791: /* output cookies array */
792: off_t *cookies;
793: size_t numcookies, maxcookies;
794: /* disk buffer */
795: off_t physstart, physend;
796: size_t skipstart, dropend;
797: char *rawbuf;
798: size_t rawbufmax, rawbytes;
799: struct uio rawuio;
800: struct iovec rawiov;
801: LFS_DIRHEADER *rawdp, *stoprawdp;
802: /* general */
803: int error;
1.47 riastrad 804:
805: KASSERT(VOP_ISLOCKED(vp));
806:
1.51 dholland 807: /* figure out where we want to read */
808: callerbytes = calleruio->uio_resid;
809: startoffset = calleruio->uio_offset;
810: endoffset = startoffset + callerbytes;
1.1 dholland 811:
1.51 dholland 812: if (callerbytes < _DIRENT_MINSIZE(dirent)) {
813: /* no room for even one struct dirent */
1.1 dholland 814: return EINVAL;
1.51 dholland 815: }
1.1 dholland 816:
1.51 dholland 817: /* round start and end down to block boundaries */
818: physstart = startoffset & ~(off_t)(fs->um_dirblksiz - 1);
819: physend = endoffset & ~(off_t)(fs->um_dirblksiz - 1);
820: skipstart = startoffset - physstart;
821: dropend = endoffset - physend;
822:
823: if (callerbytes - dropend < LFS_DIRECTSIZ(fs, 0)) {
824: /* no room for even one dirheader + name */
825: return EINVAL;
826: }
827:
828: /* how much to actually read */
829: rawbufmax = callerbytes + skipstart - dropend;
830:
831: /* read it */
832: rawbuf = kmem_alloc(rawbufmax, KM_SLEEP);
833: rawiov.iov_base = rawbuf;
834: rawiov.iov_len = rawbufmax;
835: rawuio.uio_iov = &rawiov;
836: rawuio.uio_iovcnt = 1;
837: rawuio.uio_offset = physstart;
838: rawuio.uio_resid = rawbufmax;
839: UIO_SETUP_SYSSPACE(&rawuio);
840: rawuio.uio_rw = UIO_READ;
841: error = VOP_READ(vp, &rawuio, 0, ap->a_cred);
1.1 dholland 842: if (error != 0) {
1.51 dholland 843: kmem_free(rawbuf, rawbufmax);
1.1 dholland 844: return error;
845: }
1.51 dholland 846: rawbytes = rawbufmax - rawuio.uio_resid;
1.1 dholland 847:
1.51 dholland 848: /* the raw entries to iterate over */
849: rawdp = (LFS_DIRHEADER *)(void *)rawbuf;
850: stoprawdp = (LFS_DIRHEADER *)(void *)&rawbuf[rawbytes];
1.1 dholland 851:
1.51 dholland 852: /* allocate space to produce dirents into */
853: direntbufmax = callerbytes;
854: direntbuf = kmem_alloc(direntbufmax, KM_SLEEP);
1.1 dholland 855:
1.51 dholland 856: /* the dirents to iterate over */
857: dirent = (struct dirent *)(void *)direntbuf;
858: stopdirent = (struct dirent *)(void *)&direntbuf[direntbufmax];
1.1 dholland 859:
1.51 dholland 860: /* the output "cookies" (seek positions of directory entries) */
1.1 dholland 861: if (ap->a_cookies) {
1.51 dholland 862: numcookies = 0;
863: maxcookies = rawbytes / LFS_DIRECTSIZ(fs, 1);
864: cookies = malloc(maxcookies * sizeof(*cookies),
1.1 dholland 865: M_TEMP, M_WAITOK);
866: } else {
867: /* XXX: GCC */
1.51 dholland 868: maxcookies = 0;
869: cookies = NULL;
1.1 dholland 870: }
871:
1.51 dholland 872: /* now produce the dirents */
873: curoffset = calleruio->uio_offset;
874: while (rawdp < stoprawdp) {
875: if (skipstart > 0) {
876: /* drain skipstart */
877: if (lfs_dir_getreclen(fs, rawdp) <= skipstart) {
878: skipstart -= lfs_dir_getreclen(fs, rawdp);
879: rawdp = LFS_NEXTDIR(fs, rawdp);
1.1 dholland 880: continue;
881: }
1.51 dholland 882: /* caller's start position wasn't on an entry */
1.1 dholland 883: error = EINVAL;
884: goto out;
885: }
1.51 dholland 886: if (lfs_dir_getreclen(fs, rawdp) == 0) {
887: struct dirent *save = dirent;
888: dirent->d_reclen = _DIRENT_MINSIZE(dirent);
889: dirent = _DIRENT_NEXT(dirent);
890: save->d_reclen = 0;
891: rawdp = stoprawdp;
1.1 dholland 892: break;
893: }
1.51 dholland 894:
895: /* copy the header */
896: dirent->d_type = lfs_dir_gettype(fs, rawdp);
897: dirent->d_namlen = lfs_dir_getnamlen(fs, rawdp);
898: dirent->d_reclen = _DIRENT_RECLEN(dirent, dirent->d_namlen);
899:
900: /* stop if there isn't room for the name AND another header */
901: if ((char *)(void *)dirent + dirent->d_reclen +
902: _DIRENT_MINSIZE(dirent) > (char *)(void *)stopdirent)
1.1 dholland 903: break;
1.51 dholland 904:
905: /* copy the name (and inode (XXX: why after the test?)) */
906: dirent->d_fileno = lfs_dir_getino(fs, rawdp);
907: (void)memcpy(dirent->d_name, lfs_dir_nameptr(fs, rawdp),
908: dirent->d_namlen);
909: memset(&dirent->d_name[dirent->d_namlen], 0,
910: dirent->d_reclen - _DIRENT_NAMEOFF(dirent)
911: - dirent->d_namlen);
912:
913: /* onward */
914: curoffset += lfs_dir_getreclen(fs, rawdp);
1.1 dholland 915: if (ap->a_cookies) {
1.51 dholland 916: KASSERT(numcookies < maxcookies);
917: cookies[numcookies++] = curoffset;
1.1 dholland 918: }
1.51 dholland 919: dirent = _DIRENT_NEXT(dirent);
920: rawdp = LFS_NEXTDIR(fs, rawdp);
1.1 dholland 921: }
922:
1.51 dholland 923: /* transfer the dirents to the caller's buffer */
924: callerbytes = ((char *)(void *)dirent - direntbuf);
925: error = uiomove(direntbuf, callerbytes, calleruio);
926:
1.1 dholland 927: out:
1.51 dholland 928: calleruio->uio_offset = curoffset;
1.1 dholland 929: if (ap->a_cookies) {
930: if (error) {
1.51 dholland 931: free(cookies, M_TEMP);
932: *ap->a_cookies = NULL;
933: *ap->a_ncookies = 0;
1.1 dholland 934: } else {
1.51 dholland 935: *ap->a_cookies = cookies;
936: *ap->a_ncookies = numcookies;
1.1 dholland 937: }
938: }
1.51 dholland 939: kmem_free(direntbuf, direntbufmax);
940: kmem_free(rawbuf, rawbufmax);
941: *ap->a_eofflag = VTOI(vp)->i_size <= calleruio->uio_offset;
1.1 dholland 942: return error;
943: }
944:
945: /*
946: * Return target name of a symbolic link
947: */
948: int
1.4 dholland 949: ulfs_readlink(void *v)
1.1 dholland 950: {
951: struct vop_readlink_args /* {
952: struct vnode *a_vp;
953: struct uio *a_uio;
954: kauth_cred_t a_cred;
955: } */ *ap = v;
956: struct vnode *vp = ap->a_vp;
957: struct inode *ip = VTOI(vp);
1.4 dholland 958: struct ulfsmount *ump = VFSTOULFS(vp->v_mount);
1.18 dholland 959: struct lfs *fs = ump->um_lfs;
1.1 dholland 960: int isize;
961:
1.47 riastrad 962: KASSERT(VOP_ISLOCKED(vp));
963:
1.37 dholland 964: /*
965: * The test against um_maxsymlinklen is off by one; it should
966: * theoretically be <=, not <. However, it cannot be changed
967: * as that would break compatibility with existing fs images.
968: */
969:
1.1 dholland 970: isize = ip->i_size;
1.18 dholland 971: if (isize < fs->um_maxsymlinklen ||
972: (fs->um_maxsymlinklen == 0 && DIP(ip, blocks) == 0)) {
1.1 dholland 973: uiomove((char *)SHORTLINK(ip), isize, ap->a_uio);
974: return (0);
975: }
1.22 riastrad 976: return (lfs_bufrd(vp, ap->a_uio, 0, ap->a_cred));
1.1 dholland 977: }
978:
979: /*
980: * Print out the contents of an inode.
981: */
982: int
1.4 dholland 983: ulfs_print(void *v)
1.1 dholland 984: {
985: struct vop_print_args /* {
986: struct vnode *a_vp;
987: } */ *ap = v;
988: struct vnode *vp;
989: struct inode *ip;
990:
991: vp = ap->a_vp;
992: ip = VTOI(vp);
1.4 dholland 993: printf("tag VT_ULFS, ino %llu, on dev %llu, %llu",
1.1 dholland 994: (unsigned long long)ip->i_number,
995: (unsigned long long)major(ip->i_dev),
996: (unsigned long long)minor(ip->i_dev));
997: printf(" flags 0x%x, nlink %d\n",
1.49 maya 998: ip->i_state, ip->i_nlink);
1.1 dholland 999: printf("\tmode 0%o, owner %d, group %d, size %qd",
1000: ip->i_mode, ip->i_uid, ip->i_gid,
1001: (long long)ip->i_size);
1002: if (vp->v_type == VFIFO)
1003: VOCALL(fifo_vnodeop_p, VOFFSET(vop_print), v);
1004: printf("\n");
1005: return (0);
1006: }
1007:
1008: /*
1009: * Read wrapper for special devices.
1010: */
1011: int
1.4 dholland 1012: ulfsspec_read(void *v)
1.1 dholland 1013: {
1014: struct vop_read_args /* {
1015: struct vnode *a_vp;
1016: struct uio *a_uio;
1017: int a_ioflag;
1018: kauth_cred_t a_cred;
1019: } */ *ap = v;
1020:
1.47 riastrad 1021: KASSERT(VOP_ISLOCKED(ap->a_vp));
1022:
1.1 dholland 1023: /*
1024: * Set access flag.
1025: */
1026: if ((ap->a_vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0)
1.49 maya 1027: VTOI(ap->a_vp)->i_state |= IN_ACCESS;
1.1 dholland 1028: return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap));
1029: }
1030:
1031: /*
1032: * Write wrapper for special devices.
1033: */
1034: int
1.4 dholland 1035: ulfsspec_write(void *v)
1.1 dholland 1036: {
1037: struct vop_write_args /* {
1038: struct vnode *a_vp;
1039: struct uio *a_uio;
1040: int a_ioflag;
1041: kauth_cred_t a_cred;
1042: } */ *ap = v;
1043:
1.47 riastrad 1044: KASSERT(VOP_ISLOCKED(ap->a_vp) == LK_EXCLUSIVE);
1045:
1.1 dholland 1046: /*
1047: * Set update and change flags.
1048: */
1049: if ((ap->a_vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0)
1.49 maya 1050: VTOI(ap->a_vp)->i_state |= IN_MODIFY;
1.1 dholland 1051: return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap));
1052: }
1053:
1054: /*
1055: * Read wrapper for fifo's
1056: */
1057: int
1.4 dholland 1058: ulfsfifo_read(void *v)
1.1 dholland 1059: {
1060: struct vop_read_args /* {
1061: struct vnode *a_vp;
1062: struct uio *a_uio;
1063: int a_ioflag;
1064: kauth_cred_t a_cred;
1065: } */ *ap = v;
1066:
1.47 riastrad 1067: KASSERT(VOP_ISLOCKED(ap->a_vp));
1068:
1.1 dholland 1069: /*
1070: * Set access flag.
1071: */
1.49 maya 1072: VTOI(ap->a_vp)->i_state |= IN_ACCESS;
1.1 dholland 1073: return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap));
1074: }
1075:
1076: /*
1077: * Write wrapper for fifo's.
1078: */
1079: int
1.4 dholland 1080: ulfsfifo_write(void *v)
1.1 dholland 1081: {
1082: struct vop_write_args /* {
1083: struct vnode *a_vp;
1084: struct uio *a_uio;
1085: int a_ioflag;
1086: kauth_cred_t a_cred;
1087: } */ *ap = v;
1088:
1.47 riastrad 1089: KASSERT(VOP_ISLOCKED(ap->a_vp) == LK_EXCLUSIVE);
1090:
1.1 dholland 1091: /*
1092: * Set update and change flags.
1093: */
1.49 maya 1094: VTOI(ap->a_vp)->i_state |= IN_MODIFY;
1.1 dholland 1095: return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap));
1096: }
1097:
1098: /*
1.4 dholland 1099: * Return POSIX pathconf information applicable to ulfs filesystems.
1.1 dholland 1100: */
1101: int
1.4 dholland 1102: ulfs_pathconf(void *v)
1.1 dholland 1103: {
1104: struct vop_pathconf_args /* {
1105: struct vnode *a_vp;
1106: int a_name;
1107: register_t *a_retval;
1108: } */ *ap = v;
1109:
1110: switch (ap->a_name) {
1111: case _PC_LINK_MAX:
1112: *ap->a_retval = LINK_MAX;
1113: return (0);
1114: case _PC_NAME_MAX:
1.6 dholland 1115: *ap->a_retval = LFS_MAXNAMLEN;
1.1 dholland 1116: return (0);
1117: case _PC_PATH_MAX:
1118: *ap->a_retval = PATH_MAX;
1119: return (0);
1120: case _PC_PIPE_BUF:
1121: *ap->a_retval = PIPE_BUF;
1122: return (0);
1123: case _PC_CHOWN_RESTRICTED:
1124: *ap->a_retval = 1;
1125: return (0);
1126: case _PC_NO_TRUNC:
1127: *ap->a_retval = 1;
1128: return (0);
1129: case _PC_SYNC_IO:
1130: *ap->a_retval = 1;
1131: return (0);
1132: case _PC_FILESIZEBITS:
1133: *ap->a_retval = 42;
1134: return (0);
1135: case _PC_SYMLINK_MAX:
1136: *ap->a_retval = MAXPATHLEN;
1137: return (0);
1138: case _PC_2_SYMLINKS:
1139: *ap->a_retval = 1;
1140: return (0);
1141: default:
1142: return (EINVAL);
1143: }
1144: /* NOTREACHED */
1145: }
1146:
1147: /*
1148: * Advisory record locking support
1149: */
1150: int
1.4 dholland 1151: ulfs_advlock(void *v)
1.1 dholland 1152: {
1153: struct vop_advlock_args /* {
1154: struct vnode *a_vp;
1155: void * a_id;
1156: int a_op;
1157: struct flock *a_fl;
1158: int a_flags;
1159: } */ *ap = v;
1160: struct inode *ip;
1161:
1162: ip = VTOI(ap->a_vp);
1163: return lf_advlock(ap, &ip->i_lockf, ip->i_size);
1164: }
1165:
1166: /*
1167: * Initialize the vnode associated with a new inode, handle aliased
1168: * vnodes.
1169: */
1170: void
1.4 dholland 1171: ulfs_vinit(struct mount *mntp, int (**specops)(void *), int (**fifoops)(void *),
1.1 dholland 1172: struct vnode **vpp)
1173: {
1174: struct timeval tv;
1175: struct inode *ip;
1176: struct vnode *vp;
1177: dev_t rdev;
1.4 dholland 1178: struct ulfsmount *ump;
1.1 dholland 1179:
1180: vp = *vpp;
1181: ip = VTOI(vp);
1182: switch(vp->v_type = IFTOVT(ip->i_mode)) {
1183: case VCHR:
1184: case VBLK:
1185: vp->v_op = specops;
1186: ump = ip->i_ump;
1.27 dholland 1187: // XXX clean this up
1.4 dholland 1188: if (ump->um_fstype == ULFS1)
1.27 dholland 1189: rdev = (dev_t)ulfs_rw32(ip->i_din->u_32.di_rdev,
1.18 dholland 1190: ULFS_MPNEEDSWAP(ump->um_lfs));
1.1 dholland 1191: else
1.27 dholland 1192: rdev = (dev_t)ulfs_rw64(ip->i_din->u_64.di_rdev,
1.18 dholland 1193: ULFS_MPNEEDSWAP(ump->um_lfs));
1.1 dholland 1194: spec_node_init(vp, rdev);
1195: break;
1196: case VFIFO:
1197: vp->v_op = fifoops;
1198: break;
1199: case VNON:
1200: case VBAD:
1201: case VSOCK:
1202: case VLNK:
1203: case VDIR:
1204: case VREG:
1205: break;
1206: }
1.4 dholland 1207: if (ip->i_number == ULFS_ROOTINO)
1.1 dholland 1208: vp->v_vflag |= VV_ROOT;
1209: /*
1210: * Initialize modrev times
1211: */
1212: getmicrouptime(&tv);
1213: ip->i_modrev = (uint64_t)(uint)tv.tv_sec << 32
1214: | tv.tv_usec * 4294u;
1215: *vpp = vp;
1216: }
1217:
1218: /*
1219: * Allocate len bytes at offset off.
1220: */
1221: int
1.4 dholland 1222: ulfs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags,
1.1 dholland 1223: kauth_cred_t cred)
1224: {
1225: struct inode *ip = VTOI(vp);
1226: int error, delta, bshift, bsize;
1.4 dholland 1227: UVMHIST_FUNC("ulfs_gop_alloc"); UVMHIST_CALLED(ubchist);
1.1 dholland 1228:
1.47 riastrad 1229: KASSERT(genfs_node_wrlocked(vp));
1230:
1.1 dholland 1231: error = 0;
1232: bshift = vp->v_mount->mnt_fs_bshift;
1233: bsize = 1 << bshift;
1234:
1235: delta = off & (bsize - 1);
1236: off -= delta;
1237: len += delta;
1238:
1239: while (len > 0) {
1240: bsize = MIN(bsize, len);
1241:
1.17 dholland 1242: error = lfs_balloc(vp, off, bsize, cred, flags, NULL);
1.1 dholland 1243: if (error) {
1244: goto out;
1245: }
1246:
1247: /*
1.17 dholland 1248: * increase file size now, lfs_balloc() requires that
1.1 dholland 1249: * EOF be up-to-date before each call.
1250: */
1251:
1252: if (ip->i_size < off + bsize) {
1.52 pgoyette 1253: UVMHIST_LOG(ubchist, "vp %#jx old 0x%jx new 0x%jx",
1254: (uintptr_t)vp, ip->i_size, off + bsize, 0);
1.1 dholland 1255: ip->i_size = off + bsize;
1256: DIP_ASSIGN(ip, size, ip->i_size);
1257: }
1258:
1259: off += bsize;
1260: len -= bsize;
1261: }
1262:
1263: out:
1264: return error;
1265: }
1266:
1267: void
1.4 dholland 1268: ulfs_gop_markupdate(struct vnode *vp, int flags)
1.1 dholland 1269: {
1270: u_int32_t mask = 0;
1271:
1272: if ((flags & GOP_UPDATE_ACCESSED) != 0) {
1273: mask = IN_ACCESS;
1274: }
1275: if ((flags & GOP_UPDATE_MODIFIED) != 0) {
1276: if (vp->v_type == VREG) {
1277: mask |= IN_CHANGE | IN_UPDATE;
1278: } else {
1279: mask |= IN_MODIFY;
1280: }
1281: }
1282: if (mask) {
1283: struct inode *ip = VTOI(vp);
1284:
1.49 maya 1285: ip->i_state |= mask;
1.1 dholland 1286: }
1287: }
1.22 riastrad 1288:
1289: int
1290: ulfs_bufio(enum uio_rw rw, struct vnode *vp, void *buf, size_t len, off_t off,
1291: int ioflg, kauth_cred_t cred, size_t *aresid, struct lwp *l)
1292: {
1293: struct iovec iov;
1294: struct uio uio;
1295: int error;
1296:
1.23 riastrad 1297: KASSERT(ISSET(ioflg, IO_NODELOCKED));
1298: KASSERT(VOP_ISLOCKED(vp));
1299: KASSERT(rw != UIO_WRITE || VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
1.22 riastrad 1300:
1301: iov.iov_base = buf;
1302: iov.iov_len = len;
1303: uio.uio_iov = &iov;
1304: uio.uio_iovcnt = 1;
1305: uio.uio_resid = len;
1306: uio.uio_offset = off;
1307: uio.uio_rw = rw;
1308: UIO_SETUP_SYSSPACE(&uio);
1309:
1310: switch (rw) {
1311: case UIO_READ:
1312: error = lfs_bufrd(vp, &uio, ioflg, cred);
1313: break;
1314: case UIO_WRITE:
1315: error = lfs_bufwr(vp, &uio, ioflg, cred);
1316: break;
1317: default:
1318: panic("invalid uio rw: %d", (int)rw);
1319: }
1320:
1321: if (aresid)
1322: *aresid = uio.uio_resid;
1323: else if (uio.uio_resid && error == 0)
1324: error = EIO;
1325:
1.23 riastrad 1326: KASSERT(VOP_ISLOCKED(vp));
1327: KASSERT(rw != UIO_WRITE || VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
1.22 riastrad 1328: return error;
1329: }
CVSweb <webmaster@jp.NetBSD.org>