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