2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
27 * Copyright (c) 1982, 1986, 1989, 1993, 1995
28 * The Regents of the University of California. All rights reserved.
29 * (c) UNIX System Laboratories, Inc.
30 * All or some portions of this file are derived from material licensed
31 * to the University of California by American Telephone and Telegraph
32 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
33 * the permission of UNIX System Laboratories, Inc.
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
43 * 3. All advertising materials mentioning features or use of this software
44 * must display the following acknowledgement:
45 * This product includes software developed by the University of
46 * California, Berkeley and its contributors.
47 * 4. Neither the name of the University nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * @(#)ufs_vnops.c 8.27 (Berkeley) 5/27/95
66 #include <rev_endian_fs.h>
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/namei.h>
70 #include <sys/resourcevar.h>
71 #include <sys/kernel.h>
77 #include <sys/mount.h>
78 #include <sys/vnode.h>
79 #include <sys/malloc.h>
80 #include <sys/dirent.h>
81 #include <sys/fcntl.h>
83 #include <sys/quota.h>
85 #include <kern/thread.h>
88 #include <miscfs/specfs/specdev.h>
90 #include <ufs/ufs/lockf.h>
91 #include <ufs/ufs/quota.h>
92 #include <ufs/ufs/inode.h>
93 #include <ufs/ufs/dir.h>
94 #include <ufs/ufs/ufsmount.h>
95 #include <ufs/ufs/ufs_extern.h>
98 #include <ufs/ufs/ufs_byte_order.h>
99 #include <architecture/byte_order.h>
100 #endif /* REV_ENDIAN_FS */
102 static int ufs_chmod
__P((struct vnode
*, int, struct ucred
*, struct proc
*));
104 __P((struct vnode
*, uid_t
, gid_t
, struct ucred
*, struct proc
*));
105 static int filt_ufsread
__P((struct knote
*kn
, long hint
));
106 static int filt_ufswrite
__P((struct knote
*kn
, long hint
));
107 static int filt_ufsvnode
__P((struct knote
*kn
, long hint
));
108 static void filt_ufsdetach
__P((struct knote
*kn
));
109 static int ufs_kqfilter
__P((struct vop_kqfilter_args
*ap
));
115 #define SETHIGH(q, h) { \
118 tmp.val[_QUAD_HIGHWORD] = (h); \
121 #define SETLOW(q, l) { \
124 tmp.val[_QUAD_LOWWORD] = (l); \
129 * Create a regular file
133 struct vop_create_args
/* {
135 struct vnode **a_vpp;
136 struct componentname *a_cnp;
143 ufs_makeinode(MAKEIMODE(ap
->a_vap
->va_type
, ap
->a_vap
->va_mode
),
144 ap
->a_dvp
, ap
->a_vpp
, ap
->a_cnp
))
146 VN_KNOTE(ap
->a_dvp
, NOTE_WRITE
);
156 struct vop_mknod_args
/* {
158 struct vnode **a_vpp;
159 struct componentname *a_cnp;
163 struct vattr
*vap
= ap
->a_vap
;
164 struct vnode
**vpp
= ap
->a_vpp
;
169 ufs_makeinode(MAKEIMODE(vap
->va_type
, vap
->va_mode
),
170 ap
->a_dvp
, vpp
, ap
->a_cnp
))
172 VN_KNOTE(ap
->a_dvp
, NOTE_WRITE
);
174 ip
->i_flag
|= IN_ACCESS
| IN_CHANGE
| IN_UPDATE
;
175 if (vap
->va_rdev
!= VNOVAL
) {
177 * Want to be able to use this to make badblock
178 * inodes, so don't truncate the dev number.
180 ip
->i_rdev
= vap
->va_rdev
;
183 * Remove inode so that it will be reloaded by VFS_VGET and
184 * checked to see if it is an alias of an existing entry in
188 (*vpp
)->v_type
= VNON
;
202 struct vop_open_args
/* {
205 struct ucred *a_cred;
211 * Files marked append-only must be opened for appending.
213 if ((VTOI(ap
->a_vp
)->i_flags
& APPEND
) &&
214 (ap
->a_mode
& (FWRITE
| O_APPEND
)) == FWRITE
)
222 * Update the times on the inode.
227 struct vop_close_args
/* {
230 struct ucred *a_cred;
234 register struct vnode
*vp
= ap
->a_vp
;
235 register struct inode
*ip
= VTOI(vp
);
237 simple_lock(&vp
->v_interlock
);
238 if ((!UBCISVALID(vp
) && vp
->v_usecount
> 1)
239 || (UBCISVALID(vp
) && ubc_isinuse(vp
, 1)))
240 ITIMES(ip
, &time
, &time
);
241 simple_unlock(&vp
->v_interlock
);
243 if (!VOP_ISLOCKED(vp
)) {
244 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, ap
->a_p
);
248 VOP_UNLOCK(vp
, 0, ap
->a_p
);
255 struct vop_access_args
/* {
258 struct ucred *a_cred;
262 struct vnode
*vp
= ap
->a_vp
;
263 struct inode
*ip
= VTOI(vp
);
264 struct ucred
*cred
= ap
->a_cred
;
265 mode_t mask
, mode
= ap
->a_mode
;
270 * Disallow write attempts on read-only file systems;
271 * unless the file is a socket, fifo, or a block or
272 * character device resident on the file system.
275 switch (vp
->v_type
) {
279 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
282 if (error
= getinoquota(ip
))
289 /* If immutable bit set, nobody gets to write it. */
290 if ((mode
& VWRITE
) && (ip
->i_flags
& IMMUTABLE
))
293 /* Otherwise, user id 0 always gets access. */
294 if (cred
->cr_uid
== 0)
299 /* Otherwise, check the owner. */
300 if (cred
->cr_uid
== ip
->i_uid
) {
307 return ((ip
->i_mode
& mask
) == mask
? 0 : EACCES
);
310 /* Otherwise, check the groups. */
311 for (i
= 0, gp
= cred
->cr_groups
; i
< cred
->cr_ngroups
; i
++, gp
++)
312 if (ip
->i_gid
== *gp
) {
319 return ((ip
->i_mode
& mask
) == mask
? 0 : EACCES
);
322 /* Otherwise, check everyone else. */
329 return ((ip
->i_mode
& mask
) == mask
? 0 : EACCES
);
335 struct vop_getattr_args
/* {
338 struct ucred *a_cred;
342 register struct vnode
*vp
= ap
->a_vp
;
343 register struct inode
*ip
= VTOI(vp
);
344 register struct vattr
*vap
= ap
->a_vap
;
347 ITIMES(ip
, &time
, &time
);
349 * Copy from inode table
351 vap
->va_fsid
= ip
->i_dev
;
352 vap
->va_fileid
= ip
->i_number
;
353 vap
->va_mode
= ip
->i_mode
& ~IFMT
;
354 vap
->va_nlink
= ip
->i_nlink
;
355 vap
->va_uid
= ip
->i_uid
;
356 vap
->va_gid
= ip
->i_gid
;
357 vap
->va_rdev
= (dev_t
)ip
->i_rdev
;
358 vap
->va_size
= ip
->i_din
.di_size
;
359 vap
->va_atime
.tv_sec
= ip
->i_atime
;
360 vap
->va_atime
.tv_nsec
= ip
->i_atimensec
;
361 vap
->va_mtime
.tv_sec
= ip
->i_mtime
;
362 vap
->va_mtime
.tv_nsec
= ip
->i_mtimensec
;
363 vap
->va_ctime
.tv_sec
= ip
->i_ctime
;
364 vap
->va_ctime
.tv_nsec
= ip
->i_ctimensec
;
365 vap
->va_flags
= ip
->i_flags
;
366 vap
->va_gen
= ip
->i_gen
;
367 /* this doesn't belong here */
368 if (vp
->v_type
== VBLK
)
369 vap
->va_blocksize
= BLKDEV_IOSIZE
;
370 else if (vp
->v_type
== VCHR
)
371 vap
->va_blocksize
= MAXPHYSIO
;
373 vap
->va_blocksize
= vp
->v_mount
->mnt_stat
.f_iosize
;
374 VOP_DEVBLOCKSIZE(ip
->i_devvp
, &devBlockSize
);
375 vap
->va_bytes
= dbtob((u_quad_t
)ip
->i_blocks
, devBlockSize
);
376 vap
->va_type
= vp
->v_type
;
377 vap
->va_filerev
= ip
->i_modrev
;
382 * Set attribute vnode op. called from several syscalls
386 struct vop_setattr_args
/* {
389 struct ucred *a_cred;
393 struct vattr
*vap
= ap
->a_vap
;
394 struct vnode
*vp
= ap
->a_vp
;
395 struct inode
*ip
= VTOI(vp
);
396 struct ucred
*cred
= ap
->a_cred
;
397 struct proc
*p
= ap
->a_p
;
398 struct timeval atimeval
, mtimeval
;
402 * Check for unsettable attributes.
404 if ((vap
->va_type
!= VNON
) || (vap
->va_nlink
!= VNOVAL
) ||
405 (vap
->va_fsid
!= VNOVAL
) || (vap
->va_fileid
!= VNOVAL
) ||
406 (vap
->va_blocksize
!= VNOVAL
) || (vap
->va_rdev
!= VNOVAL
) ||
407 ((int)vap
->va_bytes
!= VNOVAL
) || (vap
->va_gen
!= VNOVAL
)) {
410 if (vap
->va_flags
!= VNOVAL
) {
411 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
413 if (cred
->cr_uid
!= ip
->i_uid
&&
414 (error
= suser(cred
, &p
->p_acflag
)))
416 if (cred
->cr_uid
== 0) {
417 if ((ip
->i_flags
& (SF_IMMUTABLE
| SF_APPEND
)) &&
420 ip
->i_flags
= vap
->va_flags
;
422 if (ip
->i_flags
& (SF_IMMUTABLE
| SF_APPEND
) ||
423 (vap
->va_flags
& UF_SETTABLE
) != vap
->va_flags
)
425 ip
->i_flags
&= SF_SETTABLE
;
426 ip
->i_flags
|= (vap
->va_flags
& UF_SETTABLE
);
428 ip
->i_flag
|= IN_CHANGE
;
429 if (vap
->va_flags
& (IMMUTABLE
| APPEND
))
432 if (ip
->i_flags
& (IMMUTABLE
| APPEND
))
435 * Go through the fields and update iff not VNOVAL.
437 if (vap
->va_uid
!= (uid_t
)VNOVAL
|| vap
->va_gid
!= (gid_t
)VNOVAL
) {
438 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
440 if (error
= ufs_chown(vp
, vap
->va_uid
, vap
->va_gid
, cred
, p
))
443 if (vap
->va_size
!= VNOVAL
) {
445 * Disallow write attempts on read-only file systems;
446 * unless the file is a socket, fifo, or a block or
447 * character device resident on the file system.
449 switch (vp
->v_type
) {
454 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
458 if (error
= VOP_TRUNCATE(vp
, vap
->va_size
, 0, cred
, p
))
462 if (vap
->va_atime
.tv_sec
!= VNOVAL
|| vap
->va_mtime
.tv_sec
!= VNOVAL
) {
463 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
465 if (cred
->cr_uid
!= ip
->i_uid
&&
466 (error
= suser(cred
, &p
->p_acflag
)) &&
467 ((vap
->va_vaflags
& VA_UTIMES_NULL
) == 0 ||
468 (error
= VOP_ACCESS(vp
, VWRITE
, cred
, p
))))
470 if (vap
->va_atime
.tv_sec
!= VNOVAL
)
471 ip
->i_flag
|= IN_ACCESS
;
472 if (vap
->va_mtime
.tv_sec
!= VNOVAL
)
473 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
474 atimeval
.tv_sec
= vap
->va_atime
.tv_sec
;
475 atimeval
.tv_usec
= vap
->va_atime
.tv_nsec
/ 1000;
476 mtimeval
.tv_sec
= vap
->va_mtime
.tv_sec
;
477 mtimeval
.tv_usec
= vap
->va_mtime
.tv_nsec
/ 1000;
478 if (error
= VOP_UPDATE(vp
, &atimeval
, &mtimeval
, 1))
482 if (vap
->va_mode
!= (mode_t
)VNOVAL
) {
483 if (vp
->v_mount
->mnt_flag
& MNT_RDONLY
)
485 error
= ufs_chmod(vp
, (int)vap
->va_mode
, cred
, p
);
487 VN_KNOTE(vp
, NOTE_ATTRIB
);
492 * Change the mode on a file.
493 * Inode must be locked before calling.
496 ufs_chmod(vp
, mode
, cred
, p
)
497 register struct vnode
*vp
;
499 register struct ucred
*cred
;
502 register struct inode
*ip
= VTOI(vp
);
505 if (cred
->cr_uid
!= ip
->i_uid
&&
506 (error
= suser(cred
, &p
->p_acflag
)))
509 if (vp
->v_type
!= VDIR
&& (mode
& S_ISTXT
))
511 if (!groupmember(ip
->i_gid
, cred
) && (mode
& ISGID
))
514 ip
->i_mode
&= ~ALLPERMS
;
515 ip
->i_mode
|= (mode
& ALLPERMS
);
516 ip
->i_flag
|= IN_CHANGE
;
521 * Perform chown operation on inode ip;
522 * inode must be locked prior to call.
525 ufs_chown(vp
, uid
, gid
, cred
, p
)
526 register struct vnode
*vp
;
532 register struct inode
*ip
= VTOI(vp
);
538 int64_t change
; /* in bytes */
542 if (uid
== (uid_t
)VNOVAL
)
544 if (gid
== (gid_t
)VNOVAL
)
547 * If we don't own the file, are trying to change the owner
548 * of the file, or are not a member of the target group,
549 * the caller must be superuser or the call fails.
551 if ((cred
->cr_uid
!= ip
->i_uid
|| uid
!= ip
->i_uid
||
552 (gid
!= ip
->i_gid
&& !groupmember((gid_t
)gid
, cred
))) &&
553 (error
= suser(cred
, &p
->p_acflag
)))
558 if (error
= getinoquota(ip
))
561 dqrele(vp
, ip
->i_dquot
[USRQUOTA
]);
562 ip
->i_dquot
[USRQUOTA
] = NODQUOT
;
565 dqrele(vp
, ip
->i_dquot
[GRPQUOTA
]);
566 ip
->i_dquot
[GRPQUOTA
] = NODQUOT
;
568 VOP_DEVBLOCKSIZE(ip
->i_devvp
, &devBlockSize
);
569 change
= dbtob((int64_t)ip
->i_blocks
, devBlockSize
);
570 (void) chkdq(ip
, -change
, cred
, CHOWN
);
571 (void) chkiq(ip
, -1, cred
, CHOWN
);
572 for (i
= 0; i
< MAXQUOTAS
; i
++) {
573 dqrele(vp
, ip
->i_dquot
[i
]);
574 ip
->i_dquot
[i
] = NODQUOT
;
580 if ((error
= getinoquota(ip
)) == 0) {
582 dqrele(vp
, ip
->i_dquot
[USRQUOTA
]);
583 ip
->i_dquot
[USRQUOTA
] = NODQUOT
;
586 dqrele(vp
, ip
->i_dquot
[GRPQUOTA
]);
587 ip
->i_dquot
[GRPQUOTA
] = NODQUOT
;
589 if ((error
= chkdq(ip
, change
, cred
, CHOWN
)) == 0) {
590 if ((error
= chkiq(ip
, 1, cred
, CHOWN
)) == 0)
593 (void) chkdq(ip
, -change
, cred
, CHOWN
|FORCE
);
595 for (i
= 0; i
< MAXQUOTAS
; i
++) {
596 dqrele(vp
, ip
->i_dquot
[i
]);
597 ip
->i_dquot
[i
] = NODQUOT
;
602 if (getinoquota(ip
) == 0) {
604 dqrele(vp
, ip
->i_dquot
[USRQUOTA
]);
605 ip
->i_dquot
[USRQUOTA
] = NODQUOT
;
608 dqrele(vp
, ip
->i_dquot
[GRPQUOTA
]);
609 ip
->i_dquot
[GRPQUOTA
] = NODQUOT
;
611 (void) chkdq(ip
, change
, cred
, FORCE
|CHOWN
);
612 (void) chkiq(ip
, 1, cred
, FORCE
|CHOWN
);
613 (void) getinoquota(ip
);
618 panic("chown: lost quota");
620 if (ouid
!= uid
|| ogid
!= gid
)
621 ip
->i_flag
|= IN_CHANGE
;
622 if (ouid
!= uid
&& cred
->cr_uid
!= 0)
623 ip
->i_mode
&= ~ISUID
;
624 if (ogid
!= gid
&& cred
->cr_uid
!= 0)
625 ip
->i_mode
&= ~ISGID
;
632 struct vop_ioctl_args
/* {
637 struct ucred *a_cred;
642 switch (ap
->a_command
) {
645 { register struct inode
*ip
;
646 register struct vnode
*vp
;
647 register struct fs
*fs
;
648 register struct radvisory
*ra
;
649 int devBlockSize
= 0;
654 VOP_LEASE(vp
, ap
->a_p
, ap
->a_cred
, LEASE_READ
);
655 vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, ap
->a_p
);
657 ra
= (struct radvisory
*)(ap
->a_data
);
661 if ((u_int64_t
)ra
->ra_offset
>= ip
->i_size
) {
662 VOP_UNLOCK(vp
, 0, ap
->a_p
);
665 VOP_DEVBLOCKSIZE(ip
->i_devvp
, &devBlockSize
);
667 error
= advisory_read(vp
, ip
->i_size
, ra
->ra_offset
, ra
->ra_count
, devBlockSize
);
668 VOP_UNLOCK(vp
, 0, ap
->a_p
);
679 struct vop_select_args
/* {
683 struct ucred *a_cred;
690 * We should really check to see if I/O is possible.
698 * NB Currently unsupported.
703 struct vop_mmap_args
/* {
706 struct ucred *a_cred;
717 * Nothing to do, so just return.
722 struct vop_seek_args
/* {
726 struct ucred *a_cred;
735 struct vop_remove_args
/* {
738 struct componentname *a_cnp;
742 struct vnode
*vp
= ap
->a_vp
;
743 struct vnode
*dvp
= ap
->a_dvp
;
747 if ((ip
->i_flags
& (IMMUTABLE
| APPEND
)) ||
748 (VTOI(dvp
)->i_flags
& APPEND
)) {
753 if (ap
->a_cnp
->cn_flags
& NODELETEBUSY
) {
754 /* Caller requested Carbon delete semantics */
755 if ((!UBCISVALID(vp
) && vp
->v_usecount
> 1)
756 || (UBCISVALID(vp
) && ubc_isinuse(vp
, 1))) {
762 if ((error
= ufs_dirremove(dvp
, ap
->a_cnp
)) == 0) {
764 ip
->i_flag
|= IN_CHANGE
;
765 VN_KNOTE(vp
, NOTE_DELETE
);
766 VN_KNOTE(dvp
, NOTE_WRITE
);
770 VOP_UNLOCK(vp
, 0, ap
->a_cnp
->cn_proc
);
772 (void) ubc_uncache(vp
);
793 struct vop_link_args
/* {
795 struct vnode *a_tdvp;
796 struct componentname *a_cnp;
799 struct vnode
*vp
= ap
->a_vp
;
800 struct vnode
*tdvp
= ap
->a_tdvp
;
801 struct componentname
*cnp
= ap
->a_cnp
;
802 struct proc
*p
= cnp
->cn_proc
;
808 if ((cnp
->cn_flags
& HASBUF
) == 0)
809 panic("ufs_link: no name");
811 if (tdvp
->v_mount
!= vp
->v_mount
) {
812 VOP_ABORTOP(tdvp
, cnp
);
816 if (tdvp
!= vp
&& (error
= vn_lock(vp
, LK_EXCLUSIVE
, p
))) {
817 VOP_ABORTOP(tdvp
, cnp
);
821 if ((nlink_t
)ip
->i_nlink
>= LINK_MAX
) {
822 VOP_ABORTOP(tdvp
, cnp
);
826 if (ip
->i_flags
& (IMMUTABLE
| APPEND
)) {
827 VOP_ABORTOP(tdvp
, cnp
);
832 ip
->i_flag
|= IN_CHANGE
;
834 error
= VOP_UPDATE(vp
, &tv
, &tv
, 1);
836 error
= ufs_direnter(ip
, tdvp
, cnp
);
839 ip
->i_flag
|= IN_CHANGE
;
842 char *tmp
= cnp
->cn_pnbuf
;
843 cnp
->cn_pnbuf
= NULL
;
844 cnp
->cn_flags
&= ~HASBUF
;
845 FREE_ZONE(tmp
, cnp
->cn_pnlen
, M_NAMEI
);
847 VN_KNOTE(vp
, NOTE_LINK
);
848 VN_KNOTE(tdvp
, NOTE_WRITE
);
851 VOP_UNLOCK(vp
, 0, p
);
858 * whiteout vnode call
862 struct vop_whiteout_args
/* {
864 struct componentname *a_cnp;
868 struct vnode
*dvp
= ap
->a_dvp
;
869 struct componentname
*cnp
= ap
->a_cnp
;
870 struct direct newdir
;
873 switch (ap
->a_flags
) {
875 /* 4.4 format directories support whiteout operations */
876 if (dvp
->v_mount
->mnt_maxsymlinklen
> 0)
881 /* create a new directory whiteout */
883 if ((cnp
->cn_flags
& HASBUF
) == 0)
884 panic("ufs_whiteout: missing name");
885 if (dvp
->v_mount
->mnt_maxsymlinklen
<= 0)
886 panic("ufs_whiteout: old format filesystem");
890 newdir
.d_namlen
= cnp
->cn_namelen
;
891 bcopy(cnp
->cn_nameptr
, newdir
.d_name
, (unsigned)cnp
->cn_namelen
+ 1);
892 newdir
.d_type
= DT_WHT
;
893 error
= ufs_direnter2(dvp
, &newdir
, cnp
->cn_cred
, cnp
->cn_proc
);
897 /* remove an existing directory whiteout */
899 if (dvp
->v_mount
->mnt_maxsymlinklen
<= 0)
900 panic("ufs_whiteout: old format filesystem");
903 cnp
->cn_flags
&= ~DOWHITEOUT
;
904 error
= ufs_dirremove(dvp
, cnp
);
907 if (cnp
->cn_flags
& HASBUF
) {
908 char *tmp
= cnp
->cn_pnbuf
;
909 cnp
->cn_pnbuf
= NULL
;
910 cnp
->cn_flags
&= ~HASBUF
;
911 FREE_ZONE(tmp
, cnp
->cn_pnlen
, M_NAMEI
);
918 * Rename system call.
919 * rename("foo", "bar");
922 * link("foo", "bar");
924 * but ``atomically''. Can't do full commit without saving state in the
925 * inode on disk which isn't feasible at this time. Best we can do is
926 * always guarantee the target exists.
928 * Basic algorithm is:
930 * 1) Bump link count on source while we're linking it to the
931 * target. This also ensure the inode won't be deleted out
932 * from underneath us while we work (it may be truncated by
933 * a concurrent `trunc' or `open' for creation).
934 * 2) Link source to destination. If destination already exists,
936 * 3) Unlink source reference to inode if still around. If a
937 * directory was moved and the parent of the destination
938 * is different from the source, patch the ".." entry in the
943 struct vop_rename_args
/* {
944 struct vnode *a_fdvp;
946 struct componentname *a_fcnp;
947 struct vnode *a_tdvp;
949 struct componentname *a_tcnp;
952 struct vnode
*tvp
= ap
->a_tvp
;
953 register struct vnode
*tdvp
= ap
->a_tdvp
;
954 struct vnode
*fvp
= ap
->a_fvp
;
955 struct vnode
*fdvp
= ap
->a_fdvp
;
956 struct componentname
*tcnp
= ap
->a_tcnp
;
957 struct componentname
*fcnp
= ap
->a_fcnp
;
958 struct proc
*p
= fcnp
->cn_proc
;
959 struct inode
*ip
, *xp
, *dp
;
960 struct dirtemplate dirbuf
;
962 int doingdirectory
= 0, oldparent
= 0, newparent
= 0;
963 int error
= 0, ioflag
;
967 if ((tcnp
->cn_flags
& HASBUF
) == 0 ||
968 (fcnp
->cn_flags
& HASBUF
) == 0)
969 panic("ufs_rename: no name");
972 * Check for cross-device rename.
974 if ((fvp
->v_mount
!= tdvp
->v_mount
) ||
975 (tvp
&& (fvp
->v_mount
!= tvp
->v_mount
))) {
978 VOP_ABORTOP(tdvp
, tcnp
); /* XXX, why not in NFS? */
985 VOP_ABORTOP(fdvp
, fcnp
); /* XXX, why not in NFS? */
992 * Check if just deleting a link name.
994 if (tvp
&& ((VTOI(tvp
)->i_flags
& (IMMUTABLE
| APPEND
)) ||
995 (VTOI(tdvp
)->i_flags
& APPEND
))) {
1000 if (fvp
->v_type
== VDIR
) {
1005 /* Release destination completely. */
1006 VOP_ABORTOP(tdvp
, tcnp
);
1010 /* Delete source. */
1013 fcnp
->cn_flags
&= ~MODMASK
;
1014 fcnp
->cn_flags
|= LOCKPARENT
| LOCKLEAF
;
1015 if ((fcnp
->cn_flags
& SAVESTART
) == 0)
1016 panic("ufs_rename: lost from startdir");
1017 fcnp
->cn_nameiop
= DELETE
;
1018 (void) relookup(fdvp
, &fvp
, fcnp
);
1019 return (VOP_REMOVE(fdvp
, fvp
, fcnp
));
1021 if (error
= vn_lock(fvp
, LK_EXCLUSIVE
, p
))
1025 if ((ip
->i_flags
& (IMMUTABLE
| APPEND
)) || (dp
->i_flags
& APPEND
)) {
1026 VOP_UNLOCK(fvp
, 0, p
);
1030 if ((ip
->i_mode
& IFMT
) == IFDIR
) {
1032 * Avoid ".", "..", and aliases of "." for obvious reasons.
1034 if ((fcnp
->cn_namelen
== 1 && fcnp
->cn_nameptr
[0] == '.') ||
1035 dp
== ip
|| (fcnp
->cn_flags
&ISDOTDOT
) ||
1036 (ip
->i_flag
& IN_RENAME
)) {
1037 VOP_UNLOCK(fvp
, 0, p
);
1041 ip
->i_flag
|= IN_RENAME
;
1042 oldparent
= dp
->i_number
;
1045 VN_KNOTE(fdvp
, NOTE_WRITE
); /* XXX right place? */
1049 * When the target exists, both the directory
1050 * and target vnodes are returned locked.
1058 * 1) Bump link count while we're moving stuff
1059 * around. If we crash somewhere before
1060 * completing our work, the link count
1061 * may be wrong, but correctable.
1064 ip
->i_flag
|= IN_CHANGE
;
1066 if (error
= VOP_UPDATE(fvp
, &tv
, &tv
, 1)) {
1067 VOP_UNLOCK(fvp
, 0, p
);
1072 * If ".." must be changed (ie the directory gets a new
1073 * parent) then the source directory must not be in the
1074 * directory heirarchy above the target, as this would
1075 * orphan everything below the source directory. Also
1076 * the user must have write permission in the source so
1077 * as to be able to change "..". We must repeat the call
1078 * to namei, as the parent directory is unlocked by the
1079 * call to checkpath().
1081 error
= VOP_ACCESS(fvp
, VWRITE
, tcnp
->cn_cred
, tcnp
->cn_proc
);
1082 VOP_UNLOCK(fvp
, 0, p
);
1083 if (oldparent
!= dp
->i_number
)
1084 newparent
= dp
->i_number
;
1085 if (doingdirectory
&& newparent
) {
1086 if (error
) /* write access check above */
1090 if (error
= ufs_checkpath(ip
, dp
, tcnp
->cn_cred
))
1092 if ((tcnp
->cn_flags
& SAVESTART
) == 0)
1093 panic("ufs_rename: lost to startdir");
1094 if (error
= relookup(tdvp
, &tvp
, tcnp
))
1102 * 2) If target doesn't exist, link the target
1103 * to the source and unlink the source.
1104 * Otherwise, rewrite the target directory
1105 * entry to reference the source inode and
1106 * expunge the original entry's existence.
1109 if (dp
->i_dev
!= ip
->i_dev
)
1110 panic("rename: EXDEV");
1112 * Account for ".." in new directory.
1113 * When source and destination have the same
1114 * parent we don't fool with the link count.
1116 if (doingdirectory
&& newparent
) {
1117 if ((nlink_t
)dp
->i_nlink
>= LINK_MAX
) {
1122 dp
->i_flag
|= IN_CHANGE
;
1123 if (error
= VOP_UPDATE(tdvp
, &tv
, &tv
, 1))
1126 if (error
= ufs_direnter(ip
, tdvp
, tcnp
)) {
1127 if (doingdirectory
&& newparent
) {
1129 dp
->i_flag
|= IN_CHANGE
;
1130 (void)VOP_UPDATE(tdvp
, &tv
, &tv
, 1);
1134 VN_KNOTE(tdvp
, NOTE_WRITE
);
1137 if (xp
->i_dev
!= dp
->i_dev
|| xp
->i_dev
!= ip
->i_dev
)
1138 panic("rename: EXDEV");
1140 * Short circuit rename(foo, foo).
1142 if (xp
->i_number
== ip
->i_number
)
1143 panic("rename: same file");
1145 * If the parent directory is "sticky", then the user must
1146 * own the parent directory, or the destination of the rename,
1147 * otherwise the destination may not be changed (except by
1148 * root). This implements append-only directories.
1150 if ((dp
->i_mode
& S_ISTXT
) && tcnp
->cn_cred
->cr_uid
!= 0 &&
1151 tcnp
->cn_cred
->cr_uid
!= dp
->i_uid
&&
1152 xp
->i_uid
!= tcnp
->cn_cred
->cr_uid
) {
1157 * Target must be empty if a directory and have no links
1158 * to it. Also, ensure source and target are compatible
1159 * (both directories, or both not directories).
1161 if ((xp
->i_mode
&IFMT
) == IFDIR
) {
1162 if (!ufs_dirempty(xp
, dp
->i_number
, tcnp
->cn_cred
) ||
1167 if (!doingdirectory
) {
1172 } else if (doingdirectory
) {
1176 if (error
= ufs_dirrewrite(dp
, ip
, tcnp
))
1179 * If the target directory is in the same
1180 * directory as the source directory,
1181 * decrement the link count on the parent
1182 * of the target directory.
1184 if (doingdirectory
&& !newparent
) {
1186 dp
->i_flag
|= IN_CHANGE
;
1188 VN_KNOTE(tdvp
, NOTE_WRITE
);
1191 * Adjust the link count of the target to
1192 * reflect the dirrewrite above. If this is
1193 * a directory it is empty and there are
1194 * no links to it, so we can squash the inode and
1195 * any space associated with it. We disallowed
1196 * renaming over top of a directory with links to
1197 * it above, as the remaining link would point to
1198 * a directory without "." or ".." entries.
1201 if (doingdirectory
) {
1202 if (--xp
->i_nlink
!= 0)
1203 panic("rename: linked directory");
1204 ioflag
= ((tvp
)->v_mount
->mnt_flag
& MNT_ASYNC
) ?
1206 error
= VOP_TRUNCATE(tvp
, (off_t
)0, ioflag
,
1207 tcnp
->cn_cred
, tcnp
->cn_proc
);
1209 xp
->i_flag
|= IN_CHANGE
;
1210 VN_KNOTE(tvp
, NOTE_DELETE
);
1216 * 3) Unlink the source.
1218 fcnp
->cn_flags
&= ~MODMASK
;
1219 fcnp
->cn_flags
|= LOCKPARENT
| LOCKLEAF
;
1220 if ((fcnp
->cn_flags
& SAVESTART
) == 0)
1221 panic("ufs_rename: lost from startdir");
1222 (void) relookup(fdvp
, &fvp
, fcnp
);
1228 * From name has disappeared.
1231 panic("rename: lost dir entry");
1236 * Ensure that the directory entry still exists and has not
1237 * changed while the new name has been entered. If the source is
1238 * a file then the entry may have been unlinked or renamed. In
1239 * either case there is no further work to be done. If the source
1240 * is a directory then it cannot have been rmdir'ed; its link
1241 * count of three would cause a rmdir to fail with ENOTEMPTY.
1242 * The IRENAME flag ensures that it cannot be moved by another
1247 panic("rename: lost dir entry");
1250 * If the source is a directory with a
1251 * new parent, the link count of the old
1252 * parent directory must be decremented
1253 * and ".." set to point to the new parent.
1255 if (doingdirectory
&& newparent
) {
1257 dp
->i_flag
|= IN_CHANGE
;
1258 error
= vn_rdwr(UIO_READ
, fvp
, (caddr_t
)&dirbuf
,
1259 sizeof (struct dirtemplate
), (off_t
)0,
1260 UIO_SYSSPACE
, IO_NODELOCKED
,
1261 tcnp
->cn_cred
, (int *)0, (struct proc
*)0);
1263 # if (BYTE_ORDER == LITTLE_ENDIAN)
1264 if (fvp
->v_mount
->mnt_maxsymlinklen
<= 0)
1265 namlen
= dirbuf
.dotdot_type
;
1267 namlen
= dirbuf
.dotdot_namlen
;
1269 namlen
= dirbuf
.dotdot_namlen
;
1272 dirbuf
.dotdot_name
[0] != '.' ||
1273 dirbuf
.dotdot_name
[1] != '.') {
1274 ufs_dirbad(xp
, (doff_t
)12,
1275 "rename: mangled dir");
1277 dirbuf
.dotdot_ino
= newparent
;
1278 (void) vn_rdwr(UIO_WRITE
, fvp
,
1280 sizeof (struct dirtemplate
),
1281 (off_t
)0, UIO_SYSSPACE
,
1282 IO_NODELOCKED
|IO_SYNC
,
1283 tcnp
->cn_cred
, (int *)0,
1289 error
= ufs_dirremove(fdvp
, fcnp
);
1292 xp
->i_flag
|= IN_CHANGE
;
1294 xp
->i_flag
&= ~IN_RENAME
;
1296 VN_KNOTE(fvp
, NOTE_RENAME
);
1310 ip
->i_flag
&= ~IN_RENAME
;
1311 if (vn_lock(fvp
, LK_EXCLUSIVE
, p
) == 0) {
1313 ip
->i_flag
|= IN_CHANGE
;
1321 * A virgin directory (no blushing please).
1323 static struct dirtemplate mastertemplate
= {
1324 0, 12, DT_DIR
, 1, ".",
1325 0, DIRBLKSIZ
- 12, DT_DIR
, 2, ".."
1327 static struct odirtemplate omastertemplate
= {
1329 0, DIRBLKSIZ
- 12, 2, ".."
1337 struct vop_mkdir_args
/* {
1338 struct vnode *a_dvp;
1339 struct vnode **a_vpp;
1340 struct componentname *a_cnp;
1341 struct vattr *a_vap;
1344 register struct vnode
*dvp
= ap
->a_dvp
;
1345 register struct vattr
*vap
= ap
->a_vap
;
1346 register struct componentname
*cnp
= ap
->a_cnp
;
1347 register struct inode
*ip
, *dp
;
1349 struct dirtemplate dirtemplate
, *dtp
;
1354 if ((cnp
->cn_flags
& HASBUF
) == 0)
1355 panic("ufs_mkdir: no name");
1358 if ((nlink_t
)dp
->i_nlink
>= LINK_MAX
) {
1362 dmode
= vap
->va_mode
& 0777;
1365 * Must simulate part of ufs_makeinode here to acquire the inode,
1366 * but not have it entered in the parent directory. The entry is
1367 * made later after writing "." and ".." entries.
1369 if (error
= VOP_VALLOC(dvp
, dmode
, cnp
->cn_cred
, &tvp
))
1372 ip
->i_uid
= cnp
->cn_cred
->cr_uid
;
1373 ip
->i_gid
= dp
->i_gid
;
1375 if ((error
= getinoquota(ip
)) ||
1376 (error
= chkiq(ip
, 1, cnp
->cn_cred
, 0))) {
1377 char *tmp
= cnp
->cn_pnbuf
;
1378 cnp
->cn_pnbuf
= NULL
;
1379 cnp
->cn_flags
&= ~HASBUF
;
1380 FREE_ZONE(tmp
, cnp
->cn_pnlen
, M_NAMEI
);
1381 VOP_VFREE(tvp
, ip
->i_number
, dmode
);
1387 ip
->i_flag
|= IN_ACCESS
| IN_CHANGE
| IN_UPDATE
;
1389 tvp
->v_type
= VDIR
; /* Rest init'd in getnewvnode(). */
1391 if (cnp
->cn_flags
& ISWHITEOUT
)
1392 ip
->i_flags
|= UF_OPAQUE
;
1394 error
= VOP_UPDATE(tvp
, &tv
, &tv
, 1);
1397 * Bump link count in parent directory
1398 * to reflect work done below. Should
1399 * be done before reference is created
1400 * so reparation is possible if we crash.
1403 dp
->i_flag
|= IN_CHANGE
;
1404 if (error
= VOP_UPDATE(dvp
, &tv
, &tv
, 1))
1407 /* Initialize directory with "." and ".." from static template. */
1408 if (dvp
->v_mount
->mnt_maxsymlinklen
> 0)
1409 dtp
= &mastertemplate
;
1411 dtp
= (struct dirtemplate
*)&omastertemplate
;
1413 dirtemplate
.dot_ino
= ip
->i_number
;
1414 dirtemplate
.dotdot_ino
= dp
->i_number
;
1415 error
= vn_rdwr(UIO_WRITE
, tvp
, (caddr_t
)&dirtemplate
,
1416 sizeof (dirtemplate
), (off_t
)0, UIO_SYSSPACE
,
1417 IO_NODELOCKED
|IO_SYNC
, cnp
->cn_cred
, (int *)0, (struct proc
*)0);
1420 dp
->i_flag
|= IN_CHANGE
;
1423 if (DIRBLKSIZ
> VFSTOUFS(dvp
->v_mount
)->um_mountp
->mnt_stat
.f_bsize
)
1424 panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */
1426 ip
->i_size
= DIRBLKSIZ
;
1427 ip
->i_flag
|= IN_CHANGE
;
1430 /* Directory set up, now install it's entry in the parent directory. */
1431 if (error
= ufs_direnter(ip
, dvp
, cnp
)) {
1433 dp
->i_flag
|= IN_CHANGE
;
1437 * No need to do an explicit VOP_TRUNCATE here, vrele will do this
1438 * for us because we set the link count to 0.
1442 ip
->i_flag
|= IN_CHANGE
;
1445 VN_KNOTE(dvp
, NOTE_WRITE
| NOTE_LINK
);
1450 char *tmp
= cnp
->cn_pnbuf
;
1451 cnp
->cn_pnbuf
= NULL
;
1452 cnp
->cn_flags
&= ~HASBUF
;
1453 FREE_ZONE(tmp
, cnp
->cn_pnlen
, M_NAMEI
);
1460 * Rmdir system call.
1464 struct vop_rmdir_args
/* {
1465 struct vnode *a_dvp;
1467 struct componentname *a_cnp;
1470 struct vnode
*vp
= ap
->a_vp
;
1471 struct vnode
*dvp
= ap
->a_dvp
;
1472 struct componentname
*cnp
= ap
->a_cnp
;
1473 struct inode
*ip
, *dp
;
1479 * No rmdir "." please.
1487 * Verify the directory is empty (and valid).
1488 * (Rmdir ".." won't be valid since
1489 * ".." will contain a reference to
1490 * the current directory and thus be
1494 if (ip
->i_nlink
!= 2 ||
1495 !ufs_dirempty(ip
, dp
->i_number
, cnp
->cn_cred
)) {
1499 if ((dp
->i_flags
& APPEND
) || (ip
->i_flags
& (IMMUTABLE
| APPEND
))) {
1504 * Delete reference to directory before purging
1505 * inode. If we crash in between, the directory
1506 * will be reattached to lost+found,
1508 if (error
= ufs_dirremove(dvp
, cnp
))
1510 VN_KNOTE(dvp
, NOTE_WRITE
| NOTE_LINK
);
1512 dp
->i_flag
|= IN_CHANGE
;
1517 * Truncate inode. The only stuff left
1518 * in the directory is "." and "..". The
1519 * "." reference is inconsequential since
1520 * we're quashing it. The ".." reference
1521 * has already been adjusted above. We've
1522 * removed the "." reference and the reference
1523 * in the parent directory, but there may be
1524 * other hard links so decrement by 2 and
1525 * worry about them later.
1528 ioflag
= ((vp
)->v_mount
->mnt_flag
& MNT_ASYNC
) ? 0 : IO_SYNC
;
1529 error
= VOP_TRUNCATE(vp
, (off_t
)0, ioflag
, cnp
->cn_cred
,
1531 cache_purge(ITOV(ip
));
1535 VN_KNOTE(vp
, NOTE_DELETE
);
1541 * symlink -- make a symbolic link
1545 struct vop_symlink_args
/* {
1546 struct vnode *a_dvp;
1547 struct vnode **a_vpp;
1548 struct componentname *a_cnp;
1549 struct vattr *a_vap;
1553 register struct vnode
*vp
, **vpp
= ap
->a_vpp
;
1554 register struct inode
*ip
;
1557 if (error
= ufs_makeinode(IFLNK
| ap
->a_vap
->va_mode
, ap
->a_dvp
,
1560 VN_KNOTE(ap
->a_dvp
, NOTE_WRITE
);
1562 len
= strlen(ap
->a_target
);
1563 if (len
< vp
->v_mount
->mnt_maxsymlinklen
) {
1565 bcopy(ap
->a_target
, (char *)ip
->i_shortlink
, len
);
1567 ip
->i_flag
|= IN_CHANGE
| IN_UPDATE
;
1569 error
= vn_rdwr(UIO_WRITE
, vp
, ap
->a_target
, len
, (off_t
)0,
1570 UIO_SYSSPACE
, IO_NODELOCKED
, ap
->a_cnp
->cn_cred
, (int *)0,
1577 * Vnode op for reading directories.
1579 * The routine below assumes that the on-disk format of a directory
1580 * is the same as that defined by <sys/dirent.h>. If the on-disk
1581 * format changes, then it will be necessary to do a conversion
1582 * from the on-disk format that read returns to the format defined
1583 * by <sys/dirent.h>.
1587 struct vop_readdir_args
/* {
1590 struct ucred *a_cred;
1596 register struct uio
*uio
= ap
->a_uio
;
1599 off_t off
= uio
->uio_offset
;
1601 count
= uio
->uio_resid
;
1602 /* Make sure we don't return partial entries. */
1603 count
-= (uio
->uio_offset
+ count
) & (DIRBLKSIZ
-1);
1606 lost
= uio
->uio_resid
- count
;
1607 uio
->uio_resid
= count
;
1608 uio
->uio_iov
->iov_len
= count
;
1609 # if (BYTE_ORDER == LITTLE_ENDIAN)
1610 if (ap
->a_vp
->v_mount
->mnt_maxsymlinklen
> 0) {
1611 error
= VOP_READ(ap
->a_vp
, uio
, 0, ap
->a_cred
);
1613 struct dirent
*dp
, *edp
;
1621 auio
.uio_iov
= &aiov
;
1622 auio
.uio_iovcnt
= 1;
1623 auio
.uio_segflg
= UIO_SYSSPACE
;
1624 aiov
.iov_len
= count
;
1625 MALLOC(dirbuf
, caddr_t
, count
, M_TEMP
, M_WAITOK
);
1626 aiov
.iov_base
= dirbuf
;
1627 error
= VOP_READ(ap
->a_vp
, &auio
, 0, ap
->a_cred
);
1629 readcnt
= count
- auio
.uio_resid
;
1630 edp
= (struct dirent
*)&dirbuf
[readcnt
];
1631 for (dp
= (struct dirent
*)dirbuf
; dp
< edp
; ) {
1633 dp
->d_namlen
= dp
->d_type
;
1635 if (dp
->d_reclen
> 0) {
1636 dp
= (struct dirent
*)
1637 ((char *)dp
+ dp
->d_reclen
);
1644 error
= uiomove(dirbuf
, readcnt
, uio
);
1646 FREE(dirbuf
, M_TEMP
);
1649 error
= VOP_READ(ap
->a_vp
, uio
, 0, ap
->a_cred
);
1651 if (!error
&& ap
->a_ncookies
!= NULL
) {
1652 struct dirent
* dpStart
;
1653 struct dirent
* dpEnd
;
1660 * Only the NFS server uses cookies, and it loads the
1661 * directory block into system space, so we can just look at
1664 if (uio
->uio_segflg
!= UIO_SYSSPACE
|| uio
->uio_iovcnt
!= 1)
1665 panic("ufs_readdir: unexpected uio from NFS server");
1666 dpStart
= (struct dirent
*)
1667 (uio
->uio_iov
->iov_base
- (uio
->uio_offset
- off
));
1668 dpEnd
= (struct dirent
*) uio
->uio_iov
->iov_base
;
1669 for (dp
= dpStart
, ncookies
= 0;
1670 dp
< dpEnd
&& dp
->d_reclen
!= 0;
1671 dp
= (struct dirent
*)((caddr_t
)dp
+ dp
->d_reclen
))
1673 MALLOC(cookies
, u_long
*, ncookies
* sizeof(u_long
), M_TEMP
,
1675 for (dp
= dpStart
, cookiep
= cookies
;
1677 dp
= (struct dirent
*)((caddr_t
) dp
+ dp
->d_reclen
)) {
1678 off
+= dp
->d_reclen
;
1679 *cookiep
++ = (u_long
) off
;
1681 *ap
->a_ncookies
= ncookies
;
1682 *ap
->a_cookies
= cookies
;
1684 uio
->uio_resid
+= lost
;
1686 *ap
->a_eofflag
= VTOI(ap
->a_vp
)->i_size
<= uio
->uio_offset
;
1691 * Return target name of a symbolic link
1695 struct vop_readlink_args
/* {
1698 struct ucred *a_cred;
1701 register struct vnode
*vp
= ap
->a_vp
;
1702 register struct inode
*ip
= VTOI(vp
);
1706 if (isize
< vp
->v_mount
->mnt_maxsymlinklen
) {
1707 uiomove((char *)ip
->i_shortlink
, isize
, ap
->a_uio
);
1710 return (VOP_READ(vp
, ap
->a_uio
, 0, ap
->a_cred
));
1714 * Lock an inode. If its already locked, set the WANT bit and sleep.
1718 struct vop_lock_args
/* {
1724 struct vnode
*vp
= ap
->a_vp
;
1726 if (VTOI(vp
) == (struct inode
*)NULL
)
1727 panic("inode in vnode is null\n");
1728 return (lockmgr(&VTOI(vp
)->i_lock
, ap
->a_flags
, &vp
->v_interlock
,
1737 struct vop_unlock_args
/* {
1743 struct vnode
*vp
= ap
->a_vp
;
1745 return (lockmgr(&VTOI(vp
)->i_lock
, ap
->a_flags
| LK_RELEASE
,
1746 &vp
->v_interlock
, ap
->a_p
));
1750 * Check for a locked inode.
1754 struct vop_islocked_args
/* {
1759 return (lockstatus(&VTOI(ap
->a_vp
)->i_lock
));
1763 * Calculate the logical to physical mapping if not done already,
1764 * then call the device strategy routine.
1768 struct vop_strategy_args
/* {
1772 register struct buf
*bp
= ap
->a_bp
;
1773 register struct vnode
*vp
= bp
->b_vp
;
1774 register struct inode
*ip
;
1778 if ( !(bp
->b_flags
& B_VECTORLIST
)) {
1779 if (vp
->v_type
== VBLK
|| vp
->v_type
== VCHR
)
1780 panic("ufs_strategy: spec");
1783 if (bp
->b_flags
& B_PAGELIST
) {
1785 * if we have a page list associated with this bp,
1786 * then go through cluste_bp since it knows how to
1787 * deal with a page request that might span non-contiguous
1788 * physical blocks on the disk...
1791 if (bp
->b_blkno
== bp
->b_lblkno
) {
1792 if (error
= VOP_BMAP(vp
, bp
->b_lblkno
, NULL
,
1793 &bp
->b_blkno
, NULL
)) {
1794 bp
->b_error
= error
;
1795 bp
->b_flags
|= B_ERROR
;
1801 error
= cluster_bp(bp
);
1803 bp
->b_dev
= vp
->v_rdev
;
1808 if (bp
->b_blkno
== bp
->b_lblkno
) {
1810 VOP_BMAP(vp
, bp
->b_lblkno
, NULL
, &bp
->b_blkno
, NULL
)) {
1811 bp
->b_error
= error
;
1812 bp
->b_flags
|= B_ERROR
;
1816 if ((long)bp
->b_blkno
== -1)
1819 if ((long)bp
->b_blkno
== -1) {
1827 bp
->b_dev
= vp
->v_rdev
;
1828 VOCALL (vp
->v_op
, VOFFSET(vop_strategy
), ap
);
1833 * Print out the contents of an inode.
1837 struct vop_print_args
/* {
1841 register struct vnode
*vp
= ap
->a_vp
;
1842 register struct inode
*ip
= VTOI(vp
);
1844 printf("tag VT_UFS, ino %d, on dev %d, %d", ip
->i_number
,
1845 major(ip
->i_dev
), minor(ip
->i_dev
));
1847 if (vp
->v_type
== VFIFO
)
1850 lockmgr_printinfo(&ip
->i_lock
);
1856 * Read wrapper for special devices.
1860 struct vop_read_args
/* {
1864 struct ucred *a_cred;
1871 VTOI(ap
->a_vp
)->i_flag
|= IN_ACCESS
;
1872 return (VOCALL (spec_vnodeop_p
, VOFFSET(vop_read
), ap
));
1876 * Write wrapper for special devices.
1880 struct vop_write_args
/* {
1884 struct ucred *a_cred;
1889 * Set update and change flags.
1891 VTOI(ap
->a_vp
)->i_flag
|= IN_CHANGE
| IN_UPDATE
;
1892 return (VOCALL (spec_vnodeop_p
, VOFFSET(vop_write
), ap
));
1896 * Close wrapper for special devices.
1898 * Update the times on the inode then do device close.
1902 struct vop_close_args
/* {
1905 struct ucred *a_cred;
1909 struct vnode
*vp
= ap
->a_vp
;
1910 struct inode
*ip
= VTOI(vp
);
1912 simple_lock(&vp
->v_interlock
);
1913 if (ap
->a_vp
->v_usecount
> 1)
1914 ITIMES(ip
, &time
, &time
);
1915 simple_unlock(&vp
->v_interlock
);
1916 return (VOCALL (spec_vnodeop_p
, VOFFSET(vop_close
), ap
));
1921 * Read wrapper for fifo's
1925 struct vop_read_args
/* {
1929 struct ucred *a_cred;
1932 extern int (**fifo_vnodeop_p
)(void *);
1937 VTOI(ap
->a_vp
)->i_flag
|= IN_ACCESS
;
1938 return (VOCALL (fifo_vnodeop_p
, VOFFSET(vop_read
), ap
));
1942 * Write wrapper for fifo's.
1946 struct vop_write_args
/* {
1950 struct ucred *a_cred;
1953 extern int (**fifo_vnodeop_p
)(void *);
1956 * Set update and change flags.
1958 VTOI(ap
->a_vp
)->i_flag
|= IN_CHANGE
| IN_UPDATE
;
1959 return (VOCALL (fifo_vnodeop_p
, VOFFSET(vop_write
), ap
));
1963 * Close wrapper for fifo's.
1965 * Update the times on the inode then do device close.
1968 struct vop_close_args
/* {
1971 struct ucred *a_cred;
1975 extern int (**fifo_vnodeop_p
)(void *);
1976 struct vnode
*vp
= ap
->a_vp
;
1977 struct inode
*ip
= VTOI(vp
);
1979 simple_lock(&vp
->v_interlock
);
1980 if (ap
->a_vp
->v_usecount
> 1)
1981 ITIMES(ip
, &time
, &time
);
1982 simple_unlock(&vp
->v_interlock
);
1983 return (VOCALL (fifo_vnodeop_p
, VOFFSET(vop_close
), ap
));
1987 * kqfilt_add wrapper for fifos.
1989 * Fall through to ufs kqfilt_add routines if needed
1992 ufsfifo_kqfilt_add(ap
)
1993 struct vop_kqfilt_add_args
*ap
;
1995 extern int (**fifo_vnodeop_p
)(void *);
1998 error
= VOCALL(fifo_vnodeop_p
, VOFFSET(vop_kqfilt_add
), ap
);
2000 error
= ufs_kqfilt_add(ap
);
2006 * kqfilt_remove wrapper for fifos.
2008 * Fall through to ufs kqfilt_remove routines if needed
2011 ufsfifo_kqfilt_remove(ap
)
2012 struct vop_kqfilt_remove_args
*ap
;
2014 extern int (**fifo_vnodeop_p
)(void *);
2017 error
= VOCALL(fifo_vnodeop_p
, VOFFSET(vop_kqfilt_remove
), ap
);
2019 error
= ufs_kqfilt_remove(ap
);
2027 static struct filterops ufsread_filtops
=
2028 { 1, NULL
, filt_ufsdetach
, filt_ufsread
};
2029 static struct filterops ufswrite_filtops
=
2030 { 1, NULL
, filt_ufsdetach
, filt_ufswrite
};
2031 static struct filterops ufsvnode_filtops
=
2032 { 1, NULL
, filt_ufsdetach
, filt_ufsvnode
};
2036 #% kqfilt_add vp L L L
2039 IN struct vnode *vp;
2040 IN struct knote *kn;
2045 struct vop_kqfilt_add_args
/* {
2051 struct vnode
*vp
= ap
->a_vp
;
2052 struct knote
*kn
= ap
->a_kn
;
2054 switch (kn
->kn_filter
) {
2056 kn
->kn_fop
= &ufsread_filtops
;
2059 kn
->kn_fop
= &ufswrite_filtops
;
2062 kn
->kn_fop
= &ufsvnode_filtops
;
2068 kn
->kn_hook
= (caddr_t
)vp
;
2070 KNOTE_ATTACH(&VTOI(vp
)->i_knotes
, kn
);
2076 filt_ufsdetach(struct knote
*kn
)
2080 struct proc
*p
= current_proc();
2082 vp
= (struct vnode
*)kn
->kn_hook
;
2083 if (1) { /* ! KNDETACH_VNLOCKED */
2084 result
= vn_lock(vp
, LK_EXCLUSIVE
| LK_RETRY
, p
);
2088 result
= KNOTE_DETACH(&VTOI(vp
)->i_knotes
, kn
);
2090 if (1) { /* ! KNDETACH_VNLOCKED */
2091 VOP_UNLOCK(vp
, 0, p
);
2097 filt_ufsread(struct knote
*kn
, long hint
)
2099 struct vnode
*vp
= (struct vnode
*)kn
->kn_hook
;
2100 struct inode
*ip
= VTOI(vp
);
2103 * filesystem is gone, so set the EOF flag and schedule
2104 * the knote for deletion.
2106 if (hint
== NOTE_REVOKE
) {
2107 kn
->kn_flags
|= (EV_EOF
| EV_ONESHOT
);
2111 kn
->kn_data
= ip
->i_size
- kn
->kn_fp
->f_offset
;
2112 return (kn
->kn_data
!= 0);
2117 filt_ufswrite(struct knote
*kn
, long hint
)
2121 * filesystem is gone, so set the EOF flag and schedule
2122 * the knote for deletion.
2124 if (hint
== NOTE_REVOKE
)
2125 kn
->kn_flags
|= (EV_EOF
| EV_ONESHOT
);
2132 filt_ufsvnode(struct knote
*kn
, long hint
)
2135 if (kn
->kn_sfflags
& hint
)
2136 kn
->kn_fflags
|= hint
;
2137 if (hint
== NOTE_REVOKE
) {
2138 kn
->kn_flags
|= EV_EOF
;
2141 return (kn
->kn_fflags
!= 0);
2145 * Return POSIX pathconf information applicable to ufs filesystems.
2148 struct vop_pathconf_args
/* {
2155 switch (ap
->a_name
) {
2157 *ap
->a_retval
= LINK_MAX
;
2160 *ap
->a_retval
= NAME_MAX
;
2163 *ap
->a_retval
= PATH_MAX
;
2166 *ap
->a_retval
= PIPE_BUF
;
2168 case _PC_CHOWN_RESTRICTED
:
2181 * Advisory record locking support
2185 struct vop_advlock_args
/* {
2193 register struct inode
*ip
= VTOI(ap
->a_vp
);
2194 register struct flock
*fl
= ap
->a_fl
;
2195 register struct lockf
*lock
;
2200 * Avoid the common case of unlocking when inode has no locks.
2202 if (ip
->i_lockf
== (struct lockf
*)0) {
2203 if (ap
->a_op
!= F_SETLK
) {
2204 fl
->l_type
= F_UNLCK
;
2209 * Convert the flock structure into a start and end.
2211 switch (fl
->l_whence
) {
2216 * Caller is responsible for adding any necessary offset
2217 * when SEEK_CUR is used.
2219 start
= fl
->l_start
;
2223 start
= ip
->i_size
+ fl
->l_start
;
2231 else if (fl
->l_len
> 0)
2232 end
= start
+ fl
->l_len
- 1;
2233 else { /* l_len is negative */
2240 * Create the lockf structure
2242 MALLOC(lock
, struct lockf
*, sizeof *lock
, M_LOCKF
, M_WAITOK
);
2243 lock
->lf_start
= start
;
2245 lock
->lf_id
= ap
->a_id
;
2246 lock
->lf_inode
= ip
;
2247 lock
->lf_type
= fl
->l_type
;
2248 lock
->lf_next
= (struct lockf
*)0;
2249 TAILQ_INIT(&lock
->lf_blkhd
);
2250 lock
->lf_flags
= ap
->a_flags
;
2252 * Do the requested operation.
2256 return (lf_setlock(lock
));
2259 error
= lf_clearlock(lock
);
2260 FREE(lock
, M_LOCKF
);
2264 error
= lf_getlock(lock
, fl
);
2265 FREE(lock
, M_LOCKF
);
2269 _FREE(lock
, M_LOCKF
);
2276 * Initialize the vnode associated with a new inode, handle aliased
2280 ufs_vinit(mntp
, specops
, fifoops
, vpp
)
2286 struct proc
*p
= current_proc(); /* XXX */
2288 struct vnode
*vp
, *nvp
;
2292 switch(vp
->v_type
= IFTOVT(ip
->i_mode
)) {
2296 if (nvp
= checkalias(vp
, ip
->i_rdev
, mntp
)) {
2298 * Discard unneeded vnode, but save its inode.
2299 * Note that the lock is carried over in the inode
2300 * to the replacement vnode.
2302 nvp
->v_data
= vp
->v_data
;
2304 vp
->v_op
= spec_vnodeop_p
;
2308 * Reinitialize aliased inode.
2319 return (EOPNOTSUPP
);
2329 if (ip
->i_number
== ROOTINO
)
2330 vp
->v_flag
|= VROOT
;
2332 * Initialize modrev times
2334 SETHIGH(ip
->i_modrev
, time
.tv_sec
);
2335 SETLOW(ip
->i_modrev
, time
.tv_usec
* 4294);
2341 * Allocate a new inode.
2344 ufs_makeinode(mode
, dvp
, vpp
, cnp
)
2348 struct componentname
*cnp
;
2350 register struct inode
*ip
, *pdir
;
2357 if ((cnp
->cn_flags
& HASBUF
) == 0)
2358 panic("ufs_makeinode: no name");
2361 if ((mode
& IFMT
) == 0)
2364 if (error
= VOP_VALLOC(dvp
, mode
, cnp
->cn_cred
, &tvp
)) {
2365 char *tmp
= cnp
->cn_pnbuf
;
2366 cnp
->cn_pnbuf
= NULL
;
2367 cnp
->cn_flags
&= ~HASBUF
;
2368 FREE_ZONE(tmp
, cnp
->cn_pnlen
, M_NAMEI
);
2373 ip
->i_gid
= pdir
->i_gid
;
2374 if ((mode
& IFMT
) == IFLNK
)
2375 ip
->i_uid
= pdir
->i_uid
;
2377 ip
->i_uid
= cnp
->cn_cred
->cr_uid
;
2379 if ((error
= getinoquota(ip
)) ||
2380 (error
= chkiq(ip
, 1, cnp
->cn_cred
, 0))) {
2381 char *tmp
= cnp
->cn_pnbuf
;
2382 cnp
->cn_pnbuf
= NULL
;
2383 cnp
->cn_flags
&= ~HASBUF
;
2384 FREE_ZONE(tmp
, cnp
->cn_pnlen
, M_NAMEI
);
2385 VOP_VFREE(tvp
, ip
->i_number
, mode
);
2391 ip
->i_flag
|= IN_ACCESS
| IN_CHANGE
| IN_UPDATE
;
2393 tvp
->v_type
= IFTOVT(mode
); /* Rest init'd in getnewvnode(). */
2395 if ((ip
->i_mode
& ISGID
) && !groupmember(ip
->i_gid
, cnp
->cn_cred
) &&
2396 suser(cnp
->cn_cred
, NULL
))
2397 ip
->i_mode
&= ~ISGID
;
2399 if (cnp
->cn_flags
& ISWHITEOUT
)
2400 ip
->i_flags
|= UF_OPAQUE
;
2403 * initialize UBC before calling VOP_UPDATE and ufs_direnter
2404 * Not doing so introduces probelms in handling error from
2406 * It results in a "vget: stolen ubc_info" panic due to attempt
2407 * to shutdown uninitialized UBC.
2409 if (UBCINFOMISSING(tvp
) || UBCINFORECLAIMED(tvp
))
2413 * Make sure inode goes to disk before directory entry.
2416 if (error
= VOP_UPDATE(tvp
, &tv
, &tv
, 1))
2418 if (error
= ufs_direnter(ip
, dvp
, cnp
))
2420 if ((cnp
->cn_flags
& SAVESTART
) == 0) {
2421 char *tmp
= cnp
->cn_pnbuf
;
2422 cnp
->cn_pnbuf
= NULL
;
2423 cnp
->cn_flags
&= ~HASBUF
;
2424 FREE_ZONE(tmp
, cnp
->cn_pnlen
, M_NAMEI
);
2433 * Write error occurred trying to update the inode
2434 * or the directory so must deallocate the inode.
2437 char *tmp
= cnp
->cn_pnbuf
;
2438 cnp
->cn_pnbuf
= NULL
;
2439 cnp
->cn_flags
&= ~HASBUF
;
2440 FREE_ZONE(tmp
, cnp
->cn_pnlen
, M_NAMEI
);
2444 ip
->i_flag
|= IN_CHANGE
;