Annotation of src/sys/ufs/ufs/ufs_vnops.c, Revision 1.169.6.3
1.169.6.3! christos 1: /* $NetBSD: ufs_vnops.c,v 1.169.6.2 2008/11/20 20:45:40 christos Exp $ */
1.169.6.2 christos 2:
3: /*-
4: * Copyright (c) 2008 The NetBSD Foundation, Inc.
5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Wasabi Systems, Inc.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29: * POSSIBILITY OF SUCH DAMAGE.
30: */
31:
32: /*
33: * Copyright (c) 1982, 1986, 1989, 1993, 1995
34: * The Regents of the University of California. All rights reserved.
35: * (c) UNIX System Laboratories, Inc.
36: * All or some portions of this file are derived from material licensed
37: * to the University of California by American Telephone and Telegraph
38: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
39: * the permission of UNIX System Laboratories, Inc.
40: *
41: * Redistribution and use in source and binary forms, with or without
42: * modification, are permitted provided that the following conditions
43: * are met:
44: * 1. Redistributions of source code must retain the above copyright
45: * notice, this list of conditions and the following disclaimer.
46: * 2. Redistributions in binary form must reproduce the above copyright
47: * notice, this list of conditions and the following disclaimer in the
48: * documentation and/or other materials provided with the distribution.
49: * 3. Neither the name of the University nor the names of its contributors
50: * may be used to endorse or promote products derived from this software
51: * without specific prior written permission.
52: *
53: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63: * SUCH DAMAGE.
64: *
65: * @(#)ufs_vnops.c 8.28 (Berkeley) 7/31/95
66: */
67:
68: #include <sys/cdefs.h>
1.169.6.3! christos 69: __KERNEL_RCSID(0, "$NetBSD: ufs_vnops.c,v 1.169.6.2 2008/11/20 20:45:40 christos Exp $");
1.169.6.2 christos 70:
71: #if defined(_KERNEL_OPT)
72: #include "opt_ffs.h"
73: #include "opt_quota.h"
74: #endif
75:
76: #include <sys/param.h>
77: #include <sys/systm.h>
78: #include <sys/namei.h>
79: #include <sys/resourcevar.h>
80: #include <sys/kernel.h>
81: #include <sys/file.h>
82: #include <sys/stat.h>
83: #include <sys/buf.h>
84: #include <sys/proc.h>
85: #include <sys/mount.h>
86: #include <sys/vnode.h>
87: #include <sys/malloc.h>
88: #include <sys/dirent.h>
89: #include <sys/lockf.h>
90: #include <sys/kauth.h>
91: #include <sys/wapbl.h>
92: #include <sys/fstrans.h>
93:
94: #include <miscfs/specfs/specdev.h>
95: #include <miscfs/fifofs/fifo.h>
96:
97: #include <ufs/ufs/inode.h>
98: #include <ufs/ufs/dir.h>
99: #include <ufs/ufs/ufsmount.h>
100: #include <ufs/ufs/ufs_bswap.h>
101: #include <ufs/ufs/ufs_extern.h>
102: #include <ufs/ufs/ufs_wapbl.h>
103: #ifdef UFS_DIRHASH
104: #include <ufs/ufs/dirhash.h>
105: #endif
106: #include <ufs/ext2fs/ext2fs_extern.h>
107: #include <ufs/ffs/ffs_extern.h>
108: #include <ufs/lfs/lfs_extern.h>
109:
110: #include <uvm/uvm.h>
111:
112: static int ufs_chmod(struct vnode *, int, kauth_cred_t, struct lwp *);
113: static int ufs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t,
114: struct lwp *);
115:
116: /*
117: * A virgin directory (no blushing please).
118: */
119: static const struct dirtemplate mastertemplate = {
120: 0, 12, DT_DIR, 1, ".",
121: 0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
122: };
123:
124: /*
125: * Create a regular file
126: */
127: int
128: ufs_create(void *v)
129: {
130: struct vop_create_args /* {
131: struct vnode *a_dvp;
132: struct vnode **a_vpp;
133: struct componentname *a_cnp;
134: struct vattr *a_vap;
135: } */ *ap = v;
136: int error;
137:
138: /*
139: * UFS_WAPBL_BEGIN1(dvp->v_mount, dvp) performed by successful
140: * ufs_makeinode
141: */
142: fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED);
143: error =
144: ufs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
145: ap->a_dvp, ap->a_vpp, ap->a_cnp);
146: if (error) {
147: fstrans_done(ap->a_dvp->v_mount);
148: return (error);
149: }
150: UFS_WAPBL_END1(ap->a_dvp->v_mount, ap->a_dvp);
151: fstrans_done(ap->a_dvp->v_mount);
152: VN_KNOTE(ap->a_dvp, NOTE_WRITE);
153: return (0);
154: }
155:
156: /*
157: * Mknod vnode call
158: */
159: /* ARGSUSED */
160: int
161: ufs_mknod(void *v)
162: {
163: struct vop_mknod_args /* {
164: struct vnode *a_dvp;
165: struct vnode **a_vpp;
166: struct componentname *a_cnp;
167: struct vattr *a_vap;
168: } */ *ap = v;
169: struct vattr *vap;
170: struct vnode **vpp;
171: struct inode *ip;
172: int error;
173: struct mount *mp;
174: ino_t ino;
175:
176: vap = ap->a_vap;
177: vpp = ap->a_vpp;
178:
179: /*
180: * UFS_WAPBL_BEGIN1(dvp->v_mount, dvp) performed by successful
181: * ufs_makeinode
182: */
183: fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED);
184: if ((error =
185: ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
186: ap->a_dvp, vpp, ap->a_cnp)) != 0)
187: goto out;
188: VN_KNOTE(ap->a_dvp, NOTE_WRITE);
189: ip = VTOI(*vpp);
190: mp = (*vpp)->v_mount;
191: ino = ip->i_number;
192: ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
193: if (vap->va_rdev != VNOVAL) {
194: struct ufsmount *ump = ip->i_ump;
195: /*
196: * Want to be able to use this to make badblock
197: * inodes, so don't truncate the dev number.
198: */
199: if (ump->um_fstype == UFS1)
200: ip->i_ffs1_rdev = ufs_rw32(vap->va_rdev,
201: UFS_MPNEEDSWAP(ump));
202: else
203: ip->i_ffs2_rdev = ufs_rw64(vap->va_rdev,
204: UFS_MPNEEDSWAP(ump));
205: }
206: UFS_WAPBL_UPDATE(*vpp, NULL, NULL, 0);
207: UFS_WAPBL_END1(ap->a_dvp->v_mount, ap->a_dvp);
208: /*
209: * Remove inode so that it will be reloaded by VFS_VGET and
210: * checked to see if it is an alias of an existing entry in
211: * the inode cache.
212: */
213: VOP_UNLOCK(*vpp, 0);
214: (*vpp)->v_type = VNON;
215: vgone(*vpp);
216: error = VFS_VGET(mp, ino, vpp);
217: out:
218: fstrans_done(ap->a_dvp->v_mount);
219: if (error != 0) {
220: *vpp = NULL;
221: return (error);
222: }
223: return (0);
224: }
225:
226: /*
227: * Open called.
228: *
229: * Nothing to do.
230: */
231: /* ARGSUSED */
232: int
233: ufs_open(void *v)
234: {
235: struct vop_open_args /* {
236: struct vnode *a_vp;
237: int a_mode;
238: kauth_cred_t a_cred;
239: } */ *ap = v;
240:
241: /*
242: * Files marked append-only must be opened for appending.
243: */
244: if ((VTOI(ap->a_vp)->i_flags & APPEND) &&
245: (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
246: return (EPERM);
247: return (0);
248: }
249:
250: /*
251: * Close called.
252: *
253: * Update the times on the inode.
254: */
255: /* ARGSUSED */
256: int
257: ufs_close(void *v)
258: {
259: struct vop_close_args /* {
260: struct vnode *a_vp;
261: int a_fflag;
262: kauth_cred_t a_cred;
263: } */ *ap = v;
264: struct vnode *vp;
265: struct inode *ip;
266:
267: vp = ap->a_vp;
268: ip = VTOI(vp);
269: if (vp->v_usecount > 1)
270: UFS_ITIMES(vp, NULL, NULL, NULL);
271: return (0);
272: }
273:
274: int
275: ufs_access(void *v)
276: {
277: struct vop_access_args /* {
278: struct vnode *a_vp;
279: int a_mode;
280: kauth_cred_t a_cred;
281: } */ *ap = v;
282: struct vnode *vp;
283: struct inode *ip;
284: mode_t mode;
285: #ifdef QUOTA
286: int error;
287: #endif
288:
289: vp = ap->a_vp;
290: ip = VTOI(vp);
291: mode = ap->a_mode;
292: /*
293: * Disallow write attempts on read-only file systems;
294: * unless the file is a socket, fifo, or a block or
295: * character device resident on the file system.
296: */
297: if (mode & VWRITE) {
298: switch (vp->v_type) {
299: case VDIR:
300: case VLNK:
301: case VREG:
302: if (vp->v_mount->mnt_flag & MNT_RDONLY)
303: return (EROFS);
304: #ifdef QUOTA
305: fstrans_start(vp->v_mount, FSTRANS_SHARED);
306: error = getinoquota(ip);
307: fstrans_done(vp->v_mount);
308: if (error != 0)
309: return error;
310: #endif
311: break;
312: case VBAD:
313: case VBLK:
314: case VCHR:
315: case VSOCK:
316: case VFIFO:
317: case VNON:
318: default:
319: break;
320: }
321: }
322:
323: /* If it is a snapshot, nobody gets access to it. */
324: if ((ip->i_flags & SF_SNAPSHOT))
325: return (EPERM);
326: /* If immutable bit set, nobody gets to write it. */
327: if ((mode & VWRITE) && (ip->i_flags & IMMUTABLE))
328: return (EPERM);
329:
330: return (vaccess(vp->v_type, ip->i_mode & ALLPERMS,
331: ip->i_uid, ip->i_gid, mode, ap->a_cred));
332: }
333:
334: /* ARGSUSED */
335: int
336: ufs_getattr(void *v)
337: {
338: struct vop_getattr_args /* {
339: struct vnode *a_vp;
340: struct vattr *a_vap;
341: kauth_cred_t a_cred;
342: } */ *ap = v;
343: struct vnode *vp;
344: struct inode *ip;
345: struct vattr *vap;
346:
347: vp = ap->a_vp;
348: ip = VTOI(vp);
349: vap = ap->a_vap;
350: UFS_ITIMES(vp, NULL, NULL, NULL);
351:
352: /*
353: * Copy from inode table
354: */
355: vap->va_fsid = ip->i_dev;
356: vap->va_fileid = ip->i_number;
357: vap->va_mode = ip->i_mode & ALLPERMS;
358: vap->va_nlink = ip->i_ffs_effnlink;
359: vap->va_uid = ip->i_uid;
360: vap->va_gid = ip->i_gid;
361: vap->va_size = vp->v_size;
362: if (ip->i_ump->um_fstype == UFS1) {
363: vap->va_rdev = (dev_t)ufs_rw32(ip->i_ffs1_rdev,
364: UFS_MPNEEDSWAP(ip->i_ump));
365: vap->va_atime.tv_sec = ip->i_ffs1_atime;
366: vap->va_atime.tv_nsec = ip->i_ffs1_atimensec;
367: vap->va_mtime.tv_sec = ip->i_ffs1_mtime;
368: vap->va_mtime.tv_nsec = ip->i_ffs1_mtimensec;
369: vap->va_ctime.tv_sec = ip->i_ffs1_ctime;
370: vap->va_ctime.tv_nsec = ip->i_ffs1_ctimensec;
371: vap->va_birthtime.tv_sec = 0;
372: vap->va_birthtime.tv_nsec = 0;
373: vap->va_bytes = dbtob((u_quad_t)ip->i_ffs1_blocks);
374: } else {
375: vap->va_rdev = (dev_t)ufs_rw64(ip->i_ffs2_rdev,
376: UFS_MPNEEDSWAP(ip->i_ump));
377: vap->va_atime.tv_sec = ip->i_ffs2_atime;
378: vap->va_atime.tv_nsec = ip->i_ffs2_atimensec;
379: vap->va_mtime.tv_sec = ip->i_ffs2_mtime;
380: vap->va_mtime.tv_nsec = ip->i_ffs2_mtimensec;
381: vap->va_ctime.tv_sec = ip->i_ffs2_ctime;
382: vap->va_ctime.tv_nsec = ip->i_ffs2_ctimensec;
383: vap->va_birthtime.tv_sec = ip->i_ffs2_birthtime;
384: vap->va_birthtime.tv_nsec = ip->i_ffs2_birthnsec;
385: vap->va_bytes = dbtob(ip->i_ffs2_blocks);
386: }
387: vap->va_gen = ip->i_gen;
388: vap->va_flags = ip->i_flags;
389:
390: /* this doesn't belong here */
391: if (vp->v_type == VBLK)
392: vap->va_blocksize = BLKDEV_IOSIZE;
393: else if (vp->v_type == VCHR)
394: vap->va_blocksize = MAXBSIZE;
395: else
396: vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
397: vap->va_type = vp->v_type;
398: vap->va_filerev = ip->i_modrev;
399: return (0);
400: }
401:
402: /*
403: * Set attribute vnode op. called from several syscalls
404: */
405: int
406: ufs_setattr(void *v)
407: {
408: struct vop_setattr_args /* {
409: struct vnode *a_vp;
410: struct vattr *a_vap;
411: kauth_cred_t a_cred;
412: } */ *ap = v;
413: struct vattr *vap;
414: struct vnode *vp;
415: struct inode *ip;
416: kauth_cred_t cred;
417: struct lwp *l;
418: int error;
419:
420: vap = ap->a_vap;
421: vp = ap->a_vp;
422: ip = VTOI(vp);
423: cred = ap->a_cred;
424: l = curlwp;
425:
426: /*
427: * Check for unsettable attributes.
428: */
429: if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
430: (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
431: (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
432: ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
433: return (EINVAL);
434: }
435:
436: fstrans_start(vp->v_mount, FSTRANS_SHARED);
437:
438: if (vap->va_flags != VNOVAL) {
439: if (vp->v_mount->mnt_flag & MNT_RDONLY) {
440: error = EROFS;
441: goto out;
442: }
443: if (kauth_cred_geteuid(cred) != ip->i_uid &&
444: (error = kauth_authorize_generic(cred,
445: KAUTH_GENERIC_ISSUSER, NULL)))
446: goto out;
447: if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
448: NULL) == 0) {
449: if ((ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) &&
450: kauth_authorize_system(l->l_cred,
451: KAUTH_SYSTEM_CHSYSFLAGS, 0, NULL, NULL, NULL)) {
452: error = EPERM;
453: goto out;
454: }
455: /* Snapshot flag cannot be set or cleared */
456: if ((vap->va_flags & SF_SNAPSHOT) !=
457: (ip->i_flags & SF_SNAPSHOT)) {
458: error = EPERM;
459: goto out;
460: }
461: error = UFS_WAPBL_BEGIN(vp->v_mount);
462: if (error)
463: goto out;
464: ip->i_flags = vap->va_flags;
465: DIP_ASSIGN(ip, flags, ip->i_flags);
466: } else {
467: if ((ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) ||
468: (vap->va_flags & UF_SETTABLE) != vap->va_flags) {
469: error = EPERM;
470: goto out;
471: }
472: if ((ip->i_flags & SF_SETTABLE) !=
473: (vap->va_flags & SF_SETTABLE)) {
474: error = EPERM;
475: goto out;
476: }
477: error = UFS_WAPBL_BEGIN(vp->v_mount);
478: if (error)
479: goto out;
480: ip->i_flags &= SF_SETTABLE;
481: ip->i_flags |= (vap->va_flags & UF_SETTABLE);
482: DIP_ASSIGN(ip, flags, ip->i_flags);
483: }
484: ip->i_flag |= IN_CHANGE;
485: UFS_WAPBL_UPDATE(vp, NULL, NULL, 0);
486: UFS_WAPBL_END(vp->v_mount);
487: if (vap->va_flags & (IMMUTABLE | APPEND)) {
488: error = 0;
489: goto out;
490: }
491: }
492: if (ip->i_flags & (IMMUTABLE | APPEND)) {
493: error = EPERM;
494: goto out;
495: }
496: /*
497: * Go through the fields and update iff not VNOVAL.
498: */
499: if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
500: if (vp->v_mount->mnt_flag & MNT_RDONLY) {
501: error = EROFS;
502: goto out;
503: }
504: error = UFS_WAPBL_BEGIN(vp->v_mount);
505: if (error)
506: goto out;
507: error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, l);
508: UFS_WAPBL_END(vp->v_mount);
509: if (error)
510: goto out;
511: }
512: if (vap->va_size != VNOVAL) {
513: /*
514: * Disallow write attempts on read-only file systems;
515: * unless the file is a socket, fifo, or a block or
516: * character device resident on the file system.
517: */
518: switch (vp->v_type) {
519: case VDIR:
520: error = EISDIR;
521: goto out;
522: case VCHR:
523: case VBLK:
524: case VFIFO:
525: break;
526: case VREG:
527: if (vp->v_mount->mnt_flag & MNT_RDONLY) {
528: error = EROFS;
529: goto out;
530: }
531: if ((ip->i_flags & SF_SNAPSHOT) != 0) {
532: error = EPERM;
533: goto out;
534: }
535: error = UFS_WAPBL_BEGIN(vp->v_mount);
536: if (error)
537: goto out;
538: /*
539: * When journaling, only truncate one indirect block
540: * at a time.
541: */
542: if (vp->v_mount->mnt_wapbl) {
543: uint64_t incr = MNINDIR(ip->i_ump) <<
544: vp->v_mount->mnt_fs_bshift; /* Power of 2 */
545: uint64_t base = NDADDR <<
546: vp->v_mount->mnt_fs_bshift;
547: while (!error && ip->i_size > base + incr &&
548: ip->i_size > vap->va_size + incr) {
549: /*
550: * round down to next full indirect
551: * block boundary.
552: */
553: uint64_t nsize = base +
554: ((ip->i_size - base - 1) &
555: ~(incr - 1));
556: error = UFS_TRUNCATE(vp, nsize, 0,
557: cred);
558: if (error == 0) {
559: UFS_WAPBL_END(vp->v_mount);
560: error =
561: UFS_WAPBL_BEGIN(vp->v_mount);
562: }
563: }
564: }
565: if (!error)
566: error = UFS_TRUNCATE(vp, vap->va_size, 0, cred);
567: UFS_WAPBL_END(vp->v_mount);
568: if (error)
569: goto out;
570: break;
571: default:
572: error = EOPNOTSUPP;
573: goto out;
574: }
575: }
576: ip = VTOI(vp);
577: if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
578: vap->va_birthtime.tv_sec != VNOVAL) {
579: if (vp->v_mount->mnt_flag & MNT_RDONLY) {
580: error = EROFS;
581: goto out;
582: }
583: if ((ip->i_flags & SF_SNAPSHOT) != 0) {
584: error = EPERM;
585: goto out;
586: }
587: if (kauth_cred_geteuid(cred) != ip->i_uid &&
588: (error = kauth_authorize_generic(cred,
589: KAUTH_GENERIC_ISSUSER, NULL)) &&
590: ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
591: (error = VOP_ACCESS(vp, VWRITE, cred))))
592: goto out;
593: error = UFS_WAPBL_BEGIN(vp->v_mount);
594: if (error)
595: goto out;
596: if (vap->va_atime.tv_sec != VNOVAL)
597: if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
598: ip->i_flag |= IN_ACCESS;
599: if (vap->va_mtime.tv_sec != VNOVAL)
600: ip->i_flag |= IN_CHANGE | IN_UPDATE;
601: if (vap->va_birthtime.tv_sec != VNOVAL &&
602: ip->i_ump->um_fstype == UFS2) {
603: ip->i_ffs2_birthtime = vap->va_birthtime.tv_sec;
604: ip->i_ffs2_birthnsec = vap->va_birthtime.tv_nsec;
605: }
606: error = UFS_UPDATE(vp, &vap->va_atime, &vap->va_mtime, 0);
607: UFS_WAPBL_END(vp->v_mount);
608: if (error)
609: goto out;
610: }
611: error = 0;
612: if (vap->va_mode != (mode_t)VNOVAL) {
613: if (vp->v_mount->mnt_flag & MNT_RDONLY) {
614: error = EROFS;
615: goto out;
616: }
617: if ((ip->i_flags & SF_SNAPSHOT) != 0 &&
618: (vap->va_mode & (S_IXUSR | S_IWUSR | S_IXGRP | S_IWGRP |
619: S_IXOTH | S_IWOTH))) {
620: error = EPERM;
621: goto out;
622: }
623: error = UFS_WAPBL_BEGIN(vp->v_mount);
624: if (error)
625: goto out;
626: error = ufs_chmod(vp, (int)vap->va_mode, cred, l);
627: UFS_WAPBL_END(vp->v_mount);
628: }
629: VN_KNOTE(vp, NOTE_ATTRIB);
630: out:
631: fstrans_done(vp->v_mount);
632: return (error);
633: }
634:
635: /*
636: * Change the mode on a file.
637: * Inode must be locked before calling.
638: */
639: static int
640: ufs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct lwp *l)
641: {
642: struct inode *ip;
643: int error, ismember = 0;
644:
645: UFS_WAPBL_JLOCK_ASSERT(vp->v_mount);
646:
647: ip = VTOI(vp);
648: if (kauth_cred_geteuid(cred) != ip->i_uid &&
649: (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL)))
650: return (error);
651: if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL)) {
652: if (vp->v_type != VDIR && (mode & S_ISTXT))
653: return (EFTYPE);
654: if ((kauth_cred_ismember_gid(cred, ip->i_gid, &ismember) != 0 ||
655: !ismember) && (mode & ISGID))
656: return (EPERM);
657: }
658: ip->i_mode &= ~ALLPERMS;
659: ip->i_mode |= (mode & ALLPERMS);
660: ip->i_flag |= IN_CHANGE;
661: DIP_ASSIGN(ip, mode, ip->i_mode);
662: UFS_WAPBL_UPDATE(vp, NULL, NULL, 0);
663: return (0);
664: }
665:
666: /*
667: * Perform chown operation on inode ip;
668: * inode must be locked prior to call.
669: */
670: static int
671: ufs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
672: struct lwp *l)
673: {
674: struct inode *ip;
675: int error, ismember = 0;
676: #ifdef QUOTA
677: uid_t ouid;
678: gid_t ogid;
679: int64_t change;
680: #endif
681: ip = VTOI(vp);
682: error = 0;
683:
684: if (uid == (uid_t)VNOVAL)
685: uid = ip->i_uid;
686: if (gid == (gid_t)VNOVAL)
687: gid = ip->i_gid;
688: /*
689: * If we don't own the file, are trying to change the owner
690: * of the file, or are not a member of the target group,
691: * the caller's credentials must imply super-user privilege
692: * or the call fails.
693: */
694: if ((kauth_cred_geteuid(cred) != ip->i_uid || uid != ip->i_uid ||
695: (gid != ip->i_gid &&
696: !(kauth_cred_getegid(cred) == gid ||
697: (kauth_cred_ismember_gid(cred, gid, &ismember) == 0 &&
698: ismember)))) &&
699: ((error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
700: NULL)) != 0))
701: return (error);
702:
703: #ifdef QUOTA
704: ogid = ip->i_gid;
705: ouid = ip->i_uid;
706: change = DIP(ip, blocks);
707: (void) chkdq(ip, -change, cred, 0);
708: (void) chkiq(ip, -1, cred, 0);
709: #endif
710: ip->i_gid = gid;
711: DIP_ASSIGN(ip, gid, gid);
712: ip->i_uid = uid;
713: DIP_ASSIGN(ip, uid, uid);
714: #ifdef QUOTA
715: if ((error = chkdq(ip, change, cred, 0)) == 0) {
716: if ((error = chkiq(ip, 1, cred, 0)) == 0)
717: goto good;
718: else
719: (void) chkdq(ip, -change, cred, FORCE);
720: }
721: ip->i_gid = ogid;
722: DIP_ASSIGN(ip, gid, ogid);
723: ip->i_uid = ouid;
724: DIP_ASSIGN(ip, uid, ouid);
725: (void) chkdq(ip, change, cred, FORCE);
726: (void) chkiq(ip, 1, cred, FORCE);
727: return (error);
728: good:
729: #endif /* QUOTA */
730: ip->i_flag |= IN_CHANGE;
731: UFS_WAPBL_UPDATE(vp, NULL, NULL, 0);
732: return (0);
733: }
734:
735: int
736: ufs_remove(void *v)
737: {
738: struct vop_remove_args /* {
739: struct vnode *a_dvp;
740: struct vnode *a_vp;
741: struct componentname *a_cnp;
742: } */ *ap = v;
743: struct vnode *vp, *dvp;
744: struct inode *ip;
745: int error;
746: bool pace;
747:
748: vp = ap->a_vp;
749: dvp = ap->a_dvp;
750: ip = VTOI(vp);
751: fstrans_start(dvp->v_mount, FSTRANS_SHARED);
752: if (vp->v_type == VDIR || (ip->i_flags & (IMMUTABLE | APPEND)) ||
753: (VTOI(dvp)->i_flags & APPEND))
754: error = EPERM;
755: else {
756: error = UFS_WAPBL_BEGIN(dvp->v_mount);
757: if (error == 0) {
758: error = ufs_dirremove(dvp, ip, ap->a_cnp->cn_flags, 0);
759: UFS_WAPBL_END(dvp->v_mount);
760: }
761: }
762: VN_KNOTE(vp, NOTE_DELETE);
763: VN_KNOTE(dvp, NOTE_WRITE);
764: if (dvp == vp)
765: vrele(vp);
766: else
767: vput(vp);
768: pace = DOINGSOFTDEP(dvp);
769: vput(dvp);
770: fstrans_done(dvp->v_mount);
771: if (pace) {
772: /*
773: * Give the syncer some breathing room so that it
774: * can flush removes. XXX
775: */
776: softdep_pace_dirrem();
777: }
778: return (error);
779: }
780:
781: /*
782: * link vnode call
783: */
784: int
785: ufs_link(void *v)
786: {
787: struct vop_link_args /* {
788: struct vnode *a_dvp;
789: struct vnode *a_vp;
790: struct componentname *a_cnp;
791: } */ *ap = v;
792: struct vnode *vp, *dvp;
793: struct componentname *cnp;
794: struct inode *ip;
795: struct direct *newdir;
796: int error;
797:
798: dvp = ap->a_dvp;
799: vp = ap->a_vp;
800: cnp = ap->a_cnp;
801: #ifdef DIAGNOSTIC
802: if ((cnp->cn_flags & HASBUF) == 0)
803: panic("ufs_link: no name");
804: #endif
805: fstrans_start(dvp->v_mount, FSTRANS_SHARED);
806: if (vp->v_type == VDIR) {
807: VOP_ABORTOP(dvp, cnp);
808: error = EPERM;
809: goto out2;
810: }
811: if (dvp->v_mount != vp->v_mount) {
812: VOP_ABORTOP(dvp, cnp);
813: error = EXDEV;
814: goto out2;
815: }
816: if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE))) {
817: VOP_ABORTOP(dvp, cnp);
818: goto out2;
819: }
820: ip = VTOI(vp);
821: if ((nlink_t)ip->i_nlink >= LINK_MAX) {
822: VOP_ABORTOP(dvp, cnp);
823: error = EMLINK;
824: goto out1;
825: }
826: if (ip->i_flags & (IMMUTABLE | APPEND)) {
827: VOP_ABORTOP(dvp, cnp);
828: error = EPERM;
829: goto out1;
830: }
831: error = UFS_WAPBL_BEGIN(vp->v_mount);
832: if (error) {
833: VOP_ABORTOP(dvp, cnp);
834: goto out1;
835: }
836: ip->i_ffs_effnlink++;
837: ip->i_nlink++;
838: DIP_ASSIGN(ip, nlink, ip->i_nlink);
839: ip->i_flag |= IN_CHANGE;
840: if (DOINGSOFTDEP(vp))
841: softdep_change_linkcnt(ip);
842: error = UFS_UPDATE(vp, NULL, NULL, UPDATE_DIROP);
843: if (!error) {
844: newdir = pool_cache_get(ufs_direct_cache, PR_WAITOK);
845: ufs_makedirentry(ip, cnp, newdir);
846: error = ufs_direnter(dvp, vp, newdir, cnp, NULL);
847: pool_cache_put(ufs_direct_cache, newdir);
848: }
849: if (error) {
850: ip->i_ffs_effnlink--;
851: ip->i_nlink--;
852: DIP_ASSIGN(ip, nlink, ip->i_nlink);
853: ip->i_flag |= IN_CHANGE;
854: UFS_WAPBL_UPDATE(vp, NULL, NULL, UPDATE_DIROP);
855: if (DOINGSOFTDEP(vp))
856: softdep_change_linkcnt(ip);
857: }
858: PNBUF_PUT(cnp->cn_pnbuf);
859: UFS_WAPBL_END(vp->v_mount);
860: out1:
861: if (dvp != vp)
862: VOP_UNLOCK(vp, 0);
863: out2:
864: VN_KNOTE(vp, NOTE_LINK);
865: VN_KNOTE(dvp, NOTE_WRITE);
866: vput(dvp);
867: fstrans_done(dvp->v_mount);
868: return (error);
869: }
870:
871: /*
872: * whiteout vnode call
873: */
874: int
875: ufs_whiteout(void *v)
876: {
877: struct vop_whiteout_args /* {
878: struct vnode *a_dvp;
879: struct componentname *a_cnp;
880: int a_flags;
881: } */ *ap = v;
882: struct vnode *dvp = ap->a_dvp;
883: struct componentname *cnp = ap->a_cnp;
884: struct direct *newdir;
885: int error;
886: struct ufsmount *ump = VFSTOUFS(dvp->v_mount);
887:
888: error = 0;
889: switch (ap->a_flags) {
890: case LOOKUP:
891: /* 4.4 format directories support whiteout operations */
892: if (ump->um_maxsymlinklen > 0)
893: return (0);
894: return (EOPNOTSUPP);
895:
896: case CREATE:
897: /* create a new directory whiteout */
898: fstrans_start(dvp->v_mount, FSTRANS_SHARED);
899: #ifdef DIAGNOSTIC
900: if ((cnp->cn_flags & SAVENAME) == 0)
901: panic("ufs_whiteout: missing name");
902: if (ump->um_maxsymlinklen <= 0)
903: panic("ufs_whiteout: old format filesystem");
904: #endif
905:
906: newdir = pool_cache_get(ufs_direct_cache, PR_WAITOK);
907: newdir->d_ino = WINO;
908: newdir->d_namlen = cnp->cn_namelen;
909: memcpy(newdir->d_name, cnp->cn_nameptr,
910: (size_t)cnp->cn_namelen);
911: newdir->d_name[cnp->cn_namelen] = '\0';
912: newdir->d_type = DT_WHT;
913: error = ufs_direnter(dvp, NULL, newdir, cnp, NULL);
914: pool_cache_put(ufs_direct_cache, newdir);
915: break;
916:
917: case DELETE:
918: /* remove an existing directory whiteout */
919: fstrans_start(dvp->v_mount, FSTRANS_SHARED);
920: #ifdef DIAGNOSTIC
921: if (ump->um_maxsymlinklen <= 0)
922: panic("ufs_whiteout: old format filesystem");
923: #endif
924:
925: cnp->cn_flags &= ~DOWHITEOUT;
926: error = ufs_dirremove(dvp, NULL, cnp->cn_flags, 0);
927: break;
928: default:
929: panic("ufs_whiteout: unknown op");
930: /* NOTREACHED */
931: }
932: if (cnp->cn_flags & HASBUF) {
933: PNBUF_PUT(cnp->cn_pnbuf);
934: cnp->cn_flags &= ~HASBUF;
935: }
936: fstrans_done(dvp->v_mount);
937: return (error);
938: }
939:
940:
941: /*
942: * Rename vnode operation
943: * rename("foo", "bar");
944: * is essentially
945: * unlink("bar");
946: * link("foo", "bar");
947: * unlink("foo");
948: * but ``atomically''. Can't do full commit without saving state in the
949: * inode on disk which isn't feasible at this time. Best we can do is
950: * always guarantee the target exists.
951: *
952: * Basic algorithm is:
953: *
954: * 1) Bump link count on source while we're linking it to the
955: * target. This also ensure the inode won't be deleted out
956: * from underneath us while we work (it may be truncated by
957: * a concurrent `trunc' or `open' for creation).
958: * 2) Link source to destination. If destination already exists,
959: * delete it first.
960: * 3) Unlink source reference to inode if still around. If a
961: * directory was moved and the parent of the destination
962: * is different from the source, patch the ".." entry in the
963: * directory.
964: */
965: int
966: ufs_rename(void *v)
967: {
968: struct vop_rename_args /* {
969: struct vnode *a_fdvp;
970: struct vnode *a_fvp;
971: struct componentname *a_fcnp;
972: struct vnode *a_tdvp;
973: struct vnode *a_tvp;
974: struct componentname *a_tcnp;
975: } */ *ap = v;
976: struct vnode *tvp, *tdvp, *fvp, *fdvp;
977: struct componentname *tcnp, *fcnp;
978: struct inode *ip, *xp, *dp;
979: struct mount *mp;
980: struct direct *newdir;
981: int doingdirectory, oldparent, newparent, error;
982:
983: #ifdef WAPBL
984: if (ap->a_tdvp->v_mount->mnt_wapbl)
985: return wapbl_ufs_rename(v);
986: #endif
987:
988: tvp = ap->a_tvp;
989: tdvp = ap->a_tdvp;
990: fvp = ap->a_fvp;
991: fdvp = ap->a_fdvp;
992: tcnp = ap->a_tcnp;
993: fcnp = ap->a_fcnp;
994: doingdirectory = oldparent = newparent = error = 0;
995:
996: #ifdef DIAGNOSTIC
997: if ((tcnp->cn_flags & HASBUF) == 0 ||
998: (fcnp->cn_flags & HASBUF) == 0)
999: panic("ufs_rename: no name");
1000: #endif
1001: /*
1002: * Check for cross-device rename.
1003: */
1004: if ((fvp->v_mount != tdvp->v_mount) ||
1005: (tvp && (fvp->v_mount != tvp->v_mount))) {
1006: error = EXDEV;
1007: abortit:
1008: VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
1009: if (tdvp == tvp)
1010: vrele(tdvp);
1011: else
1012: vput(tdvp);
1013: if (tvp)
1014: vput(tvp);
1015: VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
1016: vrele(fdvp);
1017: vrele(fvp);
1018: return (error);
1019: }
1020:
1021: /*
1022: * Check if just deleting a link name.
1023: */
1024: if (tvp && ((VTOI(tvp)->i_flags & (IMMUTABLE | APPEND)) ||
1025: (VTOI(tdvp)->i_flags & APPEND))) {
1026: error = EPERM;
1027: goto abortit;
1028: }
1029: if (fvp == tvp) {
1030: if (fvp->v_type == VDIR) {
1031: error = EINVAL;
1032: goto abortit;
1033: }
1034:
1035: /* Release destination completely. */
1036: VOP_ABORTOP(tdvp, tcnp);
1037: vput(tdvp);
1038: vput(tvp);
1039:
1040: /* Delete source. */
1041: vrele(fvp);
1042: fcnp->cn_flags &= ~(MODMASK | SAVESTART);
1043: fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
1044: fcnp->cn_nameiop = DELETE;
1045: vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
1046: if ((error = relookup(fdvp, &fvp, fcnp))) {
1047: vput(fdvp);
1048: return (error);
1049: }
1050: return (VOP_REMOVE(fdvp, fvp, fcnp));
1051: }
1052: if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
1053: goto abortit;
1054: dp = VTOI(fdvp);
1055: ip = VTOI(fvp);
1056: if ((nlink_t) ip->i_nlink >= LINK_MAX) {
1057: VOP_UNLOCK(fvp, 0);
1058: error = EMLINK;
1059: goto abortit;
1060: }
1061: if ((ip->i_flags & (IMMUTABLE | APPEND)) ||
1062: (dp->i_flags & APPEND)) {
1063: VOP_UNLOCK(fvp, 0);
1064: error = EPERM;
1065: goto abortit;
1066: }
1067: if ((ip->i_mode & IFMT) == IFDIR) {
1068: /*
1069: * Avoid ".", "..", and aliases of "." for obvious reasons.
1070: */
1071: if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
1072: dp == ip ||
1073: (fcnp->cn_flags & ISDOTDOT) ||
1074: (tcnp->cn_flags & ISDOTDOT) ||
1075: (ip->i_flag & IN_RENAME)) {
1076: VOP_UNLOCK(fvp, 0);
1077: error = EINVAL;
1078: goto abortit;
1079: }
1080: ip->i_flag |= IN_RENAME;
1081: oldparent = dp->i_number;
1082: doingdirectory = 1;
1083: }
1084: VN_KNOTE(fdvp, NOTE_WRITE); /* XXXLUKEM/XXX: right place? */
1085:
1086: /*
1087: * When the target exists, both the directory
1088: * and target vnodes are returned locked.
1089: */
1090: dp = VTOI(tdvp);
1091: xp = NULL;
1092: if (tvp)
1093: xp = VTOI(tvp);
1094:
1095: mp = fdvp->v_mount;
1096: fstrans_start(mp, FSTRANS_SHARED);
1097:
1098: /*
1099: * 1) Bump link count while we're moving stuff
1100: * around. If we crash somewhere before
1101: * completing our work, the link count
1102: * may be wrong, but correctable.
1103: */
1104: ip->i_ffs_effnlink++;
1105: ip->i_nlink++;
1106: DIP_ASSIGN(ip, nlink, ip->i_nlink);
1107: ip->i_flag |= IN_CHANGE;
1108: if (DOINGSOFTDEP(fvp))
1109: softdep_change_linkcnt(ip);
1110: if ((error = UFS_UPDATE(fvp, NULL, NULL, UPDATE_DIROP)) != 0) {
1111: VOP_UNLOCK(fvp, 0);
1112: goto bad;
1113: }
1114:
1115: /*
1116: * If ".." must be changed (ie the directory gets a new
1117: * parent) then the source directory must not be in the
1118: * directory hierarchy above the target, as this would
1119: * orphan everything below the source directory. Also
1120: * the user must have write permission in the source so
1121: * as to be able to change "..". We must repeat the call
1122: * to namei, as the parent directory is unlocked by the
1123: * call to checkpath().
1124: */
1125: error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred);
1126: VOP_UNLOCK(fvp, 0);
1127: if (oldparent != dp->i_number)
1128: newparent = dp->i_number;
1129: if (doingdirectory && newparent) {
1130: if (error) /* write access check above */
1131: goto bad;
1132: if (xp != NULL)
1133: vput(tvp);
1134: vref(tdvp); /* compensate for the ref checkpath loses */
1135: if ((error = ufs_checkpath(ip, dp, tcnp->cn_cred)) != 0) {
1136: vrele(tdvp);
1137: goto out;
1138: }
1139: tcnp->cn_flags &= ~SAVESTART;
1140: vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY);
1141: error = relookup(tdvp, &tvp, tcnp);
1142: if (error != 0) {
1143: vput(tdvp);
1144: goto out;
1145: }
1146: dp = VTOI(tdvp);
1147: xp = NULL;
1148: if (tvp)
1149: xp = VTOI(tvp);
1150: }
1151: /*
1152: * 2) If target doesn't exist, link the target
1153: * to the source and unlink the source.
1154: * Otherwise, rewrite the target directory
1155: * entry to reference the source inode and
1156: * expunge the original entry's existence.
1157: */
1158: if (xp == NULL) {
1159: if (dp->i_dev != ip->i_dev)
1160: panic("rename: EXDEV");
1161: /*
1162: * Account for ".." in new directory.
1163: * When source and destination have the same
1164: * parent we don't fool with the link count.
1165: */
1166: if (doingdirectory && newparent) {
1167: if ((nlink_t)dp->i_nlink >= LINK_MAX) {
1168: error = EMLINK;
1169: goto bad;
1170: }
1171: dp->i_ffs_effnlink++;
1172: dp->i_nlink++;
1173: DIP_ASSIGN(dp, nlink, dp->i_nlink);
1174: dp->i_flag |= IN_CHANGE;
1175: if (DOINGSOFTDEP(tdvp))
1176: softdep_change_linkcnt(dp);
1177: if ((error = UFS_UPDATE(tdvp, NULL, NULL,
1178: UPDATE_DIROP)) != 0) {
1179: dp->i_ffs_effnlink--;
1180: dp->i_nlink--;
1181: DIP_ASSIGN(dp, nlink, dp->i_nlink);
1182: dp->i_flag |= IN_CHANGE;
1183: if (DOINGSOFTDEP(tdvp))
1184: softdep_change_linkcnt(dp);
1185: goto bad;
1186: }
1187: }
1188: newdir = pool_cache_get(ufs_direct_cache, PR_WAITOK);
1189: ufs_makedirentry(ip, tcnp, newdir);
1190: error = ufs_direnter(tdvp, NULL, newdir, tcnp, NULL);
1191: pool_cache_put(ufs_direct_cache, newdir);
1192: if (error != 0) {
1193: if (doingdirectory && newparent) {
1194: dp->i_ffs_effnlink--;
1195: dp->i_nlink--;
1196: DIP_ASSIGN(dp, nlink, dp->i_nlink);
1197: dp->i_flag |= IN_CHANGE;
1198: if (DOINGSOFTDEP(tdvp))
1199: softdep_change_linkcnt(dp);
1200: (void)UFS_UPDATE(tdvp, NULL, NULL,
1201: UPDATE_WAIT|UPDATE_DIROP);
1202: }
1203: goto bad;
1204: }
1205: VN_KNOTE(tdvp, NOTE_WRITE);
1206: vput(tdvp);
1207: } else {
1208: if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
1209: panic("rename: EXDEV");
1210: /*
1211: * Short circuit rename(foo, foo).
1212: */
1213: if (xp->i_number == ip->i_number)
1214: panic("rename: same file");
1215: /*
1216: * If the parent directory is "sticky", then the user must
1217: * own the parent directory, or the destination of the rename,
1218: * otherwise the destination may not be changed (except by
1219: * root). This implements append-only directories.
1220: */
1221: if ((dp->i_mode & S_ISTXT) &&
1222: kauth_authorize_generic(tcnp->cn_cred,
1223: KAUTH_GENERIC_ISSUSER, NULL) != 0 &&
1224: kauth_cred_geteuid(tcnp->cn_cred) != dp->i_uid &&
1225: xp->i_uid != kauth_cred_geteuid(tcnp->cn_cred)) {
1226: error = EPERM;
1227: goto bad;
1228: }
1229: /*
1230: * Target must be empty if a directory and have no links
1231: * to it. Also, ensure source and target are compatible
1232: * (both directories, or both not directories).
1233: */
1234: if ((xp->i_mode & IFMT) == IFDIR) {
1235: if (xp->i_ffs_effnlink > 2 ||
1236: !ufs_dirempty(xp, dp->i_number, tcnp->cn_cred)) {
1237: error = ENOTEMPTY;
1238: goto bad;
1239: }
1240: if (!doingdirectory) {
1241: error = ENOTDIR;
1242: goto bad;
1243: }
1244: cache_purge(tdvp);
1245: } else if (doingdirectory) {
1246: error = EISDIR;
1247: goto bad;
1248: }
1249: if ((error = ufs_dirrewrite(dp, xp, ip->i_number,
1250: IFTODT(ip->i_mode), doingdirectory && newparent ?
1251: newparent : doingdirectory, IN_CHANGE | IN_UPDATE)) != 0)
1252: goto bad;
1253: if (doingdirectory) {
1254: if (!newparent) {
1255: dp->i_ffs_effnlink--;
1256: if (DOINGSOFTDEP(tdvp))
1257: softdep_change_linkcnt(dp);
1258: }
1259: xp->i_ffs_effnlink--;
1260: if (DOINGSOFTDEP(tvp))
1261: softdep_change_linkcnt(xp);
1262: }
1263: if (doingdirectory && !DOINGSOFTDEP(tvp)) {
1264: /*
1265: * Truncate inode. The only stuff left in the directory
1266: * is "." and "..". The "." reference is inconsequential
1267: * since we are quashing it. We have removed the "."
1268: * reference and the reference in the parent directory,
1269: * but there may be other hard links. The soft
1270: * dependency code will arrange to do these operations
1271: * after the parent directory entry has been deleted on
1272: * disk, so when running with that code we avoid doing
1273: * them now.
1274: */
1275: if (!newparent) {
1276: dp->i_nlink--;
1277: DIP_ASSIGN(dp, nlink, dp->i_nlink);
1278: dp->i_flag |= IN_CHANGE;
1279: }
1280: xp->i_nlink--;
1281: DIP_ASSIGN(xp, nlink, xp->i_nlink);
1282: xp->i_flag |= IN_CHANGE;
1283: if ((error = UFS_TRUNCATE(tvp, (off_t)0, IO_SYNC,
1284: tcnp->cn_cred)))
1285: goto bad;
1286: }
1287: VN_KNOTE(tdvp, NOTE_WRITE);
1288: vput(tdvp);
1289: VN_KNOTE(tvp, NOTE_DELETE);
1290: vput(tvp);
1291: xp = NULL;
1292: }
1293:
1294: /*
1295: * 3) Unlink the source.
1296: */
1297: fcnp->cn_flags &= ~(MODMASK | SAVESTART);
1298: fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
1299: vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
1300: if ((error = relookup(fdvp, &fvp, fcnp))) {
1301: vput(fdvp);
1302: vrele(ap->a_fvp);
1303: goto out2;
1304: }
1305: if (fvp != NULL) {
1306: xp = VTOI(fvp);
1307: dp = VTOI(fdvp);
1308: } else {
1309: /*
1310: * From name has disappeared.
1311: */
1312: if (doingdirectory)
1313: panic("rename: lost dir entry");
1314: vrele(ap->a_fvp);
1315: error = 0;
1316: goto out2;
1317: }
1318: /*
1319: * Ensure that the directory entry still exists and has not
1320: * changed while the new name has been entered. If the source is
1321: * a file then the entry may have been unlinked or renamed. In
1322: * either case there is no further work to be done. If the source
1323: * is a directory then it cannot have been rmdir'ed; The IRENAME
1324: * flag ensures that it cannot be moved by another rename or removed
1325: * by a rmdir.
1326: */
1327: if (xp != ip) {
1328: if (doingdirectory)
1329: panic("rename: lost dir entry");
1330: } else {
1331: /*
1332: * If the source is a directory with a
1333: * new parent, the link count of the old
1334: * parent directory must be decremented
1335: * and ".." set to point to the new parent.
1336: */
1337: if (doingdirectory && newparent) {
1338: KASSERT(dp != NULL);
1339: xp->i_offset = mastertemplate.dot_reclen;
1340: ufs_dirrewrite(xp, dp, newparent, DT_DIR, 0, IN_CHANGE);
1341: cache_purge(fdvp);
1342: }
1343: error = ufs_dirremove(fdvp, xp, fcnp->cn_flags, 0);
1344: xp->i_flag &= ~IN_RENAME;
1345: }
1346: VN_KNOTE(fvp, NOTE_RENAME);
1347: if (dp)
1348: vput(fdvp);
1349: if (xp)
1350: vput(fvp);
1351: vrele(ap->a_fvp);
1352: goto out2;
1353:
1354: /* exit routines from steps 1 & 2 */
1355: bad:
1356: if (xp)
1357: vput(ITOV(xp));
1358: vput(ITOV(dp));
1359: out:
1360: if (doingdirectory)
1361: ip->i_flag &= ~IN_RENAME;
1362: if (vn_lock(fvp, LK_EXCLUSIVE) == 0) {
1363: ip->i_ffs_effnlink--;
1364: ip->i_nlink--;
1365: DIP_ASSIGN(ip, nlink, ip->i_nlink);
1366: ip->i_flag |= IN_CHANGE;
1367: ip->i_flag &= ~IN_RENAME;
1368: if (DOINGSOFTDEP(fvp))
1369: softdep_change_linkcnt(ip);
1370: vput(fvp);
1371: } else
1372: vrele(fvp);
1373: vrele(fdvp);
1374:
1375: /* exit routines from step 3 */
1376: out2:
1377: fstrans_done(mp);
1378: return (error);
1379: }
1380:
1381: int
1382: ufs_mkdir(void *v)
1383: {
1384: struct vop_mkdir_args /* {
1385: struct vnode *a_dvp;
1386: struct vnode **a_vpp;
1387: struct componentname *a_cnp;
1388: struct vattr *a_vap;
1389: } */ *ap = v;
1390: struct vnode *dvp = ap->a_dvp, *tvp;
1391: struct vattr *vap = ap->a_vap;
1392: struct componentname *cnp = ap->a_cnp;
1393: struct inode *ip, *dp = VTOI(dvp);
1394: struct buf *bp;
1395: struct dirtemplate dirtemplate;
1396: struct direct *newdir;
1397: int error, dmode, blkoff;
1398: struct ufsmount *ump = dp->i_ump;
1399: int dirblksiz = ump->um_dirblksiz;
1400:
1401: fstrans_start(dvp->v_mount, FSTRANS_SHARED);
1402:
1403: #ifdef DIAGNOSTIC
1404: if ((cnp->cn_flags & HASBUF) == 0)
1405: panic("ufs_mkdir: no name");
1406: #endif
1407: if ((nlink_t)dp->i_nlink >= LINK_MAX) {
1408: error = EMLINK;
1409: goto out;
1410: }
1411: dmode = vap->va_mode & ACCESSPERMS;
1412: dmode |= IFDIR;
1413: /*
1414: * Must simulate part of ufs_makeinode here to acquire the inode,
1415: * but not have it entered in the parent directory. The entry is
1416: * made later after writing "." and ".." entries.
1417: */
1418: if ((error = UFS_VALLOC(dvp, dmode, cnp->cn_cred, ap->a_vpp)) != 0)
1419: goto out;
1420: error = UFS_WAPBL_BEGIN(ap->a_dvp->v_mount);
1421: if (error)
1422: goto out;
1423: tvp = *ap->a_vpp;
1424: ip = VTOI(tvp);
1425: ip->i_uid = kauth_cred_geteuid(cnp->cn_cred);
1426: DIP_ASSIGN(ip, uid, ip->i_uid);
1427: ip->i_gid = dp->i_gid;
1428: DIP_ASSIGN(ip, gid, ip->i_gid);
1429: #ifdef QUOTA
1430: if ((error = chkiq(ip, 1, cnp->cn_cred, 0))) {
1431: PNBUF_PUT(cnp->cn_pnbuf);
1432: UFS_VFREE(tvp, ip->i_number, dmode);
1433: UFS_WAPBL_END(dvp->v_mount);
1434: fstrans_done(dvp->v_mount);
1435: vput(tvp);
1436: vput(dvp);
1437: return (error);
1438: }
1439: #endif
1440: ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1441: ip->i_mode = dmode;
1442: DIP_ASSIGN(ip, mode, dmode);
1443: tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */
1444: ip->i_ffs_effnlink = 2;
1445: ip->i_nlink = 2;
1446: DIP_ASSIGN(ip, nlink, 2);
1447: if (DOINGSOFTDEP(tvp))
1448: softdep_change_linkcnt(ip);
1449: if (cnp->cn_flags & ISWHITEOUT) {
1450: ip->i_flags |= UF_OPAQUE;
1451: DIP_ASSIGN(ip, flags, ip->i_flags);
1452: }
1453:
1454: /*
1455: * Bump link count in parent directory to reflect work done below.
1456: * Should be done before reference is created so cleanup is
1457: * possible if we crash.
1458: */
1459: dp->i_ffs_effnlink++;
1460: dp->i_nlink++;
1461: DIP_ASSIGN(dp, nlink, dp->i_nlink);
1462: dp->i_flag |= IN_CHANGE;
1463: if (DOINGSOFTDEP(dvp))
1464: softdep_change_linkcnt(dp);
1465: if ((error = UFS_UPDATE(dvp, NULL, NULL, UPDATE_DIROP)) != 0)
1466: goto bad;
1467:
1468: /*
1469: * Initialize directory with "." and ".." from static template.
1470: */
1471: dirtemplate = mastertemplate;
1472: dirtemplate.dotdot_reclen = dirblksiz - dirtemplate.dot_reclen;
1473: dirtemplate.dot_ino = ufs_rw32(ip->i_number, UFS_MPNEEDSWAP(ump));
1474: dirtemplate.dotdot_ino = ufs_rw32(dp->i_number, UFS_MPNEEDSWAP(ump));
1475: dirtemplate.dot_reclen = ufs_rw16(dirtemplate.dot_reclen,
1476: UFS_MPNEEDSWAP(ump));
1477: dirtemplate.dotdot_reclen = ufs_rw16(dirtemplate.dotdot_reclen,
1478: UFS_MPNEEDSWAP(ump));
1479: if (ump->um_maxsymlinklen <= 0) {
1480: #if BYTE_ORDER == LITTLE_ENDIAN
1481: if (UFS_MPNEEDSWAP(ump) == 0)
1482: #else
1483: if (UFS_MPNEEDSWAP(ump) != 0)
1484: #endif
1485: {
1486: dirtemplate.dot_type = dirtemplate.dot_namlen;
1487: dirtemplate.dotdot_type = dirtemplate.dotdot_namlen;
1488: dirtemplate.dot_namlen = dirtemplate.dotdot_namlen = 0;
1489: } else
1490: dirtemplate.dot_type = dirtemplate.dotdot_type = 0;
1491: }
1492: if ((error = UFS_BALLOC(tvp, (off_t)0, dirblksiz, cnp->cn_cred,
1493: B_CLRBUF, &bp)) != 0)
1494: goto bad;
1495: ip->i_size = dirblksiz;
1496: DIP_ASSIGN(ip, size, dirblksiz);
1497: ip->i_flag |= IN_CHANGE | IN_UPDATE;
1498: uvm_vnp_setsize(tvp, ip->i_size);
1499: memcpy((void *)bp->b_data, (void *)&dirtemplate, sizeof dirtemplate);
1500: if (DOINGSOFTDEP(tvp)) {
1501: /*
1502: * Ensure that the entire newly allocated block is a
1503: * valid directory so that future growth within the
1504: * block does not have to ensure that the block is
1505: * written before the inode.
1506: */
1507: blkoff = dirblksiz;
1508: while (blkoff < bp->b_bcount) {
1509: ((struct direct *)
1510: ((char *)bp->b_data + blkoff))->d_reclen = dirblksiz;
1511: blkoff += dirblksiz;
1512: }
1513: }
1514: /*
1515: * Directory set up, now install it's entry in the parent directory.
1516: *
1517: * If we are not doing soft dependencies, then we must write out the
1518: * buffer containing the new directory body before entering the new
1519: * name in the parent. If we are doing soft dependencies, then the
1520: * buffer containing the new directory body will be passed to and
1521: * released in the soft dependency code after the code has attached
1522: * an appropriate ordering dependency to the buffer which ensures that
1523: * the buffer is written before the new name is written in the parent.
1524: */
1525: if (!DOINGSOFTDEP(tvp) && ((error = VOP_BWRITE(bp)) != 0))
1526: goto bad;
1527: if ((error = UFS_UPDATE(tvp, NULL, NULL, UPDATE_DIROP)) != 0) {
1528: if (DOINGSOFTDEP(tvp))
1529: (void)VOP_BWRITE(bp);
1530: goto bad;
1531: }
1532: newdir = pool_cache_get(ufs_direct_cache, PR_WAITOK);
1533: ufs_makedirentry(ip, cnp, newdir);
1534: error = ufs_direnter(dvp, tvp, newdir, cnp, bp);
1535: pool_cache_put(ufs_direct_cache, newdir);
1536: bad:
1537: if (error == 0) {
1538: VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1539: UFS_WAPBL_END(dvp->v_mount);
1540: } else {
1541: dp->i_ffs_effnlink--;
1542: dp->i_nlink--;
1543: DIP_ASSIGN(dp, nlink, dp->i_nlink);
1544: dp->i_flag |= IN_CHANGE;
1545: UFS_WAPBL_UPDATE(dvp, NULL, NULL, UPDATE_DIROP);
1546: if (DOINGSOFTDEP(dvp))
1547: softdep_change_linkcnt(dp);
1548: /*
1549: * No need to do an explicit UFS_TRUNCATE here, vrele will
1550: * do this for us because we set the link count to 0.
1551: */
1552: ip->i_ffs_effnlink = 0;
1553: ip->i_nlink = 0;
1554: DIP_ASSIGN(ip, nlink, 0);
1555: ip->i_flag |= IN_CHANGE;
1556: /* If IN_ADIROP, account for it */
1.169.6.3! christos 1557: UFS_UNMARK_VNODE(tvp);
1.169.6.2 christos 1558: UFS_WAPBL_UPDATE(tvp, NULL, NULL, UPDATE_DIROP);
1559: if (DOINGSOFTDEP(tvp))
1560: softdep_change_linkcnt(ip);
1561: UFS_WAPBL_END(dvp->v_mount);
1562: vput(tvp);
1563: }
1564: out:
1565: PNBUF_PUT(cnp->cn_pnbuf);
1566: fstrans_done(dvp->v_mount);
1567: vput(dvp);
1568: return (error);
1569: }
1570:
1571: int
1572: ufs_rmdir(void *v)
1573: {
1574: struct vop_rmdir_args /* {
1575: struct vnode *a_dvp;
1576: struct vnode *a_vp;
1577: struct componentname *a_cnp;
1578: } */ *ap = v;
1579: struct vnode *vp, *dvp;
1580: struct componentname *cnp;
1581: struct inode *ip, *dp;
1582: int error;
1583: bool pace;
1584:
1585: vp = ap->a_vp;
1586: dvp = ap->a_dvp;
1587: cnp = ap->a_cnp;
1588: ip = VTOI(vp);
1589: dp = VTOI(dvp);
1590: /*
1591: * No rmdir "." or of mounted directories please.
1592: */
1593: if (dp == ip || vp->v_mountedhere != NULL) {
1594: if (dp == ip)
1595: vrele(vp);
1596: else
1597: vput(vp);
1598: vput(vp);
1599: return (EINVAL);
1600: }
1601:
1602: fstrans_start(dvp->v_mount, FSTRANS_SHARED);
1603:
1604: /*
1605: * Do not remove a directory that is in the process of being renamed.
1606: * Verify that the directory is empty (and valid). (Rmdir ".." won't
1607: * be valid since ".." will contain a reference to the current
1608: * directory and thus be non-empty.)
1609: */
1610: error = 0;
1611: if (ip->i_flag & IN_RENAME) {
1612: error = EINVAL;
1613: goto out;
1614: }
1615: if (ip->i_ffs_effnlink != 2 ||
1616: !ufs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
1617: error = ENOTEMPTY;
1618: goto out;
1619: }
1620: if ((dp->i_flags & APPEND) ||
1621: (ip->i_flags & (IMMUTABLE | APPEND))) {
1622: error = EPERM;
1623: goto out;
1624: }
1625: error = UFS_WAPBL_BEGIN(dvp->v_mount);
1626: if (error)
1627: goto out;
1628: /*
1629: * Delete reference to directory before purging
1630: * inode. If we crash in between, the directory
1631: * will be reattached to lost+found,
1632: */
1633: if (DOINGSOFTDEP(vp)) {
1634: dp->i_ffs_effnlink--;
1635: ip->i_ffs_effnlink--;
1636: softdep_change_linkcnt(dp);
1637: softdep_change_linkcnt(ip);
1638: }
1639: error = ufs_dirremove(dvp, ip, cnp->cn_flags, 1);
1640: if (error) {
1641: if (DOINGSOFTDEP(vp)) {
1642: dp->i_ffs_effnlink++;
1643: ip->i_ffs_effnlink++;
1644: softdep_change_linkcnt(dp);
1645: softdep_change_linkcnt(ip);
1646: }
1647: UFS_WAPBL_END(dvp->v_mount);
1648: goto out;
1649: }
1650: VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1651: cache_purge(dvp);
1652: /*
1653: * Truncate inode. The only stuff left in the directory is "." and
1654: * "..". The "." reference is inconsequential since we're quashing
1655: * it. The soft dependency code will arrange to do these operations
1656: * after the parent directory entry has been deleted on disk, so
1657: * when running with that code we avoid doing them now.
1658: */
1659: if (!DOINGSOFTDEP(vp)) {
1660: dp->i_nlink--;
1661: dp->i_ffs_effnlink--;
1662: DIP_ASSIGN(dp, nlink, dp->i_nlink);
1663: dp->i_flag |= IN_CHANGE;
1664: UFS_WAPBL_UPDATE(dvp, NULL, NULL, UPDATE_DIROP);
1665: ip->i_nlink--;
1666: ip->i_ffs_effnlink--;
1667: DIP_ASSIGN(ip, nlink, ip->i_nlink);
1668: ip->i_flag |= IN_CHANGE;
1669: error = UFS_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred);
1670: }
1671: cache_purge(vp);
1672: /*
1673: * Unlock the log while we still have reference to unlinked
1674: * directory vp so that it will not get locked for recycling
1675: */
1676: UFS_WAPBL_END(dvp->v_mount);
1677: #ifdef UFS_DIRHASH
1678: if (ip->i_dirhash != NULL)
1679: ufsdirhash_free(ip);
1680: #endif
1681: out:
1682: VN_KNOTE(vp, NOTE_DELETE);
1683: fstrans_done(dvp->v_mount);
1684: pace = DOINGSOFTDEP(dvp);
1685: vput(dvp);
1686: vput(vp);
1687: if (pace) {
1688: /*
1689: * Give the syncer some breathing room so that it
1690: * can flush removes. XXX
1691: */
1692: softdep_pace_dirrem();
1693: }
1694: return (error);
1695: }
1696:
1697: /*
1698: * symlink -- make a symbolic link
1699: */
1700: int
1701: ufs_symlink(void *v)
1702: {
1703: struct vop_symlink_args /* {
1704: struct vnode *a_dvp;
1705: struct vnode **a_vpp;
1706: struct componentname *a_cnp;
1707: struct vattr *a_vap;
1708: char *a_target;
1709: } */ *ap = v;
1710: struct vnode *vp, **vpp;
1711: struct inode *ip;
1712: int len, error;
1713:
1714: vpp = ap->a_vpp;
1715: /*
1716: * UFS_WAPBL_BEGIN1(dvp->v_mount, dvp) performed by successful
1717: * ufs_makeinode
1718: */
1719: fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED);
1720: error = ufs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
1721: vpp, ap->a_cnp);
1722: if (error)
1723: goto out;
1724: VN_KNOTE(ap->a_dvp, NOTE_WRITE);
1725: vp = *vpp;
1726: len = strlen(ap->a_target);
1727: ip = VTOI(vp);
1728: if (len < ip->i_ump->um_maxsymlinklen) {
1729: memcpy((char *)SHORTLINK(ip), ap->a_target, len);
1730: ip->i_size = len;
1731: DIP_ASSIGN(ip, size, len);
1732: uvm_vnp_setsize(vp, ip->i_size);
1733: ip->i_flag |= IN_CHANGE | IN_UPDATE;
1734: UFS_WAPBL_UPDATE(vp, NULL, NULL, 0);
1735: } else
1736: error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
1737: UIO_SYSSPACE, IO_NODELOCKED | IO_JOURNALLOCKED,
1738: ap->a_cnp->cn_cred, NULL, NULL);
1739: UFS_WAPBL_END1(ap->a_dvp->v_mount, ap->a_dvp);
1740: if (error)
1741: vput(vp);
1742: out:
1743: fstrans_done(ap->a_dvp->v_mount);
1744: return (error);
1745: }
1746:
1747: /*
1748: * Vnode op for reading directories.
1749: *
1750: * This routine handles converting from the on-disk directory format
1751: * "struct direct" to the in-memory format "struct dirent" as well as
1752: * byte swapping the entries if necessary.
1753: */
1754: int
1755: ufs_readdir(void *v)
1756: {
1757: struct vop_readdir_args /* {
1758: struct vnode *a_vp;
1759: struct uio *a_uio;
1760: kauth_cred_t a_cred;
1761: int *a_eofflag;
1762: off_t **a_cookies;
1763: int *ncookies;
1764: } */ *ap = v;
1765: struct vnode *vp = ap->a_vp;
1766: struct direct *cdp, *ecdp;
1767: struct dirent *ndp;
1768: char *cdbuf, *ndbuf, *endp;
1769: struct uio auio, *uio;
1770: struct iovec aiov;
1771: int error;
1772: size_t count, ccount, rcount;
1773: off_t off, *ccp;
1774: off_t startoff;
1775: size_t skipbytes;
1776: struct ufsmount *ump = VFSTOUFS(vp->v_mount);
1777: int nswap = UFS_MPNEEDSWAP(ump);
1778: #if BYTE_ORDER == LITTLE_ENDIAN
1779: int needswap = ump->um_maxsymlinklen <= 0 && nswap == 0;
1780: #else
1781: int needswap = ump->um_maxsymlinklen <= 0 && nswap != 0;
1782: #endif
1783: uio = ap->a_uio;
1784: count = uio->uio_resid;
1785: rcount = count - ((uio->uio_offset + count) & (ump->um_dirblksiz - 1));
1786:
1787: if (rcount < _DIRENT_MINSIZE(cdp) || count < _DIRENT_MINSIZE(ndp))
1788: return EINVAL;
1789:
1790: startoff = uio->uio_offset & ~(ump->um_dirblksiz - 1);
1791: skipbytes = uio->uio_offset - startoff;
1792: rcount += skipbytes;
1793:
1794: auio.uio_iov = &aiov;
1795: auio.uio_iovcnt = 1;
1796: auio.uio_offset = startoff;
1797: auio.uio_resid = rcount;
1798: UIO_SETUP_SYSSPACE(&auio);
1799: auio.uio_rw = UIO_READ;
1800: cdbuf = malloc(rcount, M_TEMP, M_WAITOK);
1801: aiov.iov_base = cdbuf;
1802: aiov.iov_len = rcount;
1803: error = VOP_READ(vp, &auio, 0, ap->a_cred);
1804: if (error != 0) {
1805: free(cdbuf, M_TEMP);
1806: return error;
1807: }
1808:
1809: rcount -= auio.uio_resid;
1810:
1811: cdp = (struct direct *)(void *)cdbuf;
1812: ecdp = (struct direct *)(void *)&cdbuf[rcount];
1813:
1814: ndbuf = malloc(count, M_TEMP, M_WAITOK);
1815: ndp = (struct dirent *)(void *)ndbuf;
1816: endp = &ndbuf[count];
1817:
1818: off = uio->uio_offset;
1819: if (ap->a_cookies) {
1820: ccount = rcount / _DIRENT_RECLEN(cdp, 1);
1821: ccp = *(ap->a_cookies) = malloc(ccount * sizeof(*ccp),
1822: M_TEMP, M_WAITOK);
1823: } else {
1824: /* XXX: GCC */
1825: ccount = 0;
1826: ccp = NULL;
1827: }
1828:
1829: while (cdp < ecdp) {
1830: cdp->d_reclen = ufs_rw16(cdp->d_reclen, nswap);
1831: if (skipbytes > 0) {
1832: if (cdp->d_reclen <= skipbytes) {
1833: skipbytes -= cdp->d_reclen;
1834: cdp = _DIRENT_NEXT(cdp);
1835: continue;
1836: }
1837: /*
1838: * invalid cookie.
1839: */
1840: error = EINVAL;
1841: goto out;
1842: }
1843: if (cdp->d_reclen == 0) {
1844: struct dirent *ondp = ndp;
1845: ndp->d_reclen = _DIRENT_MINSIZE(ndp);
1846: ndp = _DIRENT_NEXT(ndp);
1847: ondp->d_reclen = 0;
1848: cdp = ecdp;
1849: break;
1850: }
1851: if (needswap) {
1852: ndp->d_type = cdp->d_namlen;
1853: ndp->d_namlen = cdp->d_type;
1854: } else {
1855: ndp->d_type = cdp->d_type;
1856: ndp->d_namlen = cdp->d_namlen;
1857: }
1858: ndp->d_reclen = _DIRENT_RECLEN(ndp, ndp->d_namlen);
1859: if ((char *)(void *)ndp + ndp->d_reclen +
1860: _DIRENT_MINSIZE(ndp) > endp)
1861: break;
1862: ndp->d_fileno = ufs_rw32(cdp->d_ino, nswap);
1863: (void)memcpy(ndp->d_name, cdp->d_name, ndp->d_namlen);
1864: memset(&ndp->d_name[ndp->d_namlen], 0,
1865: ndp->d_reclen - _DIRENT_NAMEOFF(ndp) - ndp->d_namlen);
1866: off += cdp->d_reclen;
1867: if (ap->a_cookies) {
1868: KASSERT(ccp - *(ap->a_cookies) < ccount);
1869: *(ccp++) = off;
1870: }
1871: ndp = _DIRENT_NEXT(ndp);
1872: cdp = _DIRENT_NEXT(cdp);
1873: }
1874:
1875: count = ((char *)(void *)ndp - ndbuf);
1876: error = uiomove(ndbuf, count, uio);
1877: out:
1878: if (ap->a_cookies) {
1879: if (error) {
1880: free(*(ap->a_cookies), M_TEMP);
1881: *(ap->a_cookies) = NULL;
1882: *(ap->a_ncookies) = 0;
1883: } else {
1884: *ap->a_ncookies = ccp - *(ap->a_cookies);
1885: }
1886: }
1887: uio->uio_offset = off;
1888: free(ndbuf, M_TEMP);
1889: free(cdbuf, M_TEMP);
1890: *ap->a_eofflag = VTOI(vp)->i_size <= uio->uio_offset;
1891: return error;
1892: }
1893:
1894: /*
1895: * Return target name of a symbolic link
1896: */
1897: int
1898: ufs_readlink(void *v)
1899: {
1900: struct vop_readlink_args /* {
1901: struct vnode *a_vp;
1902: struct uio *a_uio;
1903: kauth_cred_t a_cred;
1904: } */ *ap = v;
1905: struct vnode *vp = ap->a_vp;
1906: struct inode *ip = VTOI(vp);
1907: struct ufsmount *ump = VFSTOUFS(vp->v_mount);
1908: int isize;
1909:
1910: isize = ip->i_size;
1911: if (isize < ump->um_maxsymlinklen ||
1912: (ump->um_maxsymlinklen == 0 && DIP(ip, blocks) == 0)) {
1913: uiomove((char *)SHORTLINK(ip), isize, ap->a_uio);
1914: return (0);
1915: }
1916: return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
1917: }
1918:
1919: /*
1920: * Calculate the logical to physical mapping if not done already,
1921: * then call the device strategy routine.
1922: */
1923: int
1924: ufs_strategy(void *v)
1925: {
1926: struct vop_strategy_args /* {
1927: struct vnode *a_vp;
1928: struct buf *a_bp;
1929: } */ *ap = v;
1930: struct buf *bp;
1931: struct vnode *vp;
1932: struct inode *ip;
1.169.6.3! christos 1933: struct mount *mp;
1.169.6.2 christos 1934: int error;
1935:
1936: bp = ap->a_bp;
1937: vp = ap->a_vp;
1938: ip = VTOI(vp);
1939: if (vp->v_type == VBLK || vp->v_type == VCHR)
1940: panic("ufs_strategy: spec");
1941: KASSERT(bp->b_bcount != 0);
1942: if (bp->b_blkno == bp->b_lblkno) {
1943: error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno,
1944: NULL);
1945: if (error) {
1946: bp->b_error = error;
1947: biodone(bp);
1948: return (error);
1949: }
1950: if (bp->b_blkno == -1) /* no valid data */
1951: clrbuf(bp);
1952: }
1953: if (bp->b_blkno < 0) { /* block is not on disk */
1954: biodone(bp);
1955: return (0);
1956: }
1957: vp = ip->i_devvp;
1.169.6.3! christos 1958:
! 1959: error = VOP_STRATEGY(vp, bp);
! 1960: if (error)
! 1961: return error;
! 1962:
! 1963: if (!BUF_ISREAD(bp))
! 1964: return 0;
! 1965:
! 1966: mp = wapbl_vptomp(vp);
! 1967: if (mp == NULL || mp->mnt_wapbl_replay == NULL ||
! 1968: !WAPBL_REPLAY_ISOPEN(mp) ||
! 1969: !WAPBL_REPLAY_CAN_READ(mp, bp->b_blkno, bp->b_bcount))
! 1970: return 0;
! 1971:
! 1972: error = biowait(bp);
! 1973: if (error)
! 1974: return error;
! 1975:
! 1976: error = WAPBL_REPLAY_READ(mp, bp->b_data, bp->b_blkno, bp->b_bcount);
! 1977: if (error) {
! 1978: mutex_enter(&bufcache_lock);
! 1979: SET(bp->b_cflags, BC_INVAL);
! 1980: mutex_exit(&bufcache_lock);
! 1981: }
! 1982: return error;
1.169.6.2 christos 1983: }
1984:
1985: /*
1986: * Print out the contents of an inode.
1987: */
1988: int
1989: ufs_print(void *v)
1990: {
1991: struct vop_print_args /* {
1992: struct vnode *a_vp;
1993: } */ *ap = v;
1994: struct vnode *vp;
1995: struct inode *ip;
1996:
1997: vp = ap->a_vp;
1998: ip = VTOI(vp);
1999: printf("tag VT_UFS, ino %llu, on dev %llu, %llu",
2000: (unsigned long long)ip->i_number,
2001: (unsigned long long)major(ip->i_dev),
2002: (unsigned long long)minor(ip->i_dev));
2003: printf(" flags 0x%x, effnlink %d, nlink %d\n",
2004: ip->i_flag, ip->i_ffs_effnlink, ip->i_nlink);
2005: printf("\tmode 0%o, owner %d, group %d, size %qd",
2006: ip->i_mode, ip->i_uid, ip->i_gid,
2007: (long long)ip->i_size);
2008: if (vp->v_type == VFIFO)
2009: fifo_printinfo(vp);
2010: printf("\n");
2011: return (0);
2012: }
2013:
2014: /*
2015: * Read wrapper for special devices.
2016: */
2017: int
2018: ufsspec_read(void *v)
2019: {
2020: struct vop_read_args /* {
2021: struct vnode *a_vp;
2022: struct uio *a_uio;
2023: int a_ioflag;
2024: kauth_cred_t a_cred;
2025: } */ *ap = v;
2026:
2027: /*
2028: * Set access flag.
2029: */
2030: if ((ap->a_vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0)
2031: VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
2032: return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap));
2033: }
2034:
2035: /*
2036: * Write wrapper for special devices.
2037: */
2038: int
2039: ufsspec_write(void *v)
2040: {
2041: struct vop_write_args /* {
2042: struct vnode *a_vp;
2043: struct uio *a_uio;
2044: int a_ioflag;
2045: kauth_cred_t a_cred;
2046: } */ *ap = v;
2047:
2048: /*
2049: * Set update and change flags.
2050: */
2051: if ((ap->a_vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0)
2052: VTOI(ap->a_vp)->i_flag |= IN_MODIFY;
2053: return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap));
2054: }
2055:
2056: /*
2057: * Close wrapper for special devices.
2058: *
2059: * Update the times on the inode then do device close.
2060: */
2061: int
2062: ufsspec_close(void *v)
2063: {
2064: struct vop_close_args /* {
2065: struct vnode *a_vp;
2066: int a_fflag;
2067: kauth_cred_t a_cred;
2068: } */ *ap = v;
2069: struct vnode *vp;
2070: struct inode *ip;
2071:
2072: vp = ap->a_vp;
2073: ip = VTOI(vp);
2074: if (vp->v_usecount > 1)
2075: UFS_ITIMES(vp, NULL, NULL, NULL);
2076: return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap));
2077: }
2078:
2079: /*
2080: * Read wrapper for fifo's
2081: */
2082: int
2083: ufsfifo_read(void *v)
2084: {
2085: struct vop_read_args /* {
2086: struct vnode *a_vp;
2087: struct uio *a_uio;
2088: int a_ioflag;
2089: kauth_cred_t a_cred;
2090: } */ *ap = v;
2091:
2092: /*
2093: * Set access flag.
2094: */
2095: VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
2096: return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap));
2097: }
2098:
2099: /*
2100: * Write wrapper for fifo's.
2101: */
2102: int
2103: ufsfifo_write(void *v)
2104: {
2105: struct vop_write_args /* {
2106: struct vnode *a_vp;
2107: struct uio *a_uio;
2108: int a_ioflag;
2109: kauth_cred_t a_cred;
2110: } */ *ap = v;
2111:
2112: /*
2113: * Set update and change flags.
2114: */
2115: VTOI(ap->a_vp)->i_flag |= IN_MODIFY;
2116: return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap));
2117: }
2118:
2119: /*
2120: * Close wrapper for fifo's.
2121: *
2122: * Update the times on the inode then do device close.
2123: */
2124: int
2125: ufsfifo_close(void *v)
2126: {
2127: struct vop_close_args /* {
2128: struct vnode *a_vp;
2129: int a_fflag;
2130: kauth_cred_t a_cred;
2131: } */ *ap = v;
2132: struct vnode *vp;
2133: struct inode *ip;
2134:
2135: vp = ap->a_vp;
2136: ip = VTOI(vp);
2137: if (ap->a_vp->v_usecount > 1)
2138: UFS_ITIMES(vp, NULL, NULL, NULL);
2139: return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_close), ap));
2140: }
2141:
2142: /*
2143: * Return POSIX pathconf information applicable to ufs filesystems.
2144: */
2145: int
2146: ufs_pathconf(void *v)
2147: {
2148: struct vop_pathconf_args /* {
2149: struct vnode *a_vp;
2150: int a_name;
2151: register_t *a_retval;
2152: } */ *ap = v;
2153:
2154: switch (ap->a_name) {
2155: case _PC_LINK_MAX:
2156: *ap->a_retval = LINK_MAX;
2157: return (0);
2158: case _PC_NAME_MAX:
2159: *ap->a_retval = NAME_MAX;
2160: return (0);
2161: case _PC_PATH_MAX:
2162: *ap->a_retval = PATH_MAX;
2163: return (0);
2164: case _PC_PIPE_BUF:
2165: *ap->a_retval = PIPE_BUF;
2166: return (0);
2167: case _PC_CHOWN_RESTRICTED:
2168: *ap->a_retval = 1;
2169: return (0);
2170: case _PC_NO_TRUNC:
2171: *ap->a_retval = 1;
2172: return (0);
2173: case _PC_SYNC_IO:
2174: *ap->a_retval = 1;
2175: return (0);
2176: case _PC_FILESIZEBITS:
2177: *ap->a_retval = 42;
2178: return (0);
2179: case _PC_SYMLINK_MAX:
2180: *ap->a_retval = MAXPATHLEN;
2181: return (0);
2182: case _PC_2_SYMLINKS:
2183: *ap->a_retval = 1;
2184: return (0);
2185: default:
2186: return (EINVAL);
2187: }
2188: /* NOTREACHED */
2189: }
2190:
2191: /*
2192: * Advisory record locking support
2193: */
2194: int
2195: ufs_advlock(void *v)
2196: {
2197: struct vop_advlock_args /* {
2198: struct vnode *a_vp;
2199: void * a_id;
2200: int a_op;
2201: struct flock *a_fl;
2202: int a_flags;
2203: } */ *ap = v;
2204: struct inode *ip;
2205:
2206: ip = VTOI(ap->a_vp);
2207: return lf_advlock(ap, &ip->i_lockf, ip->i_size);
2208: }
2209:
2210: /*
2211: * Initialize the vnode associated with a new inode, handle aliased
2212: * vnodes.
2213: */
2214: void
2215: ufs_vinit(struct mount *mntp, int (**specops)(void *), int (**fifoops)(void *),
2216: struct vnode **vpp)
2217: {
2218: struct timeval tv;
2219: struct inode *ip;
2220: struct vnode *vp;
2221: dev_t rdev;
2222: struct ufsmount *ump;
2223:
2224: vp = *vpp;
2225: ip = VTOI(vp);
2226: switch(vp->v_type = IFTOVT(ip->i_mode)) {
2227: case VCHR:
2228: case VBLK:
2229: vp->v_op = specops;
2230: ump = ip->i_ump;
2231: if (ump->um_fstype == UFS1)
2232: rdev = (dev_t)ufs_rw32(ip->i_ffs1_rdev,
2233: UFS_MPNEEDSWAP(ump));
2234: else
2235: rdev = (dev_t)ufs_rw64(ip->i_ffs2_rdev,
2236: UFS_MPNEEDSWAP(ump));
2237: spec_node_init(vp, rdev);
2238: break;
2239: case VFIFO:
2240: vp->v_op = fifoops;
2241: break;
2242: case VNON:
2243: case VBAD:
2244: case VSOCK:
2245: case VLNK:
2246: case VDIR:
2247: case VREG:
2248: break;
2249: }
2250: if (ip->i_number == ROOTINO)
2251: vp->v_vflag |= VV_ROOT;
2252: /*
2253: * Initialize modrev times
2254: */
2255: getmicrouptime(&tv);
2256: ip->i_modrev = (uint64_t)(uint)tv.tv_sec << 32
2257: | tv.tv_usec * 4294u;
2258: *vpp = vp;
2259: }
2260:
2261: /*
2262: * Allocate a new inode.
2263: */
2264: int
2265: ufs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
2266: struct componentname *cnp)
2267: {
2268: struct inode *ip, *pdir;
2269: struct direct *newdir;
2270: struct vnode *tvp;
2271: int error, ismember = 0;
2272:
2273: UFS_WAPBL_JUNLOCK_ASSERT(dvp->v_mount);
2274:
2275: pdir = VTOI(dvp);
2276: #ifdef DIAGNOSTIC
2277: if ((cnp->cn_flags & HASBUF) == 0)
2278: panic("ufs_makeinode: no name");
2279: #endif
2280: if ((mode & IFMT) == 0)
2281: mode |= IFREG;
2282:
2283: if ((error = UFS_VALLOC(dvp, mode, cnp->cn_cred, vpp)) != 0) {
2284: PNBUF_PUT(cnp->cn_pnbuf);
2285: vput(dvp);
2286: return (error);
2287: }
2288: tvp = *vpp;
2289: ip = VTOI(tvp);
2290: ip->i_gid = pdir->i_gid;
2291: DIP_ASSIGN(ip, gid, ip->i_gid);
2292: ip->i_uid = kauth_cred_geteuid(cnp->cn_cred);
2293: DIP_ASSIGN(ip, uid, ip->i_uid);
2294: error = UFS_WAPBL_BEGIN1(dvp->v_mount, dvp);
2295: if (error) {
2296: /*
2297: * Note, we can't VOP_VFREE(tvp) here like we should
2298: * because we can't write to the disk. Instead, we leave
2299: * the vnode dangling from the journal.
2300: */
2301: vput(tvp);
2302: PNBUF_PUT(cnp->cn_pnbuf);
2303: vput(dvp);
2304: return (error);
2305: }
2306: #ifdef QUOTA
2307: if ((error = chkiq(ip, 1, cnp->cn_cred, 0))) {
2308: UFS_VFREE(tvp, ip->i_number, mode);
2309: UFS_WAPBL_END1(dvp->v_mount, dvp);
2310: vput(tvp);
2311: PNBUF_PUT(cnp->cn_pnbuf);
2312: vput(dvp);
2313: return (error);
2314: }
2315: #endif
2316: ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
2317: ip->i_mode = mode;
2318: DIP_ASSIGN(ip, mode, mode);
2319: tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */
2320: ip->i_ffs_effnlink = 1;
2321: ip->i_nlink = 1;
2322: DIP_ASSIGN(ip, nlink, 1);
2323: if (DOINGSOFTDEP(tvp))
2324: softdep_change_linkcnt(ip);
2325: if ((ip->i_mode & ISGID) && (kauth_cred_ismember_gid(cnp->cn_cred,
2326: ip->i_gid, &ismember) != 0 || !ismember) &&
2327: kauth_authorize_generic(cnp->cn_cred, KAUTH_GENERIC_ISSUSER, NULL)) {
2328: ip->i_mode &= ~ISGID;
2329: DIP_ASSIGN(ip, mode, ip->i_mode);
2330: }
2331:
2332: if (cnp->cn_flags & ISWHITEOUT) {
2333: ip->i_flags |= UF_OPAQUE;
2334: DIP_ASSIGN(ip, flags, ip->i_flags);
2335: }
2336:
2337: /*
2338: * Make sure inode goes to disk before directory entry.
2339: */
2340: if ((error = UFS_UPDATE(tvp, NULL, NULL, UPDATE_DIROP)) != 0)
2341: goto bad;
2342: newdir = pool_cache_get(ufs_direct_cache, PR_WAITOK);
2343: ufs_makedirentry(ip, cnp, newdir);
2344: error = ufs_direnter(dvp, tvp, newdir, cnp, NULL);
2345: pool_cache_put(ufs_direct_cache, newdir);
2346: if (error)
2347: goto bad;
2348: if ((cnp->cn_flags & SAVESTART) == 0)
2349: PNBUF_PUT(cnp->cn_pnbuf);
2350: vput(dvp);
2351: *vpp = tvp;
2352: return (0);
2353:
2354: bad:
2355: /*
2356: * Write error occurred trying to update the inode
2357: * or the directory so must deallocate the inode.
2358: */
2359: ip->i_ffs_effnlink = 0;
2360: ip->i_nlink = 0;
2361: DIP_ASSIGN(ip, nlink, 0);
2362: ip->i_flag |= IN_CHANGE;
2363: /* If IN_ADIROP, account for it */
1.169.6.3! christos 2364: UFS_UNMARK_VNODE(tvp);
1.169.6.2 christos 2365: UFS_WAPBL_UPDATE(tvp, NULL, NULL, 0);
2366: if (DOINGSOFTDEP(tvp))
2367: softdep_change_linkcnt(ip);
2368: tvp->v_type = VNON; /* explodes later if VBLK */
2369: UFS_WAPBL_END1(dvp->v_mount, dvp);
2370: vput(tvp);
2371: PNBUF_PUT(cnp->cn_pnbuf);
2372: vput(dvp);
2373: return (error);
2374: }
2375:
2376: /*
2377: * Allocate len bytes at offset off.
2378: */
2379: int
2380: ufs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags,
2381: kauth_cred_t cred)
2382: {
2383: struct inode *ip = VTOI(vp);
2384: int error, delta, bshift, bsize;
2385: UVMHIST_FUNC("ufs_gop_alloc"); UVMHIST_CALLED(ubchist);
2386:
2387: error = 0;
2388: bshift = vp->v_mount->mnt_fs_bshift;
2389: bsize = 1 << bshift;
2390:
2391: delta = off & (bsize - 1);
2392: off -= delta;
2393: len += delta;
2394:
2395: while (len > 0) {
2396: bsize = MIN(bsize, len);
2397:
2398: error = UFS_BALLOC(vp, off, bsize, cred, flags, NULL);
2399: if (error) {
2400: goto out;
2401: }
2402:
2403: /*
2404: * increase file size now, UFS_BALLOC() requires that
2405: * EOF be up-to-date before each call.
2406: */
2407:
2408: if (ip->i_size < off + bsize) {
2409: UVMHIST_LOG(ubchist, "vp %p old 0x%x new 0x%x",
2410: vp, ip->i_size, off + bsize, 0);
2411: ip->i_size = off + bsize;
2412: DIP_ASSIGN(ip, size, ip->i_size);
2413: }
2414:
2415: off += bsize;
2416: len -= bsize;
2417: }
2418:
2419: out:
2420: UFS_WAPBL_UPDATE(vp, NULL, NULL, 0);
2421: return error;
2422: }
2423:
2424: void
2425: ufs_gop_markupdate(struct vnode *vp, int flags)
2426: {
2427: u_int32_t mask = 0;
2428:
2429: if ((flags & GOP_UPDATE_ACCESSED) != 0) {
2430: mask = IN_ACCESS;
2431: }
2432: if ((flags & GOP_UPDATE_MODIFIED) != 0) {
2433: if (vp->v_type == VREG) {
2434: mask |= IN_CHANGE | IN_UPDATE;
2435: } else {
2436: mask |= IN_MODIFY;
2437: }
2438: }
2439: if (mask) {
2440: struct inode *ip = VTOI(vp);
2441:
2442: ip->i_flag |= mask;
2443: }
2444: }
CVSweb <webmaster@jp.NetBSD.org>