Remove redundant .Pp macros right before .El, .Sh and .Ss.
[dragonfly.git] / sys / vfs / ufs / ufs_vnops.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1982, 1986, 1989, 1993, 1995
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, 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 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * @(#)ufs_vnops.c 8.27 (Berkeley) 5/27/95
39 * $FreeBSD: src/sys/ufs/ufs/ufs_vnops.c,v 1.131.2.8 2003/01/02 17:26:19 bde Exp $
54078292 40 * $DragonFly: src/sys/vfs/ufs/ufs_vnops.c,v 1.34 2006/03/24 18:35:34 dillon Exp $
984263bc
MD
41 */
42
43#include "opt_quota.h"
44#include "opt_suiddir.h"
45#include "opt_ufs.h"
46
47#include <sys/param.h>
48#include <sys/systm.h>
984263bc
MD
49#include <sys/kernel.h>
50#include <sys/fcntl.h>
51#include <sys/stat.h>
52#include <sys/buf.h>
53#include <sys/proc.h>
dadab5e9 54#include <sys/namei.h>
984263bc
MD
55#include <sys/mount.h>
56#include <sys/unistd.h>
57#include <sys/vnode.h>
58#include <sys/malloc.h>
59#include <sys/dirent.h>
60#include <sys/lockf.h>
61#include <sys/event.h>
62#include <sys/conf.h>
63
64#include <sys/file.h> /* XXX */
21c8b4bd 65#include <sys/jail.h>
984263bc
MD
66
67#include <vm/vm.h>
68#include <vm/vm_extern.h>
69
1f2de5d4 70#include <vfs/fifofs/fifo.h>
984263bc 71
1f2de5d4
MD
72#include "quota.h"
73#include "inode.h"
74#include "dir.h"
75#include "ufsmount.h"
76#include "ufs_extern.h"
984263bc 77#ifdef UFS_DIRHASH
1f2de5d4 78#include "dirhash.h"
984263bc
MD
79#endif
80
a6ee311a
RG
81static int ufs_access (struct vop_access_args *);
82static int ufs_advlock (struct vop_advlock_args *);
83static int ufs_chmod (struct vnode *, int, struct ucred *, struct thread *);
84static int ufs_chown (struct vnode *, uid_t, gid_t, struct ucred *, struct thread *);
85static int ufs_close (struct vop_close_args *);
e62afb5f 86static int ufs_create (struct vop_old_create_args *);
a6ee311a 87static int ufs_getattr (struct vop_getattr_args *);
e62afb5f 88static int ufs_link (struct vop_old_link_args *);
a6ee311a
RG
89static int ufs_makeinode (int mode, struct vnode *, struct vnode **, struct componentname *);
90static int ufs_missingop (struct vop_generic_args *ap);
e62afb5f
MD
91static int ufs_mkdir (struct vop_old_mkdir_args *);
92static int ufs_mknod (struct vop_old_mknod_args *);
a6ee311a
RG
93static int ufs_mmap (struct vop_mmap_args *);
94static int ufs_open (struct vop_open_args *);
95static int ufs_pathconf (struct vop_pathconf_args *);
96static int ufs_print (struct vop_print_args *);
97static int ufs_readdir (struct vop_readdir_args *);
98static int ufs_readlink (struct vop_readlink_args *);
e62afb5f
MD
99static int ufs_remove (struct vop_old_remove_args *);
100static int ufs_rename (struct vop_old_rename_args *);
101static int ufs_rmdir (struct vop_old_rmdir_args *);
a6ee311a
RG
102static int ufs_setattr (struct vop_setattr_args *);
103static int ufs_strategy (struct vop_strategy_args *);
e62afb5f
MD
104static int ufs_symlink (struct vop_old_symlink_args *);
105static int ufs_whiteout (struct vop_old_whiteout_args *);
a6ee311a
RG
106static int ufsfifo_close (struct vop_close_args *);
107static int ufsfifo_kqfilter (struct vop_kqfilter_args *);
108static int ufsfifo_read (struct vop_read_args *);
109static int ufsfifo_write (struct vop_write_args *);
110static int ufsspec_close (struct vop_close_args *);
111static int ufsspec_read (struct vop_read_args *);
112static int ufsspec_write (struct vop_write_args *);
113static int filt_ufsread (struct knote *kn, long hint);
114static int filt_ufswrite (struct knote *kn, long hint);
115static int filt_ufsvnode (struct knote *kn, long hint);
116static void filt_ufsdetach (struct knote *kn);
117static int ufs_kqfilter (struct vop_kqfilter_args *ap);
984263bc
MD
118
119union _qcvt {
120 int64_t qcvt;
121 int32_t val[2];
122};
123#define SETHIGH(q, h) { \
124 union _qcvt tmp; \
125 tmp.qcvt = (q); \
126 tmp.val[_QUAD_HIGHWORD] = (h); \
127 (q) = tmp.qcvt; \
128}
129#define SETLOW(q, l) { \
130 union _qcvt tmp; \
131 tmp.qcvt = (q); \
132 tmp.val[_QUAD_LOWWORD] = (l); \
133 (q) = tmp.qcvt; \
134}
135#define VN_KNOTE(vp, b) \
136 KNOTE(&vp->v_pollinfo.vpi_selinfo.si_note, (b))
137
e088dc32
JS
138#define OFSFMT(vp) ((vp)->v_mount->mnt_maxsymlinklen <= 0)
139
984263bc
MD
140/*
141 * A virgin directory (no blushing please).
142 */
143static struct dirtemplate mastertemplate = {
144 0, 12, DT_DIR, 1, ".",
145 0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
146};
147static struct odirtemplate omastertemplate = {
148 0, 12, 1, ".",
149 0, DIRBLKSIZ - 12, 2, ".."
150};
151
152void
0973c589 153ufs_itimes(struct vnode *vp)
984263bc
MD
154{
155 struct inode *ip;
156 struct timespec ts;
157
158 ip = VTOI(vp);
159 if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0)
160 return;
161 if ((vp->v_type == VBLK || vp->v_type == VCHR) && !DOINGSOFTDEP(vp))
162 ip->i_flag |= IN_LAZYMOD;
163 else
164 ip->i_flag |= IN_MODIFIED;
165 if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
166 vfs_timestamp(&ts);
167 if (ip->i_flag & IN_ACCESS) {
168 ip->i_atime = ts.tv_sec;
169 ip->i_atimensec = ts.tv_nsec;
170 }
171 if (ip->i_flag & IN_UPDATE) {
172 ip->i_mtime = ts.tv_sec;
173 ip->i_mtimensec = ts.tv_nsec;
174 ip->i_modrev++;
175 }
176 if (ip->i_flag & IN_CHANGE) {
177 ip->i_ctime = ts.tv_sec;
178 ip->i_ctimensec = ts.tv_nsec;
179 }
180 }
181 ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE);
182}
183
184/*
185 * Create a regular file
0973c589
CP
186 *
187 * ufs_create(struct vnode *a_dvp, struct vnode **a_vpp,
188 * struct componentname *a_cnp, struct vattr *a_vap)
984263bc 189 */
0961aa92 190static
984263bc 191int
e62afb5f 192ufs_create(struct vop_old_create_args *ap)
984263bc
MD
193{
194 int error;
195
196 error =
197 ufs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
198 ap->a_dvp, ap->a_vpp, ap->a_cnp);
199 if (error)
200 return (error);
201 VN_KNOTE(ap->a_dvp, NOTE_WRITE);
202 return (0);
203}
204
205/*
206 * Mknod vnode call
0973c589
CP
207 *
208 * ufs_mknod(struct vnode *a_dvp, struct vnode **a_vpp,
209 * struct componentname *a_cnp, struct vattr *a_vap)
984263bc
MD
210 */
211/* ARGSUSED */
0961aa92 212static
984263bc 213int
e62afb5f 214ufs_mknod(struct vop_old_mknod_args *ap)
984263bc
MD
215{
216 struct vattr *vap = ap->a_vap;
217 struct vnode **vpp = ap->a_vpp;
218 struct inode *ip;
219 ino_t ino;
220 int error;
221
222 error = ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
223 ap->a_dvp, vpp, ap->a_cnp);
224 if (error)
225 return (error);
226 VN_KNOTE(ap->a_dvp, NOTE_WRITE);
227 ip = VTOI(*vpp);
228 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
229 if (vap->va_rdev != VNOVAL) {
230 /*
231 * Want to be able to use this to make badblock
232 * inodes, so don't truncate the dev number.
233 */
234 ip->i_rdev = vap->va_rdev;
235 }
236 /*
237 * Remove inode, then reload it through VFS_VGET so it is
238 * checked to see if it is an alias of an existing entry in
239 * the inode cache.
240 */
984263bc
MD
241 (*vpp)->v_type = VNON;
242 ino = ip->i_number; /* Save this before vgone() invalidates ip. */
243 vgone(*vpp);
5fd012e0 244 vput(*vpp);
984263bc
MD
245 error = VFS_VGET(ap->a_dvp->v_mount, ino, vpp);
246 if (error) {
247 *vpp = NULL;
248 return (error);
249 }
250 return (0);
251}
252
253/*
254 * Open called.
255 *
256 * Nothing to do.
0973c589
CP
257 *
258 * ufs_open(struct vnode *a_vp, int a_mode, struct ucred *a_cred,
259 * struct thread *a_td)
984263bc
MD
260 */
261/* ARGSUSED */
0961aa92 262static
984263bc 263int
0973c589 264ufs_open(struct vop_open_args *ap)
984263bc 265{
984263bc
MD
266 /*
267 * Files marked append-only must be opened for appending.
268 */
269 if ((VTOI(ap->a_vp)->i_flags & APPEND) &&
270 (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
271 return (EPERM);
272 return (0);
273}
274
275/*
276 * Close called.
277 *
278 * Update the times on the inode.
0973c589
CP
279 *
280 * ufs_close(struct vnode *a_vp, int a_fflag, struct ucred *a_cred,
281 * struct thread *a_td)
984263bc
MD
282 */
283/* ARGSUSED */
0961aa92 284static
984263bc 285int
0973c589 286ufs_close(struct vop_close_args *ap)
984263bc 287{
3ff2135f 288 struct vnode *vp = ap->a_vp;
984263bc 289
984263bc
MD
290 if (vp->v_usecount > 1)
291 ufs_itimes(vp);
984263bc
MD
292 return (0);
293}
294
0973c589
CP
295/*
296 * ufs_access(struct vnode *a_vp, int a_mode, struct ucred *a_cred,
297 * struct thread *a_td)
298 */
0961aa92 299static
984263bc 300int
0973c589 301ufs_access(struct vop_access_args *ap)
984263bc
MD
302{
303 struct vnode *vp = ap->a_vp;
304 struct inode *ip = VTOI(vp);
305 struct ucred *cred = ap->a_cred;
306 mode_t mask, mode = ap->a_mode;
3ff2135f 307 gid_t *gp;
984263bc
MD
308 int i;
309#ifdef QUOTA
310 int error;
311#endif
312
313 /*
f719c866 314 * Disallow write attempts on read-only filesystems;
984263bc 315 * unless the file is a socket, fifo, or a block or
f719c866 316 * character device resident on the filesystem.
984263bc
MD
317 */
318 if (mode & VWRITE) {
319 switch (vp->v_type) {
320 case VDIR:
321 case VLNK:
322 case VREG:
323 if (vp->v_mount->mnt_flag & MNT_RDONLY)
324 return (EROFS);
325#ifdef QUOTA
326 if ((error = getinoquota(ip)) != 0)
327 return (error);
328#endif
329 break;
330 default:
331 break;
332 }
333 }
334
335 /* If immutable bit set, nobody gets to write it. */
336 if ((mode & VWRITE) && (ip->i_flags & IMMUTABLE))
337 return (EPERM);
338
339 /* Otherwise, user id 0 always gets access. */
340 if (cred->cr_uid == 0)
341 return (0);
342
343 mask = 0;
344
345 /* Otherwise, check the owner. */
346 if (cred->cr_uid == ip->i_uid) {
347 if (mode & VEXEC)
348 mask |= S_IXUSR;
349 if (mode & VREAD)
350 mask |= S_IRUSR;
351 if (mode & VWRITE)
352 mask |= S_IWUSR;
353 return ((ip->i_mode & mask) == mask ? 0 : EACCES);
354 }
355
356 /* Otherwise, check the groups. */
357 for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
358 if (ip->i_gid == *gp) {
359 if (mode & VEXEC)
360 mask |= S_IXGRP;
361 if (mode & VREAD)
362 mask |= S_IRGRP;
363 if (mode & VWRITE)
364 mask |= S_IWGRP;
365 return ((ip->i_mode & mask) == mask ? 0 : EACCES);
366 }
367
368 /* Otherwise, check everyone else. */
369 if (mode & VEXEC)
370 mask |= S_IXOTH;
371 if (mode & VREAD)
372 mask |= S_IROTH;
373 if (mode & VWRITE)
374 mask |= S_IWOTH;
375 return ((ip->i_mode & mask) == mask ? 0 : EACCES);
376}
377
0973c589
CP
378/*
379 * ufs_getattr(struct vnode *a_vp, struct vattr *a_vap,
380 * struct thread *a_td)
381 */
984263bc 382/* ARGSUSED */
0961aa92 383static
984263bc 384int
0973c589 385ufs_getattr(struct vop_getattr_args *ap)
984263bc 386{
3ff2135f
RG
387 struct vnode *vp = ap->a_vp;
388 struct inode *ip = VTOI(vp);
389 struct vattr *vap = ap->a_vap;
984263bc 390
dc1be39c
MD
391 /*
392 * This may cause i_fsmid to be updated even if no change (0)
393 * is returned, but we should only write out the inode if non-zero
394 * is returned and if the mount is read-write.
395 */
396 if (cache_check_fsmid_vp(vp, &ip->i_fsmid) &&
397 (vp->v_mount->mnt_flag & MNT_RDONLY) == 0
398 ) {
399 ip->i_flag |= IN_LAZYMOD;
400 }
401
984263bc
MD
402 ufs_itimes(vp);
403 /*
404 * Copy from inode table
405 */
406 vap->va_fsid = dev2udev(ip->i_dev);
407 vap->va_fileid = ip->i_number;
408 vap->va_mode = ip->i_mode & ~IFMT;
409 vap->va_nlink = VFSTOUFS(vp->v_mount)->um_i_effnlink_valid ?
410 ip->i_effnlink : ip->i_nlink;
411 vap->va_uid = ip->i_uid;
412 vap->va_gid = ip->i_gid;
413 vap->va_rdev = ip->i_rdev;
414 vap->va_size = ip->i_din.di_size;
415 vap->va_atime.tv_sec = ip->i_atime;
416 vap->va_atime.tv_nsec = ip->i_atimensec;
417 vap->va_mtime.tv_sec = ip->i_mtime;
418 vap->va_mtime.tv_nsec = ip->i_mtimensec;
419 vap->va_ctime.tv_sec = ip->i_ctime;
420 vap->va_ctime.tv_nsec = ip->i_ctimensec;
421 vap->va_flags = ip->i_flags;
422 vap->va_gen = ip->i_gen;
423 vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
424 vap->va_bytes = dbtob((u_quad_t)ip->i_blocks);
425 vap->va_type = IFTOVT(ip->i_mode);
426 vap->va_filerev = ip->i_modrev;
dc1be39c 427 vap->va_fsmid = ip->i_fsmid;
984263bc
MD
428 return (0);
429}
430
431/*
432 * Set attribute vnode op. called from several syscalls
0973c589
CP
433 *
434 * ufs_setattr(struct vnode *a_vp, struct vattr *a_vap,
435 * struct ucred *a_cred, struct thread *a_td)
984263bc 436 */
0961aa92 437static
984263bc 438int
0973c589 439ufs_setattr(struct vop_setattr_args *ap)
984263bc
MD
440{
441 struct vattr *vap = ap->a_vap;
442 struct vnode *vp = ap->a_vp;
443 struct inode *ip = VTOI(vp);
444 struct ucred *cred = ap->a_cred;
984263bc
MD
445 int error;
446
447 /*
448 * Check for unsettable attributes.
449 */
450 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
451 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
452 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
453 ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
454 return (EINVAL);
455 }
456 if (vap->va_flags != VNOVAL) {
457 if (vp->v_mount->mnt_flag & MNT_RDONLY)
458 return (EROFS);
459 if (cred->cr_uid != ip->i_uid &&
dadab5e9 460 (error = suser_cred(cred, PRISON_ROOT)))
984263bc 461 return (error);
21c8b4bd
MD
462 /*
463 * Note that a root chflags becomes a user chflags when
464 * we are jailed, unless the jail.chflags_allowed sysctl
465 * is set.
466 */
467 if (cred->cr_uid == 0 &&
468 (!jailed(cred) || jail_chflags_allowed)) {
984263bc
MD
469 if ((ip->i_flags
470 & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) &&
471 securelevel > 0)
472 return (EPERM);
473 ip->i_flags = vap->va_flags;
474 } else {
475 if (ip->i_flags
476 & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND) ||
477 (vap->va_flags & UF_SETTABLE) != vap->va_flags)
478 return (EPERM);
479 ip->i_flags &= SF_SETTABLE;
480 ip->i_flags |= (vap->va_flags & UF_SETTABLE);
481 }
482 ip->i_flag |= IN_CHANGE;
483 if (vap->va_flags & (IMMUTABLE | APPEND))
484 return (0);
485 }
486 if (ip->i_flags & (IMMUTABLE | APPEND))
487 return (EPERM);
488 /*
489 * Go through the fields and update iff not VNOVAL.
490 */
491 if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
492 if (vp->v_mount->mnt_flag & MNT_RDONLY)
493 return (EROFS);
dadab5e9 494 if ((error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, ap->a_td)) != 0)
984263bc
MD
495 return (error);
496 }
497 if (vap->va_size != VNOVAL) {
498 /*
f719c866 499 * Disallow write attempts on read-only filesystems;
984263bc 500 * unless the file is a socket, fifo, or a block or
f719c866 501 * character device resident on the filesystem.
984263bc
MD
502 */
503 switch (vp->v_type) {
504 case VDIR:
505 return (EISDIR);
506 case VLNK:
507 case VREG:
508 if (vp->v_mount->mnt_flag & MNT_RDONLY)
509 return (EROFS);
510 break;
511 default:
512 break;
513 }
dadab5e9 514 if ((error = UFS_TRUNCATE(vp, vap->va_size, 0, cred, ap->a_td)) != 0)
984263bc
MD
515 return (error);
516 }
517 ip = VTOI(vp);
518 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
519 if (vp->v_mount->mnt_flag & MNT_RDONLY)
520 return (EROFS);
521 if (cred->cr_uid != ip->i_uid &&
dadab5e9 522 (error = suser_cred(cred, PRISON_ROOT)) &&
984263bc 523 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
dadab5e9 524 (error = VOP_ACCESS(vp, VWRITE, cred, ap->a_td))))
984263bc
MD
525 return (error);
526 if (vap->va_atime.tv_sec != VNOVAL)
527 ip->i_flag |= IN_ACCESS;
528 if (vap->va_mtime.tv_sec != VNOVAL)
529 ip->i_flag |= IN_CHANGE | IN_UPDATE;
530 ufs_itimes(vp);
531 if (vap->va_atime.tv_sec != VNOVAL) {
532 ip->i_atime = vap->va_atime.tv_sec;
533 ip->i_atimensec = vap->va_atime.tv_nsec;
534 }
535 if (vap->va_mtime.tv_sec != VNOVAL) {
536 ip->i_mtime = vap->va_mtime.tv_sec;
537 ip->i_mtimensec = vap->va_mtime.tv_nsec;
538 }
539 error = UFS_UPDATE(vp, 0);
540 if (error)
541 return (error);
542 }
543 error = 0;
544 if (vap->va_mode != (mode_t)VNOVAL) {
545 if (vp->v_mount->mnt_flag & MNT_RDONLY)
546 return (EROFS);
dadab5e9 547 error = ufs_chmod(vp, (int)vap->va_mode, cred, ap->a_td);
984263bc
MD
548 }
549 VN_KNOTE(vp, NOTE_ATTRIB);
550 return (error);
551}
552
553/*
554 * Change the mode on a file.
555 * Inode must be locked before calling.
556 */
557static int
dadab5e9 558ufs_chmod(struct vnode *vp, int mode, struct ucred *cred, struct thread *td)
984263bc 559{
3ff2135f 560 struct inode *ip = VTOI(vp);
984263bc
MD
561 int error;
562
563 if (cred->cr_uid != ip->i_uid) {
dadab5e9 564 error = suser_cred(cred, PRISON_ROOT);
984263bc
MD
565 if (error)
566 return (error);
567 }
568 if (cred->cr_uid) {
569 if (vp->v_type != VDIR && (mode & S_ISTXT))
570 return (EFTYPE);
571 if (!groupmember(ip->i_gid, cred) && (mode & ISGID))
572 return (EPERM);
573 }
574 ip->i_mode &= ~ALLPERMS;
575 ip->i_mode |= (mode & ALLPERMS);
576 ip->i_flag |= IN_CHANGE;
577 return (0);
578}
579
580/*
581 * Perform chown operation on inode ip;
582 * inode must be locked prior to call.
583 */
584static int
0973c589
CP
585ufs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred,
586 struct thread *td)
984263bc 587{
3ff2135f 588 struct inode *ip = VTOI(vp);
984263bc
MD
589 uid_t ouid;
590 gid_t ogid;
591 int error = 0;
592#ifdef QUOTA
3ff2135f 593 int i;
984263bc
MD
594 long change;
595#endif
596
597 if (uid == (uid_t)VNOVAL)
598 uid = ip->i_uid;
599 if (gid == (gid_t)VNOVAL)
600 gid = ip->i_gid;
601 /*
602 * If we don't own the file, are trying to change the owner
603 * of the file, or are not a member of the target group,
604 * the caller must be superuser or the call fails.
605 */
606 if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid ||
a10e3626
DR
607 (gid != ip->i_gid && !(cred->cr_gid == gid ||
608 groupmember((gid_t)gid, cred)))) &&
dadab5e9 609 (error = suser_cred(cred, PRISON_ROOT)))
984263bc
MD
610 return (error);
611 ogid = ip->i_gid;
612 ouid = ip->i_uid;
613#ifdef QUOTA
614 if ((error = getinoquota(ip)) != 0)
615 return (error);
616 if (ouid == uid) {
617 dqrele(vp, ip->i_dquot[USRQUOTA]);
618 ip->i_dquot[USRQUOTA] = NODQUOT;
619 }
620 if (ogid == gid) {
621 dqrele(vp, ip->i_dquot[GRPQUOTA]);
622 ip->i_dquot[GRPQUOTA] = NODQUOT;
623 }
624 change = ip->i_blocks;
625 (void) chkdq(ip, -change, cred, CHOWN);
626 (void) chkiq(ip, -1, cred, CHOWN);
627 for (i = 0; i < MAXQUOTAS; i++) {
628 dqrele(vp, ip->i_dquot[i]);
629 ip->i_dquot[i] = NODQUOT;
630 }
631#endif
632 ip->i_gid = gid;
633 ip->i_uid = uid;
634#ifdef QUOTA
635 if ((error = getinoquota(ip)) == 0) {
636 if (ouid == uid) {
637 dqrele(vp, ip->i_dquot[USRQUOTA]);
638 ip->i_dquot[USRQUOTA] = NODQUOT;
639 }
640 if (ogid == gid) {
641 dqrele(vp, ip->i_dquot[GRPQUOTA]);
642 ip->i_dquot[GRPQUOTA] = NODQUOT;
643 }
644 if ((error = chkdq(ip, change, cred, CHOWN)) == 0) {
645 if ((error = chkiq(ip, 1, cred, CHOWN)) == 0)
646 goto good;
647 else
648 (void) chkdq(ip, -change, cred, CHOWN|FORCE);
649 }
650 for (i = 0; i < MAXQUOTAS; i++) {
651 dqrele(vp, ip->i_dquot[i]);
652 ip->i_dquot[i] = NODQUOT;
653 }
654 }
655 ip->i_gid = ogid;
656 ip->i_uid = ouid;
657 if (getinoquota(ip) == 0) {
658 if (ouid == uid) {
659 dqrele(vp, ip->i_dquot[USRQUOTA]);
660 ip->i_dquot[USRQUOTA] = NODQUOT;
661 }
662 if (ogid == gid) {
663 dqrele(vp, ip->i_dquot[GRPQUOTA]);
664 ip->i_dquot[GRPQUOTA] = NODQUOT;
665 }
666 (void) chkdq(ip, change, cred, FORCE|CHOWN);
667 (void) chkiq(ip, 1, cred, FORCE|CHOWN);
668 (void) getinoquota(ip);
669 }
670 return (error);
671good:
672 if (getinoquota(ip))
673 panic("ufs_chown: lost quota");
674#endif /* QUOTA */
675 ip->i_flag |= IN_CHANGE;
676 if (cred->cr_uid != 0 && (ouid != uid || ogid != gid))
677 ip->i_mode &= ~(ISUID | ISGID);
678 return (0);
679}
680
681/*
682 * Mmap a file
683 *
684 * NB Currently unsupported.
0973c589
CP
685 *
686 * ufs_mmap(struct vnode *a_vp, int a_fflags, struct ucred *a_cred,
687 * struct thread *a_td)
984263bc
MD
688 */
689/* ARGSUSED */
0961aa92 690static
984263bc 691int
0973c589 692ufs_mmap(struct vop_mmap_args *ap)
984263bc 693{
984263bc
MD
694 return (EINVAL);
695}
696
0973c589
CP
697/*
698 * ufs_remove(struct vnode *a_dvp, struct vnode *a_vp,
699 * struct componentname *a_cnp)
700 */
0961aa92 701static
984263bc 702int
e62afb5f 703ufs_remove(struct vop_old_remove_args *ap)
984263bc
MD
704{
705 struct inode *ip;
706 struct vnode *vp = ap->a_vp;
707 struct vnode *dvp = ap->a_dvp;
708 int error;
709
710 ip = VTOI(vp);
711 if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
712 (VTOI(dvp)->i_flags & APPEND)) {
713 error = EPERM;
714 goto out;
715 }
716 error = ufs_dirremove(dvp, ip, ap->a_cnp->cn_flags, 0);
717 VN_KNOTE(vp, NOTE_DELETE);
718 VN_KNOTE(dvp, NOTE_WRITE);
719out:
720 return (error);
721}
722
723/*
724 * link vnode call
0973c589
CP
725 *
726 * ufs_link(struct vnode *a_tdvp, struct vnode *a_vp,
727 * struct componentname *a_cnp)
984263bc 728 */
0961aa92 729static
984263bc 730int
e62afb5f 731ufs_link(struct vop_old_link_args *ap)
984263bc
MD
732{
733 struct vnode *vp = ap->a_vp;
734 struct vnode *tdvp = ap->a_tdvp;
735 struct componentname *cnp = ap->a_cnp;
dadab5e9 736 struct thread *td = cnp->cn_td;
984263bc
MD
737 struct inode *ip;
738 struct direct newdir;
739 int error;
740
984263bc
MD
741 if (tdvp->v_mount != vp->v_mount) {
742 error = EXDEV;
743 goto out2;
744 }
5fd012e0 745 if (tdvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, td))) {
984263bc
MD
746 goto out2;
747 }
748 ip = VTOI(vp);
749 if ((nlink_t)ip->i_nlink >= LINK_MAX) {
750 error = EMLINK;
751 goto out1;
752 }
753 if (ip->i_flags & (IMMUTABLE | APPEND)) {
754 error = EPERM;
755 goto out1;
756 }
757 ip->i_effnlink++;
758 ip->i_nlink++;
759 ip->i_flag |= IN_CHANGE;
760 if (DOINGSOFTDEP(vp))
761 softdep_change_linkcnt(ip);
762 error = UFS_UPDATE(vp, !(DOINGSOFTDEP(vp) | DOINGASYNC(vp)));
763 if (!error) {
764 ufs_makedirentry(ip, cnp, &newdir);
765 error = ufs_direnter(tdvp, vp, &newdir, cnp, NULL);
766 }
767
768 if (error) {
769 ip->i_effnlink--;
770 ip->i_nlink--;
771 ip->i_flag |= IN_CHANGE;
772 if (DOINGSOFTDEP(vp))
773 softdep_change_linkcnt(ip);
774 }
775out1:
776 if (tdvp != vp)
5fd012e0 777 VOP_UNLOCK(vp, 0, td);
984263bc
MD
778out2:
779 VN_KNOTE(vp, NOTE_LINK);
780 VN_KNOTE(tdvp, NOTE_WRITE);
781 return (error);
782}
783
784/*
785 * whiteout vnode call
0973c589
CP
786 *
787 * ufs_whiteout(struct vnode *a_dvp, struct componentname *a_cnp, int a_flags)
984263bc 788 */
0961aa92 789static
984263bc 790int
e62afb5f 791ufs_whiteout(struct vop_old_whiteout_args *ap)
984263bc
MD
792{
793 struct vnode *dvp = ap->a_dvp;
794 struct componentname *cnp = ap->a_cnp;
795 struct direct newdir;
796 int error = 0;
797
798 switch (ap->a_flags) {
2b69e610 799 case NAMEI_LOOKUP:
984263bc
MD
800 /* 4.4 format directories support whiteout operations */
801 if (dvp->v_mount->mnt_maxsymlinklen > 0)
802 return (0);
803 return (EOPNOTSUPP);
804
2b69e610 805 case NAMEI_CREATE:
984263bc
MD
806 /* create a new directory whiteout */
807#ifdef DIAGNOSTIC
984263bc
MD
808 if (dvp->v_mount->mnt_maxsymlinklen <= 0)
809 panic("ufs_whiteout: old format filesystem");
810#endif
811
812 newdir.d_ino = WINO;
813 newdir.d_namlen = cnp->cn_namelen;
814 bcopy(cnp->cn_nameptr, newdir.d_name, (unsigned)cnp->cn_namelen + 1);
815 newdir.d_type = DT_WHT;
816 error = ufs_direnter(dvp, NULL, &newdir, cnp, NULL);
817 break;
818
2b69e610 819 case NAMEI_DELETE:
984263bc
MD
820 /* remove an existing directory whiteout */
821#ifdef DIAGNOSTIC
822 if (dvp->v_mount->mnt_maxsymlinklen <= 0)
823 panic("ufs_whiteout: old format filesystem");
824#endif
825
2b69e610 826 cnp->cn_flags &= ~CNP_DOWHITEOUT;
984263bc
MD
827 error = ufs_dirremove(dvp, NULL, cnp->cn_flags, 0);
828 break;
829 default:
830 panic("ufs_whiteout: unknown op");
831 }
832 return (error);
833}
834
835/*
836 * Rename system call.
837 * rename("foo", "bar");
838 * is essentially
839 * unlink("bar");
840 * link("foo", "bar");
841 * unlink("foo");
842 * but ``atomically''. Can't do full commit without saving state in the
843 * inode on disk which isn't feasible at this time. Best we can do is
844 * always guarantee the target exists.
845 *
846 * Basic algorithm is:
847 *
848 * 1) Bump link count on source while we're linking it to the
849 * target. This also ensure the inode won't be deleted out
850 * from underneath us while we work (it may be truncated by
851 * a concurrent `trunc' or `open' for creation).
852 * 2) Link source to destination. If destination already exists,
853 * delete it first.
854 * 3) Unlink source reference to inode if still around. If a
855 * directory was moved and the parent of the destination
856 * is different from the source, patch the ".." entry in the
857 * directory.
0973c589
CP
858 *
859 * ufs_rename(struct vnode *a_fdvp, struct vnode *a_fvp,
860 * struct componentname *a_fcnp, struct vnode *a_tdvp,
861 * struct vnode *a_tvp, struct componentname *a_tcnp)
984263bc 862 */
0961aa92 863static
984263bc 864int
e62afb5f 865ufs_rename(struct vop_old_rename_args *ap)
984263bc
MD
866{
867 struct vnode *tvp = ap->a_tvp;
3ff2135f 868 struct vnode *tdvp = ap->a_tdvp;
984263bc
MD
869 struct vnode *fvp = ap->a_fvp;
870 struct vnode *fdvp = ap->a_fdvp;
871 struct componentname *tcnp = ap->a_tcnp;
872 struct componentname *fcnp = ap->a_fcnp;
dadab5e9 873 struct thread *td = fcnp->cn_td;
984263bc
MD
874 struct inode *ip, *xp, *dp;
875 struct direct newdir;
9ab06300
MD
876 ino_t oldparent = 0, newparent = 0;
877 int doingdirectory = 0;
984263bc
MD
878 int error = 0, ioflag;
879
984263bc
MD
880 /*
881 * Check for cross-device rename.
882 */
883 if ((fvp->v_mount != tdvp->v_mount) ||
884 (tvp && (fvp->v_mount != tvp->v_mount))) {
885 error = EXDEV;
886abortit:
887 if (tdvp == tvp)
888 vrele(tdvp);
889 else
890 vput(tdvp);
891 if (tvp)
892 vput(tvp);
893 vrele(fdvp);
894 vrele(fvp);
895 return (error);
896 }
897
898 if (tvp && ((VTOI(tvp)->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
899 (VTOI(tdvp)->i_flags & APPEND))) {
900 error = EPERM;
901 goto abortit;
902 }
903
904 /*
905 * Renaming a file to itself has no effect. The upper layers should
906 * not call us in that case. Temporarily just warn if they do.
907 */
908 if (fvp == tvp) {
909 printf("ufs_rename: fvp == tvp (can't happen)\n");
910 error = 0;
911 goto abortit;
912 }
913
5fd012e0 914 if ((error = vn_lock(fvp, LK_EXCLUSIVE, td)) != 0)
984263bc 915 goto abortit;
fad57d0e
MD
916
917 /*
918 * Note: now that fvp is locked we have to be sure to unlock it before
919 * using the 'abortit' target.
920 */
984263bc
MD
921 dp = VTOI(fdvp);
922 ip = VTOI(fvp);
923 if (ip->i_nlink >= LINK_MAX) {
5fd012e0 924 VOP_UNLOCK(fvp, 0, td);
984263bc
MD
925 error = EMLINK;
926 goto abortit;
927 }
928 if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))
929 || (dp->i_flags & APPEND)) {
5fd012e0 930 VOP_UNLOCK(fvp, 0, td);
984263bc
MD
931 error = EPERM;
932 goto abortit;
933 }
934 if ((ip->i_mode & IFMT) == IFDIR) {
935 /*
936 * Avoid ".", "..", and aliases of "." for obvious reasons.
937 */
938 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
2b69e610 939 dp == ip || (fcnp->cn_flags | tcnp->cn_flags) & CNP_ISDOTDOT ||
984263bc 940 (ip->i_flag & IN_RENAME)) {
5fd012e0 941 VOP_UNLOCK(fvp, 0, td);
984263bc
MD
942 error = EINVAL;
943 goto abortit;
944 }
945 ip->i_flag |= IN_RENAME;
946 oldparent = dp->i_number;
947 doingdirectory = 1;
948 }
949 VN_KNOTE(fdvp, NOTE_WRITE); /* XXX right place? */
984263bc
MD
950
951 /*
fad57d0e
MD
952 * fvp still locked. ip->i_flag has IN_RENAME set if doingdirectory.
953 * Cleanup fvp requirements so we can unlock it.
954 *
955 * tvp and tdvp are locked. tvp may be NULL. Now that dp and xp
956 * is setup we can use the 'bad' target if we unlock fvp. We cannot
957 * use the abortit target anymore because of IN_RENAME.
984263bc
MD
958 */
959 dp = VTOI(tdvp);
984263bc
MD
960 if (tvp)
961 xp = VTOI(tvp);
fad57d0e
MD
962 else
963 xp = NULL;
984263bc
MD
964
965 /*
966 * 1) Bump link count while we're moving stuff
967 * around. If we crash somewhere before
968 * completing our work, the link count
969 * may be wrong, but correctable.
970 */
971 ip->i_effnlink++;
972 ip->i_nlink++;
973 ip->i_flag |= IN_CHANGE;
974 if (DOINGSOFTDEP(fvp))
975 softdep_change_linkcnt(ip);
976 if ((error = UFS_UPDATE(fvp, !(DOINGSOFTDEP(fvp) |
977 DOINGASYNC(fvp)))) != 0) {
5fd012e0 978 VOP_UNLOCK(fvp, 0, td);
984263bc
MD
979 goto bad;
980 }
981
982 /*
983 * If ".." must be changed (ie the directory gets a new
984 * parent) then the source directory must not be in the
985 * directory heirarchy above the target, as this would
986 * orphan everything below the source directory. Also
987 * the user must have write permission in the source so
988 * as to be able to change "..". We must repeat the call
989 * to namei, as the parent directory is unlocked by the
990 * call to checkpath().
991 */
dadab5e9 992 error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_td);
5fd012e0 993 VOP_UNLOCK(fvp, 0, td);
fad57d0e
MD
994
995 /*
996 * We are now back to where we were in that fvp, fdvp are unlocked
997 * and tvp, tdvp are locked. tvp may be NULL. IN_RENAME may be
998 * set. Only the bad target or, if we clean up tvp and tdvp, the
999 * out target, may be used.
1000 */
984263bc
MD
1001 if (oldparent != dp->i_number)
1002 newparent = dp->i_number;
1003 if (doingdirectory && newparent) {
1004 if (error) /* write access check above */
1005 goto bad;
fad57d0e
MD
1006
1007 /*
1008 * Once we start messing with tvp and tdvp we cannot use the
1009 * 'bad' target, only finish cleaning tdvp and tvp up and
1010 * use the 'out' target.
1011 *
1012 * This cleans up tvp.
1013 */
1014 if (xp != NULL) {
984263bc 1015 vput(tvp);
fad57d0e
MD
1016 xp = NULL;
1017 }
1018
1019 /*
1020 * This is a real mess. ufs_checkpath vput's the target
1021 * directory so retain an extra ref and note that tdvp will
1022 * lose its lock on return. This leaves us with one good
1023 * ref after ufs_checkpath returns.
1024 */
1025 vref(tdvp);
984263bc 1026 error = ufs_checkpath(ip, dp, tcnp->cn_cred);
fad57d0e
MD
1027 tcnp->cn_flags |= CNP_PDIRUNLOCK;
1028 if (error) {
1029 vrele(tdvp);
984263bc 1030 goto out;
fad57d0e
MD
1031 }
1032
1033 /*
1034 * relookup no longer messes with tdvp's refs. tdvp must be
1035 * unlocked on entry and will be locked on a successful
1036 * return.
1037 */
984263bc 1038 error = relookup(tdvp, &tvp, tcnp);
fad57d0e
MD
1039 if (error) {
1040 if (tcnp->cn_flags & CNP_PDIRUNLOCK)
1041 vrele(tdvp);
1042 else
1043 vput(tdvp);
984263bc 1044 goto out;
fad57d0e
MD
1045 }
1046 KKASSERT((tcnp->cn_flags & CNP_PDIRUNLOCK) == 0);
984263bc 1047 dp = VTOI(tdvp);
984263bc
MD
1048 if (tvp)
1049 xp = VTOI(tvp);
1050 }
fad57d0e
MD
1051
1052 /*
1053 * We are back to fvp, fdvp unlocked, tvp, tdvp locked. tvp may
1054 * be NULL (xp will also be NULL in that case), and IN_RENAME will
1055 * be set if doingdirectory. This means we can use the 'bad' target
1056 * again.
1057 */
1058
984263bc
MD
1059 /*
1060 * 2) If target doesn't exist, link the target
1061 * to the source and unlink the source.
1062 * Otherwise, rewrite the target directory
1063 * entry to reference the source inode and
1064 * expunge the original entry's existence.
1065 */
1066 if (xp == NULL) {
1067 if (dp->i_dev != ip->i_dev)
1068 panic("ufs_rename: EXDEV");
1069 /*
1070 * Account for ".." in new directory.
1071 * When source and destination have the same
1072 * parent we don't fool with the link count.
1073 */
1074 if (doingdirectory && newparent) {
1075 if ((nlink_t)dp->i_nlink >= LINK_MAX) {
1076 error = EMLINK;
1077 goto bad;
1078 }
1079 dp->i_effnlink++;
1080 dp->i_nlink++;
1081 dp->i_flag |= IN_CHANGE;
1082 if (DOINGSOFTDEP(tdvp))
1083 softdep_change_linkcnt(dp);
1084 error = UFS_UPDATE(tdvp, !(DOINGSOFTDEP(tdvp) |
1085 DOINGASYNC(tdvp)));
1086 if (error)
1087 goto bad;
1088 }
1089 ufs_makedirentry(ip, tcnp, &newdir);
1090 error = ufs_direnter(tdvp, NULL, &newdir, tcnp, NULL);
1091 if (error) {
1092 if (doingdirectory && newparent) {
1093 dp->i_effnlink--;
1094 dp->i_nlink--;
1095 dp->i_flag |= IN_CHANGE;
1096 if (DOINGSOFTDEP(tdvp))
1097 softdep_change_linkcnt(dp);
1098 (void)UFS_UPDATE(tdvp, 1);
1099 }
1100 goto bad;
1101 }
1102 VN_KNOTE(tdvp, NOTE_WRITE);
1103 vput(tdvp);
1104 } else {
1105 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
1106 panic("ufs_rename: EXDEV");
1107 /*
1108 * Short circuit rename(foo, foo).
1109 */
1110 if (xp->i_number == ip->i_number)
1111 panic("ufs_rename: same file");
1112 /*
1113 * If the parent directory is "sticky", then the user must
1114 * own the parent directory, or the destination of the rename,
1115 * otherwise the destination may not be changed (except by
1116 * root). This implements append-only directories.
1117 */
1118 if ((dp->i_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 &&
1119 tcnp->cn_cred->cr_uid != dp->i_uid &&
1120 xp->i_uid != tcnp->cn_cred->cr_uid) {
1121 error = EPERM;
1122 goto bad;
1123 }
1124 /*
1125 * Target must be empty if a directory and have no links
1126 * to it. Also, ensure source and target are compatible
1127 * (both directories, or both not directories).
8e005a45
MD
1128 *
1129 * Purge the file or directory being replaced from the
1130 * nameccache.
984263bc
MD
1131 */
1132 if ((xp->i_mode&IFMT) == IFDIR) {
1133 if ((xp->i_effnlink > 2) ||
1134 !ufs_dirempty(xp, dp->i_number, tcnp->cn_cred)) {
1135 error = ENOTEMPTY;
1136 goto bad;
1137 }
1138 if (!doingdirectory) {
1139 error = ENOTDIR;
1140 goto bad;
1141 }
fad57d0e 1142 /* cache_purge removed - handled by VFS compat layer */
8e005a45 1143 } else if (doingdirectory == 0) {
fad57d0e 1144 /* cache_purge removed - handled by VFS compat layer */
8e005a45 1145 } else {
984263bc
MD
1146 error = EISDIR;
1147 goto bad;
1148 }
9ab06300
MD
1149 /*
1150 * note: inode passed to ufs_dirrewrite() is 0 for a
1151 * non-directory file rename, 1 for a directory rename
1152 * in the same directory, and > 1 for an inode representing
1153 * the new directory.
1154 */
984263bc
MD
1155 error = ufs_dirrewrite(dp, xp, ip->i_number,
1156 IFTODT(ip->i_mode),
9ab06300
MD
1157 (doingdirectory && newparent) ?
1158 newparent : (ino_t)doingdirectory);
984263bc
MD
1159 if (error)
1160 goto bad;
1161 if (doingdirectory) {
1162 if (!newparent) {
1163 dp->i_effnlink--;
1164 if (DOINGSOFTDEP(tdvp))
1165 softdep_change_linkcnt(dp);
1166 }
1167 xp->i_effnlink--;
1168 if (DOINGSOFTDEP(tvp))
1169 softdep_change_linkcnt(xp);
1170 }
1171 if (doingdirectory && !DOINGSOFTDEP(tvp)) {
1172 /*
1173 * Truncate inode. The only stuff left in the directory
1174 * is "." and "..". The "." reference is inconsequential
1175 * since we are quashing it. We have removed the "."
1176 * reference and the reference in the parent directory,
1177 * but there may be other hard links. The soft
1178 * dependency code will arrange to do these operations
1179 * after the parent directory entry has been deleted on
1180 * disk, so when running with that code we avoid doing
1181 * them now.
1182 */
1183 if (!newparent) {
1184 dp->i_nlink--;
1185 dp->i_flag |= IN_CHANGE;
1186 }
1187 xp->i_nlink--;
1188 xp->i_flag |= IN_CHANGE;
1189 ioflag = DOINGASYNC(tvp) ? 0 : IO_SYNC;
1190 if ((error = UFS_TRUNCATE(tvp, (off_t)0, ioflag,
dadab5e9 1191 tcnp->cn_cred, tcnp->cn_td)) != 0)
984263bc
MD
1192 goto bad;
1193 }
1194 VN_KNOTE(tdvp, NOTE_WRITE);
1195 vput(tdvp);
1196 VN_KNOTE(tvp, NOTE_DELETE);
1197 vput(tvp);
1198 xp = NULL;
1199 }
1200
fad57d0e
MD
1201 /*
1202 * tvp and tdvp have been cleaned up. only fvp and fdvp (both
1203 * unlocked) remain. We are about to overwrite fvp but we have to
1204 * keep 'ip' intact so we cannot release the old fvp, which is still
1205 * refd and accessible via ap->a_fvp.
1206 *
1207 * This means we cannot use either 'bad' or 'out' to cleanup any
1208 * more.
1209 */
1210
984263bc
MD
1211 /*
1212 * 3) Unlink the source.
1213 */
2b69e610 1214 fcnp->cn_flags &= ~CNP_MODMASK;
fad57d0e 1215 fcnp->cn_flags |= CNP_LOCKPARENT;
984263bc 1216 error = relookup(fdvp, &fvp, fcnp);
fad57d0e 1217 if (error || fvp == NULL) {
984263bc 1218 /*
fad57d0e
MD
1219 * From name has disappeared. IN_RENAME will not be set if
1220 * we get past the panic so we don't have to clean it up.
984263bc
MD
1221 */
1222 if (doingdirectory)
1223 panic("ufs_rename: lost dir entry");
1224 vrele(ap->a_fvp);
fad57d0e
MD
1225 if (fcnp->cn_flags & CNP_PDIRUNLOCK)
1226 vrele(fdvp);
1227 else
1228 vput(fdvp);
1229 return(0);
984263bc 1230 }
fad57d0e
MD
1231 KKASSERT((fcnp->cn_flags & CNP_PDIRUNLOCK) == 0);
1232
1233 /*
1234 * fdvp and fvp are locked.
1235 */
1236 xp = VTOI(fvp);
1237 dp = VTOI(fdvp);
1238
984263bc
MD
1239 /*
1240 * Ensure that the directory entry still exists and has not
1241 * changed while the new name has been entered. If the source is
1242 * a file then the entry may have been unlinked or renamed. In
1243 * either case there is no further work to be done. If the source
1244 * is a directory then it cannot have been rmdir'ed; the IN_RENAME
1245 * flag ensures that it cannot be moved by another rename or removed
fad57d0e 1246 * by a rmdir. Cleanup IN_RENAME.
984263bc
MD
1247 */
1248 if (xp != ip) {
1249 if (doingdirectory)
1250 panic("ufs_rename: lost dir entry");
1251 } else {
1252 /*
1253 * If the source is a directory with a
1254 * new parent, the link count of the old
1255 * parent directory must be decremented
1256 * and ".." set to point to the new parent.
1257 */
1258 if (doingdirectory && newparent) {
1259 xp->i_offset = mastertemplate.dot_reclen;
1260 ufs_dirrewrite(xp, dp, newparent, DT_DIR, 0);
fad57d0e 1261 /* cache_purge removed - handled by VFS compat layer */
984263bc
MD
1262 }
1263 error = ufs_dirremove(fdvp, xp, fcnp->cn_flags, 0);
1264 xp->i_flag &= ~IN_RENAME;
1265 }
8e005a45 1266
984263bc 1267 VN_KNOTE(fvp, NOTE_RENAME);
fad57d0e
MD
1268 vput(fdvp);
1269 vput(fvp);
984263bc
MD
1270 vrele(ap->a_fvp);
1271 return (error);
1272
1273bad:
1274 if (xp)
1275 vput(ITOV(xp));
1276 vput(ITOV(dp));
1277out:
1278 if (doingdirectory)
1279 ip->i_flag &= ~IN_RENAME;
5fd012e0 1280 if (vn_lock(fvp, LK_EXCLUSIVE, td) == 0) {
984263bc
MD
1281 ip->i_effnlink--;
1282 ip->i_nlink--;
1283 ip->i_flag |= IN_CHANGE;
1284 ip->i_flag &= ~IN_RENAME;
1285 if (DOINGSOFTDEP(fvp))
1286 softdep_change_linkcnt(ip);
1287 vput(fvp);
fad57d0e 1288 } else {
984263bc 1289 vrele(fvp);
fad57d0e 1290 }
984263bc
MD
1291 return (error);
1292}
1293
1294/*
1295 * Mkdir system call
0973c589
CP
1296 *
1297 * ufs_mkdir(struct vnode *a_dvp, struct vnode **a_vpp,
1298 * struct componentname *a_cnp, struct vattr *a_vap)
984263bc 1299 */
0961aa92 1300static
984263bc 1301int
e62afb5f 1302ufs_mkdir(struct vop_old_mkdir_args *ap)
984263bc 1303{
3ff2135f
RG
1304 struct vnode *dvp = ap->a_dvp;
1305 struct vattr *vap = ap->a_vap;
1306 struct componentname *cnp = ap->a_cnp;
1307 struct inode *ip, *dp;
984263bc
MD
1308 struct vnode *tvp;
1309 struct buf *bp;
1310 struct dirtemplate dirtemplate, *dtp;
1311 struct direct newdir;
1312 int error, dmode;
1313 long blkoff;
1314
984263bc
MD
1315 dp = VTOI(dvp);
1316 if ((nlink_t)dp->i_nlink >= LINK_MAX) {
1317 error = EMLINK;
1318 goto out;
1319 }
1320 dmode = vap->va_mode & 0777;
1321 dmode |= IFDIR;
1322 /*
1323 * Must simulate part of ufs_makeinode here to acquire the inode,
1324 * but not have it entered in the parent directory. The entry is
1325 * made later after writing "." and ".." entries.
1326 */
1327 error = UFS_VALLOC(dvp, dmode, cnp->cn_cred, &tvp);
1328 if (error)
1329 goto out;
1330 ip = VTOI(tvp);
1331 ip->i_gid = dp->i_gid;
1332#ifdef SUIDDIR
1333 {
1334#ifdef QUOTA
1335 struct ucred ucred, *ucp;
1336 ucp = cnp->cn_cred;
1337#endif
1338 /*
1339 * If we are hacking owners here, (only do this where told to)
1340 * and we are not giving it TO root, (would subvert quotas)
1341 * then go ahead and give it to the other user.
1342 * The new directory also inherits the SUID bit.
1343 * If user's UID and dir UID are the same,
1344 * 'give it away' so that the SUID is still forced on.
1345 */
1346 if ((dvp->v_mount->mnt_flag & MNT_SUIDDIR) &&
1347 (dp->i_mode & ISUID) && dp->i_uid) {
1348 dmode |= ISUID;
1349 ip->i_uid = dp->i_uid;
1350#ifdef QUOTA
1351 if (dp->i_uid != cnp->cn_cred->cr_uid) {
1352 /*
1353 * Make sure the correct user gets charged
1354 * for the space.
1355 * Make a dummy credential for the victim.
1356 * XXX This seems to never be accessed out of
1357 * our context so a stack variable is ok.
1358 */
1359 ucred.cr_ref = 1;
1360 ucred.cr_uid = ip->i_uid;
1361 ucred.cr_ngroups = 1;
1362 ucred.cr_groups[0] = dp->i_gid;
1363 ucp = &ucred;
1364 }
1365#endif
1366 } else
1367 ip->i_uid = cnp->cn_cred->cr_uid;
1368#ifdef QUOTA
1369 if ((error = getinoquota(ip)) ||
1370 (error = chkiq(ip, 1, ucp, 0))) {
1371 UFS_VFREE(tvp, ip->i_number, dmode);
1372 vput(tvp);
1373 return (error);
1374 }
1375#endif
1376 }
1377#else /* !SUIDDIR */
1378 ip->i_uid = cnp->cn_cred->cr_uid;
1379#ifdef QUOTA
1380 if ((error = getinoquota(ip)) ||
1381 (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
1382 UFS_VFREE(tvp, ip->i_number, dmode);
1383 vput(tvp);
1384 return (error);
1385 }
1386#endif
1387#endif /* !SUIDDIR */
1388 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1389 ip->i_mode = dmode;
1390 tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */
1391 ip->i_effnlink = 2;
1392 ip->i_nlink = 2;
1393 if (DOINGSOFTDEP(tvp))
1394 softdep_change_linkcnt(ip);
2b69e610 1395 if (cnp->cn_flags & CNP_ISWHITEOUT)
984263bc
MD
1396 ip->i_flags |= UF_OPAQUE;
1397
1398 /*
1399 * Bump link count in parent directory to reflect work done below.
1400 * Should be done before reference is created so cleanup is
1401 * possible if we crash.
1402 */
1403 dp->i_effnlink++;
1404 dp->i_nlink++;
1405 dp->i_flag |= IN_CHANGE;
1406 if (DOINGSOFTDEP(dvp))
1407 softdep_change_linkcnt(dp);
1408 error = UFS_UPDATE(tvp, !(DOINGSOFTDEP(dvp) | DOINGASYNC(dvp)));
1409 if (error)
1410 goto bad;
1411
1412 /*
1413 * Initialize directory with "." and ".." from static template.
1414 */
1415 if (dvp->v_mount->mnt_maxsymlinklen > 0
1416 )
1417 dtp = &mastertemplate;
1418 else
1419 dtp = (struct dirtemplate *)&omastertemplate;
1420 dirtemplate = *dtp;
1421 dirtemplate.dot_ino = ip->i_number;
1422 dirtemplate.dotdot_ino = dp->i_number;
1423 if ((error = VOP_BALLOC(tvp, (off_t)0, DIRBLKSIZ, cnp->cn_cred,
1424 B_CLRBUF, &bp)) != 0)
1425 goto bad;
1426 ip->i_size = DIRBLKSIZ;
1427 ip->i_flag |= IN_CHANGE | IN_UPDATE;
1428 vnode_pager_setsize(tvp, (u_long)ip->i_size);
1429 bcopy((caddr_t)&dirtemplate, (caddr_t)bp->b_data, sizeof dirtemplate);
1430 if (DOINGSOFTDEP(tvp)) {
1431 /*
1432 * Ensure that the entire newly allocated block is a
1433 * valid directory so that future growth within the
1434 * block does not have to ensure that the block is
1435 * written before the inode.
1436 */
1437 blkoff = DIRBLKSIZ;
1438 while (blkoff < bp->b_bcount) {
1439 ((struct direct *)
1440 (bp->b_data + blkoff))->d_reclen = DIRBLKSIZ;
1441 blkoff += DIRBLKSIZ;
1442 }
1443 }
1444 if ((error = UFS_UPDATE(tvp, !(DOINGSOFTDEP(tvp) |
1445 DOINGASYNC(tvp)))) != 0) {
81b5c339 1446 VOP_BWRITE(bp->b_vp, bp);
984263bc
MD
1447 goto bad;
1448 }
1449 /*
1450 * Directory set up, now install its entry in the parent directory.
1451 *
1452 * If we are not doing soft dependencies, then we must write out the
1453 * buffer containing the new directory body before entering the new
1454 * name in the parent. If we are doing soft dependencies, then the
1455 * buffer containing the new directory body will be passed to and
1456 * released in the soft dependency code after the code has attached
1457 * an appropriate ordering dependency to the buffer which ensures that
1458 * the buffer is written before the new name is written in the parent.
1459 */
1460 if (DOINGASYNC(dvp))
1461 bdwrite(bp);
1462 else if (!DOINGSOFTDEP(dvp) && ((error = VOP_BWRITE(bp->b_vp, bp))))
1463 goto bad;
1464 ufs_makedirentry(ip, cnp, &newdir);
1465 error = ufs_direnter(dvp, tvp, &newdir, cnp, bp);
1466
1467bad:
1468 if (error == 0) {
1469 VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1470 *ap->a_vpp = tvp;
1471 } else {
1472 dp->i_effnlink--;
1473 dp->i_nlink--;
1474 dp->i_flag |= IN_CHANGE;
1475 if (DOINGSOFTDEP(dvp))
1476 softdep_change_linkcnt(dp);
1477 /*
1478 * No need to do an explicit VOP_TRUNCATE here, vrele will
1479 * do this for us because we set the link count to 0.
1480 */
1481 ip->i_effnlink = 0;
1482 ip->i_nlink = 0;
1483 ip->i_flag |= IN_CHANGE;
1484 if (DOINGSOFTDEP(tvp))
1485 softdep_change_linkcnt(ip);
1486 vput(tvp);
1487 }
1488out:
1489 return (error);
1490}
1491
1492/*
1493 * Rmdir system call.
0973c589
CP
1494 *
1495 * ufs_rmdir(struct vnode *a_dvp, struct vnode *a_vp,
1496 * struct componentname *a_cnp)
984263bc 1497 */
0961aa92 1498static
984263bc 1499int
e62afb5f 1500ufs_rmdir(struct vop_old_rmdir_args *ap)
984263bc
MD
1501{
1502 struct vnode *vp = ap->a_vp;
1503 struct vnode *dvp = ap->a_dvp;
1504 struct componentname *cnp = ap->a_cnp;
1505 struct inode *ip, *dp;
1506 int error, ioflag;
1507
1508 ip = VTOI(vp);
1509 dp = VTOI(dvp);
1510
1511 /*
1512 * Do not remove a directory that is in the process of being renamed.
1513 * Verify the directory is empty (and valid). Rmdir ".." will not be
1514 * valid since ".." will contain a reference to the current directory
1515 * and thus be non-empty. Do not allow the removal of mounted on
1516 * directories (this can happen when an NFS exported filesystem
1517 * tries to remove a locally mounted on directory).
1518 */
1519 error = 0;
1520 if (ip->i_flag & IN_RENAME) {
1521 error = EINVAL;
1522 goto out;
1523 }
1524 if (ip->i_effnlink != 2 ||
1525 !ufs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
1526 error = ENOTEMPTY;
1527 goto out;
1528 }
1529 if ((dp->i_flags & APPEND)
1530 || (ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))) {
1531 error = EPERM;
1532 goto out;
1533 }
1534 if (vp->v_mountedhere != 0) {
1535 error = EINVAL;
1536 goto out;
1537 }
1538 /*
1539 * Delete reference to directory before purging
1540 * inode. If we crash in between, the directory
1541 * will be reattached to lost+found,
1542 */
1543 dp->i_effnlink--;
1544 ip->i_effnlink--;
1545 if (DOINGSOFTDEP(vp)) {
1546 softdep_change_linkcnt(dp);
1547 softdep_change_linkcnt(ip);
1548 }
1549 error = ufs_dirremove(dvp, ip, cnp->cn_flags, 1);
1550 if (error) {
1551 dp->i_effnlink++;
1552 ip->i_effnlink++;
1553 if (DOINGSOFTDEP(vp)) {
1554 softdep_change_linkcnt(dp);
1555 softdep_change_linkcnt(ip);
1556 }
1557 goto out;
1558 }
1559 VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
984263bc
MD
1560 /*
1561 * Truncate inode. The only stuff left in the directory is "." and
1562 * "..". The "." reference is inconsequential since we are quashing
1563 * it. The soft dependency code will arrange to do these operations
1564 * after the parent directory entry has been deleted on disk, so
1565 * when running with that code we avoid doing them now.
1566 */
1567 if (!DOINGSOFTDEP(vp)) {
1568 dp->i_nlink--;
1569 dp->i_flag |= IN_CHANGE;
1570 ip->i_nlink--;
1571 ip->i_flag |= IN_CHANGE;
1572 ioflag = DOINGASYNC(vp) ? 0 : IO_SYNC;
1573 error = UFS_TRUNCATE(vp, (off_t)0, ioflag, cnp->cn_cred,
dadab5e9 1574 cnp->cn_td);
984263bc 1575 }
fad57d0e 1576 /* cache_purge removed - handled by VFS compat layer */
984263bc
MD
1577#ifdef UFS_DIRHASH
1578 /* Kill any active hash; i_effnlink == 0, so it will not come back. */
1579 if (ip->i_dirhash != NULL)
1580 ufsdirhash_free(ip);
1581#endif
1582out:
1583 VN_KNOTE(vp, NOTE_DELETE);
1584 return (error);
1585}
1586
1587/*
1588 * symlink -- make a symbolic link
0973c589
CP
1589 *
1590 * ufs_symlink(struct vnode *a_dvp, struct vnode **a_vpp,
1591 * struct componentname *a_cnp, struct vattr *a_vap,
1592 * char *a_target)
984263bc 1593 */
0961aa92 1594static
984263bc 1595int
e62afb5f 1596ufs_symlink(struct vop_old_symlink_args *ap)
984263bc 1597{
3ff2135f
RG
1598 struct vnode *vp, **vpp = ap->a_vpp;
1599 struct inode *ip;
984263bc
MD
1600 int len, error;
1601
1602 error = ufs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
1603 vpp, ap->a_cnp);
1604 if (error)
1605 return (error);
1606 VN_KNOTE(ap->a_dvp, NOTE_WRITE);
1607 vp = *vpp;
1608 len = strlen(ap->a_target);
1609 if (len < vp->v_mount->mnt_maxsymlinklen) {
1610 ip = VTOI(vp);
1611 bcopy(ap->a_target, (char *)ip->i_shortlink, len);
1612 ip->i_size = len;
1613 ip->i_flag |= IN_CHANGE | IN_UPDATE;
1614 } else
1615 error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
dadab5e9
MD
1616 UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred,
1617 (int *)0, NULL);
984263bc
MD
1618 if (error)
1619 vput(vp);
1620 return (error);
1621}
1622
1623/*
1624 * Vnode op for reading directories.
1625 *
1626 * The routine below assumes that the on-disk format of a directory
1627 * is the same as that defined by <sys/dirent.h>. If the on-disk
1628 * format changes, then it will be necessary to do a conversion
1629 * from the on-disk format that read returns to the format defined
1630 * by <sys/dirent.h>.
0973c589
CP
1631 *
1632 * ufs_readdir(struct vnode *a_vp, struct uio *a_uio, struct ucred *a_cred,
1633 * int *a_eofflag, int *ncookies, u_long **a_cookies)
984263bc 1634 */
0961aa92 1635static
984263bc 1636int
0973c589 1637ufs_readdir(struct vop_readdir_args *ap)
984263bc 1638{
3ff2135f 1639 struct uio *uio = ap->a_uio;
e088dc32
JS
1640 int count, error;
1641
1642 struct direct *edp, *dp;
1643 int ncookies;
e088dc32
JS
1644 struct uio auio;
1645 struct iovec aiov;
1646 caddr_t dirbuf;
82fd1984 1647 int readcnt, retval;
e088dc32 1648 off_t startoffset = uio->uio_offset;
984263bc 1649
984263bc 1650 count = uio->uio_resid;
e088dc32
JS
1651 /*
1652 * Avoid complications for partial directory entries by adjusting
1653 * the i/o to end at a block boundary. Don't give up (like the old ufs
1654 * does) if the initial adjustment gives a negative count, since
1655 * many callers don't supply a large enough buffer. The correct
1656 * size is a little larger than DIRBLKSIZ to allow for expansion
1657 * of directory entries, but some callers just use 512.
1658 */
984263bc 1659 count -= (uio->uio_offset + count) & (DIRBLKSIZ -1);
e088dc32
JS
1660 if (count <= 0)
1661 count += DIRBLKSIZ;
1662
1663 auio = *uio;
1664 auio.uio_iov = &aiov;
1665 auio.uio_iovcnt = 1;
1666 auio.uio_resid = count;
1667 auio.uio_segflg = UIO_SYSSPACE;
1668 aiov.iov_len = count;
1669 MALLOC(dirbuf, caddr_t, count, M_TEMP, M_WAITOK);
1670 aiov.iov_base = dirbuf;
1671 error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred);
1672 if (error == 0) {
1673 readcnt = count - auio.uio_resid;
1674 edp = (struct direct *)&dirbuf[readcnt];
1675 ncookies = 0;
e088dc32
JS
1676 for (dp = (struct direct *)dirbuf;
1677 !error && uio->uio_resid > 0 && dp < edp; ) {
82fd1984
JS
1678 if (dp->d_reclen <= 0) {
1679 error = EIO;
1680 break;
1681 }
e088dc32
JS
1682#if BYTE_ORDER == LITTLE_ENDIAN
1683 if (OFSFMT(ap->a_vp)) {
82fd1984
JS
1684 retval = vop_write_dirent(&error, uio,
1685 dp->d_ino, dp->d_namlen, dp->d_type,
1686 dp->d_name);
e088dc32
JS
1687 } else
1688#endif
1689 {
82fd1984
JS
1690 retval = vop_write_dirent(&error, uio,
1691 dp->d_ino, dp->d_type, dp->d_namlen,
1692 dp->d_name);
e088dc32 1693 }
82fd1984
JS
1694
1695 if (retval)
e088dc32 1696 break;
82fd1984
JS
1697 /* advance dp */
1698 dp = (struct direct *)((char *)dp + dp->d_reclen);
1699 if (!error)
1700 ncookies++;
984263bc 1701 }
e088dc32
JS
1702 /* we need to correct uio_offset */
1703 uio->uio_offset = startoffset + (caddr_t)dp - dirbuf;
1704
1705 if (!error && ap->a_ncookies != NULL) {
1706 u_long *cookiep, *cookies, *ecookies;
1707 off_t off;
1708
1709 if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
1710 panic("ufs_readdir: unexpected uio from NFS server");
1711 MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
1712 M_WAITOK);
1713 off = startoffset;
1714 for (dp = (struct direct *)dirbuf,
1715 cookiep = cookies, ecookies = cookies + ncookies;
1716 cookiep < ecookies;
1717 dp = (struct direct *)((caddr_t) dp + dp->d_reclen)) {
1718 off += dp->d_reclen;
1719 *cookiep++ = (u_long) off;
1720 }
1721 *ap->a_ncookies = ncookies;
1722 *ap->a_cookies = cookies;
984263bc 1723 }
984263bc 1724 }
e088dc32 1725 FREE(dirbuf, M_TEMP);
984263bc 1726 if (ap->a_eofflag)
e088dc32
JS
1727 *ap->a_eofflag = VTOI(ap->a_vp)->i_size <= uio->uio_offset;
1728 return (error);
984263bc
MD
1729}
1730
1731/*
1732 * Return target name of a symbolic link
0973c589
CP
1733 *
1734 * ufs_readlink(struct vnode *a_vp, struct uio *a_uio, struct ucred *a_cred)
984263bc 1735 */
0961aa92 1736static
984263bc 1737int
0973c589 1738ufs_readlink(struct vop_readlink_args *ap)
984263bc 1739{
3ff2135f
RG
1740 struct vnode *vp = ap->a_vp;
1741 struct inode *ip = VTOI(vp);
984263bc
MD
1742 int isize;
1743
1744 isize = ip->i_size;
1745 if ((isize < vp->v_mount->mnt_maxsymlinklen) ||
f719c866 1746 (ip->i_din.di_blocks == 0)) { /* XXX - for old fastlink support */
984263bc
MD
1747 uiomove((char *)ip->i_shortlink, isize, ap->a_uio);
1748 return (0);
1749 }
1750 return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
1751}
1752
1753/*
1754 * Calculate the logical to physical mapping if not done already,
1755 * then call the device strategy routine.
1756 *
1757 * In order to be able to swap to a file, the VOP_BMAP operation may not
1758 * deadlock on memory. See ufs_bmap() for details.
0973c589 1759 *
81b5c339 1760 * ufs_strategy(struct vnode *a_vp, struct bio *a_bio)
984263bc 1761 */
0961aa92 1762static
984263bc 1763int
0973c589 1764ufs_strategy(struct vop_strategy_args *ap)
984263bc 1765{
81b5c339
MD
1766 struct bio *bio = ap->a_bio;
1767 struct bio *nbio;
1768 struct buf *bp = bio->bio_buf;
3ff2135f
RG
1769 struct vnode *vp = ap->a_vp;
1770 struct inode *ip;
984263bc
MD
1771 int error;
1772
1773 ip = VTOI(vp);
1774 if (vp->v_type == VBLK || vp->v_type == VCHR)
1775 panic("ufs_strategy: spec");
81b5c339 1776 nbio = push_bio(bio);
54078292
MD
1777 if (nbio->bio_offset == NOOFFSET) {
1778 error = VOP_BMAP(vp, bio->bio_offset, NULL, &nbio->bio_offset,
81b5c339 1779 NULL, NULL);
984263bc
MD
1780 if (error) {
1781 bp->b_error = error;
1782 bp->b_flags |= B_ERROR;
81b5c339
MD
1783 /* I/O was never started on nbio, must biodone(bio) */
1784 biodone(bio);
984263bc
MD
1785 return (error);
1786 }
54078292 1787 if (nbio->bio_offset == NOOFFSET)
984263bc
MD
1788 vfs_bio_clrbuf(bp);
1789 }
54078292 1790 if (nbio->bio_offset == NOOFFSET) {
81b5c339
MD
1791 /* I/O was never started on nbio, must biodone(bio) */
1792 biodone(bio);
984263bc
MD
1793 return (0);
1794 }
81b5c339 1795 vn_strategy(ip->i_devvp, nbio);
984263bc
MD
1796 return (0);
1797}
1798
1799/*
1800 * Print out the contents of an inode.
0973c589
CP
1801 *
1802 * ufs_print(struct vnode *a_vp)
984263bc 1803 */
0961aa92 1804static
984263bc 1805int
0973c589 1806ufs_print(struct vop_print_args *ap)
984263bc 1807{
3ff2135f
RG
1808 struct vnode *vp = ap->a_vp;
1809 struct inode *ip = VTOI(vp);
984263bc
MD
1810
1811 printf("tag VT_UFS, ino %lu, on dev %s (%d, %d)",
1812 (u_long)ip->i_number, devtoname(ip->i_dev), major(ip->i_dev),
1813 minor(ip->i_dev));
1814 if (vp->v_type == VFIFO)
1815 fifo_printinfo(vp);
3446c007 1816 lockmgr_printinfo(&vp->v_lock);
984263bc
MD
1817 printf("\n");
1818 return (0);
1819}
1820
1821/*
1822 * Read wrapper for special devices.
0973c589
CP
1823 *
1824 * ufsspec_read(struct vnode *a_vp, struct uio *a_uio, int a_ioflag,
1825 * struct ucred *a_cred)
984263bc 1826 */
0961aa92 1827static
984263bc 1828int
0973c589 1829ufsspec_read(struct vop_read_args *ap)
984263bc
MD
1830{
1831 int error, resid;
1832 struct inode *ip;
1833 struct uio *uio;
1834
1835 uio = ap->a_uio;
1836 resid = uio->uio_resid;
0961aa92 1837 error = VOCALL(spec_vnode_vops, &ap->a_head);
984263bc
MD
1838 /*
1839 * The inode may have been revoked during the call, so it must not
1840 * be accessed blindly here or in the other wrapper functions.
1841 */
1842 ip = VTOI(ap->a_vp);
1843 if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0)))
1844 ip->i_flag |= IN_ACCESS;
1845 return (error);
1846}
1847
1848/*
1849 * Write wrapper for special devices.
0973c589
CP
1850 *
1851 * ufsspec_write(struct vnode *a_vp, struct uio *a_uio, int a_ioflag,
1852 * struct ucred *a_cred)
984263bc 1853 */
0961aa92 1854static
984263bc 1855int
0973c589 1856ufsspec_write(struct vop_write_args *ap)
984263bc
MD
1857{
1858 int error, resid;
1859 struct inode *ip;
1860 struct uio *uio;
1861
1862 uio = ap->a_uio;
1863 resid = uio->uio_resid;
0961aa92 1864 error = VOCALL(spec_vnode_vops, &ap->a_head);
984263bc
MD
1865 ip = VTOI(ap->a_vp);
1866 if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0)))
1867 VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
1868 return (error);
1869}
1870
1871/*
1872 * Close wrapper for special devices.
1873 *
1874 * Update the times on the inode then do device close.
0973c589
CP
1875 *
1876 * ufsspec_close(struct vnode *a_vp, int a_fflag, struct ucred *a_cred,
1877 * struct thread *a_td)
984263bc 1878 */
0961aa92 1879static
984263bc 1880int
0973c589 1881ufsspec_close(struct vop_close_args *ap)
984263bc
MD
1882{
1883 struct vnode *vp = ap->a_vp;
1884
984263bc
MD
1885 if (vp->v_usecount > 1)
1886 ufs_itimes(vp);
0961aa92 1887 return (VOCALL(spec_vnode_vops, &ap->a_head));
984263bc
MD
1888}
1889
1890/*
1891 * Read wrapper for fifos.
0973c589
CP
1892 *
1893 * ufsfifo_read(struct vnode *a_vp, struct uio *a_uio, int a_ioflag,
1894 * struct ucred *a_cred)
984263bc 1895 */
0961aa92 1896static
984263bc 1897int
0973c589 1898ufsfifo_read(struct vop_read_args *ap)
984263bc
MD
1899{
1900 int error, resid;
1901 struct inode *ip;
1902 struct uio *uio;
1903
1904 uio = ap->a_uio;
1905 resid = uio->uio_resid;
0961aa92 1906 error = VOCALL(fifo_vnode_vops, &ap->a_head);
984263bc
MD
1907 ip = VTOI(ap->a_vp);
1908 if ((ap->a_vp->v_mount->mnt_flag & MNT_NOATIME) == 0 && ip != NULL &&
1909 (uio->uio_resid != resid || (error == 0 && resid != 0)))
1910 VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
1911 return (error);
1912}
1913
1914/*
1915 * Write wrapper for fifos.
0973c589
CP
1916 *
1917 * ufsfifo_write(struct vnode *a_vp, struct uio *a_uio, int a_ioflag,
1918 * struct ucred *a_cred)
984263bc 1919 */
0961aa92 1920static
984263bc 1921int
0973c589 1922ufsfifo_write(struct vop_write_args *ap)
984263bc
MD
1923{
1924 int error, resid;
1925 struct inode *ip;
1926 struct uio *uio;
1927
1928 uio = ap->a_uio;
1929 resid = uio->uio_resid;
0961aa92 1930 error = VOCALL(fifo_vnode_vops, &ap->a_head);
984263bc
MD
1931 ip = VTOI(ap->a_vp);
1932 if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0)))
1933 VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
1934 return (error);
1935}
1936
1937/*
1938 * Close wrapper for fifos.
1939 *
1940 * Update the times on the inode then do device close.
0973c589
CP
1941 *
1942 * ufsfifo_close(struct vnode *a_vp, int a_fflag, struct ucred *a_cred,
1943 * struct thread *a_td)
984263bc 1944 */
0961aa92 1945static
984263bc 1946int
0973c589 1947ufsfifo_close(struct vop_close_args *ap)
984263bc
MD
1948{
1949 struct vnode *vp = ap->a_vp;
1950
984263bc
MD
1951 if (vp->v_usecount > 1)
1952 ufs_itimes(vp);
0961aa92 1953 return (VOCALL(fifo_vnode_vops, &ap->a_head));
984263bc
MD
1954}
1955
1956/*
1957 * Kqfilter wrapper for fifos.
1958 *
1959 * Fall through to ufs kqfilter routines if needed
1960 */
0961aa92 1961static
984263bc 1962int
0973c589 1963ufsfifo_kqfilter(struct vop_kqfilter_args *ap)
984263bc
MD
1964{
1965 int error;
1966
0961aa92 1967 error = VOCALL(fifo_vnode_vops, &ap->a_head);
984263bc
MD
1968 if (error)
1969 error = ufs_kqfilter(ap);
1970 return (error);
1971}
1972
1973/*
1974 * Return POSIX pathconf information applicable to ufs filesystems.
0973c589
CP
1975 *
1976 * ufs_pathconf(struct vnode *a_vp, int a_name, int *a_retval)
984263bc 1977 */
0961aa92 1978static
984263bc 1979int
0973c589 1980ufs_pathconf(struct vop_pathconf_args *ap)
984263bc 1981{
984263bc
MD
1982 switch (ap->a_name) {
1983 case _PC_LINK_MAX:
1984 *ap->a_retval = LINK_MAX;
1985 return (0);
1986 case _PC_NAME_MAX:
1987 *ap->a_retval = NAME_MAX;
1988 return (0);
1989 case _PC_PATH_MAX:
1990 *ap->a_retval = PATH_MAX;
1991 return (0);
1992 case _PC_PIPE_BUF:
1993 *ap->a_retval = PIPE_BUF;
1994 return (0);
1995 case _PC_CHOWN_RESTRICTED:
1996 *ap->a_retval = 1;
1997 return (0);
1998 case _PC_NO_TRUNC:
1999 *ap->a_retval = 1;
2000 return (0);
2001 default:
2002 return (EINVAL);
2003 }
2004 /* NOTREACHED */
2005}
2006
2007/*
2008 * Advisory record locking support
0973c589
CP
2009 *
2010 * ufs_advlock(struct vnode *a_vp, caddr_t a_id, int a_op, struct flock *a_fl,
2011 * int a_flags)
984263bc 2012 */
0961aa92 2013static
984263bc 2014int
0973c589 2015ufs_advlock(struct vop_advlock_args *ap)
984263bc 2016{
3ff2135f 2017 struct inode *ip = VTOI(ap->a_vp);
984263bc
MD
2018
2019 return (lf_advlock(ap, &(ip->i_lockf), ip->i_size));
2020}
2021
2022/*
2023 * Initialize the vnode associated with a new inode, handle aliased
2024 * vnodes.
2025 */
2026int
0961aa92 2027ufs_vinit(struct mount *mntp, struct vnode **vpp)
984263bc
MD
2028{
2029 struct inode *ip;
2030 struct vnode *vp;
2031 struct timeval tv;
2032
2033 vp = *vpp;
2034 ip = VTOI(vp);
2035 switch(vp->v_type = IFTOVT(ip->i_mode)) {
2036 case VCHR:
2037 case VBLK:
6ddb7618 2038 vp->v_ops = &mntp->mnt_vn_spec_ops;
984263bc
MD
2039 addaliasu(vp, ip->i_rdev);
2040 break;
2041 case VFIFO:
6ddb7618 2042 vp->v_ops = &mntp->mnt_vn_fifo_ops;
984263bc
MD
2043 break;
2044 default:
2045 break;
2046
2047 }
2048 if (ip->i_number == ROOTINO)
2049 vp->v_flag |= VROOT;
2050 /*
2051 * Initialize modrev times
2052 */
2053 getmicrouptime(&tv);
2054 SETHIGH(ip->i_modrev, tv.tv_sec);
2055 SETLOW(ip->i_modrev, tv.tv_usec * 4294);
2056 *vpp = vp;
2057 return (0);
2058}
2059
2060/*
2061 * Allocate a new inode.
2062 */
0961aa92 2063static
984263bc 2064int
0973c589
CP
2065ufs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
2066 struct componentname *cnp)
984263bc 2067{
3ff2135f 2068 struct inode *ip, *pdir;
984263bc
MD
2069 struct direct newdir;
2070 struct vnode *tvp;
2071 int error;
2072
2073 pdir = VTOI(dvp);
984263bc
MD
2074 *vpp = NULL;
2075 if ((mode & IFMT) == 0)
2076 mode |= IFREG;
2077
2078 error = UFS_VALLOC(dvp, mode, cnp->cn_cred, &tvp);
2079 if (error)
2080 return (error);
2081 ip = VTOI(tvp);
2082 ip->i_gid = pdir->i_gid;
2083#ifdef SUIDDIR
2084 {
2085#ifdef QUOTA
2086 struct ucred ucred, *ucp;
2087 ucp = cnp->cn_cred;
2088#endif
2089 /*
2090 * If we are not the owner of the directory,
2091 * and we are hacking owners here, (only do this where told to)
2092 * and we are not giving it TO root, (would subvert quotas)
2093 * then go ahead and give it to the other user.
2094 * Note that this drops off the execute bits for security.
2095 */
2096 if ((dvp->v_mount->mnt_flag & MNT_SUIDDIR) &&
2097 (pdir->i_mode & ISUID) &&
2098 (pdir->i_uid != cnp->cn_cred->cr_uid) && pdir->i_uid) {
2099 ip->i_uid = pdir->i_uid;
2100 mode &= ~07111;
2101#ifdef QUOTA
2102 /*
2103 * Make sure the correct user gets charged
2104 * for the space.
2105 * Quickly knock up a dummy credential for the victim.
2106 * XXX This seems to never be accessed out of our
2107 * context so a stack variable is ok.
2108 */
2109 ucred.cr_ref = 1;
2110 ucred.cr_uid = ip->i_uid;
2111 ucred.cr_ngroups = 1;
2112 ucred.cr_groups[0] = pdir->i_gid;
2113 ucp = &ucred;
2114#endif
2115 } else
2116 ip->i_uid = cnp->cn_cred->cr_uid;
2117
2118#ifdef QUOTA
2119 if ((error = getinoquota(ip)) ||
2120 (error = chkiq(ip, 1, ucp, 0))) {
2121 UFS_VFREE(tvp, ip->i_number, mode);
2122 vput(tvp);
2123 return (error);
2124 }
2125#endif
2126 }
2127#else /* !SUIDDIR */
2128 ip->i_uid = cnp->cn_cred->cr_uid;
2129#ifdef QUOTA
2130 if ((error = getinoquota(ip)) ||
2131 (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
2132 UFS_VFREE(tvp, ip->i_number, mode);
2133 vput(tvp);
2134 return (error);
2135 }
2136#endif
2137#endif /* !SUIDDIR */
2138 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
2139 ip->i_mode = mode;
2140 tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */
2141 ip->i_effnlink = 1;
2142 ip->i_nlink = 1;
2143 if (DOINGSOFTDEP(tvp))
2144 softdep_change_linkcnt(ip);
2145 if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) &&
dadab5e9 2146 suser_cred(cnp->cn_cred, 0)) {
984263bc 2147 ip->i_mode &= ~ISGID;
41c20dac 2148 }
984263bc 2149
2b69e610 2150 if (cnp->cn_flags & CNP_ISWHITEOUT)
984263bc
MD
2151 ip->i_flags |= UF_OPAQUE;
2152
2153 /*
2154 * Make sure inode goes to disk before directory entry.
2155 */
2156 error = UFS_UPDATE(tvp, !(DOINGSOFTDEP(tvp) | DOINGASYNC(tvp)));
2157 if (error)
2158 goto bad;
2159 ufs_makedirentry(ip, cnp, &newdir);
2160 error = ufs_direnter(dvp, tvp, &newdir, cnp, NULL);
2161 if (error)
2162 goto bad;
2163 *vpp = tvp;
2164 return (0);
2165
2166bad:
2167 /*
2168 * Write error occurred trying to update the inode
2169 * or the directory so must deallocate the inode.
2170 */
2171 ip->i_effnlink = 0;
2172 ip->i_nlink = 0;
2173 ip->i_flag |= IN_CHANGE;
2174 if (DOINGSOFTDEP(tvp))
2175 softdep_change_linkcnt(ip);
2176 vput(tvp);
2177 return (error);
2178}
2179
2180static int
0973c589 2181ufs_missingop(struct vop_generic_args *ap)
984263bc 2182{
984263bc
MD
2183 panic("no vop function for %s in ufs child", ap->a_desc->vdesc_name);
2184 return (EOPNOTSUPP);
2185}
2186
2187static struct filterops ufsread_filtops =
2188 { 1, NULL, filt_ufsdetach, filt_ufsread };
2189static struct filterops ufswrite_filtops =
2190 { 1, NULL, filt_ufsdetach, filt_ufswrite };
2191static struct filterops ufsvnode_filtops =
2192 { 1, NULL, filt_ufsdetach, filt_ufsvnode };
2193
0973c589
CP
2194/*
2195 * ufs_kqfilter(struct vnode *a_vp, struct knote *a_kn)
2196 */
984263bc 2197static int
0973c589 2198ufs_kqfilter(struct vop_kqfilter_args *ap)
984263bc
MD
2199{
2200 struct vnode *vp = ap->a_vp;
2201 struct knote *kn = ap->a_kn;
41a01a4d 2202 lwkt_tokref ilock;
984263bc
MD
2203
2204 switch (kn->kn_filter) {
2205 case EVFILT_READ:
2206 kn->kn_fop = &ufsread_filtops;
2207 break;
2208 case EVFILT_WRITE:
2209 kn->kn_fop = &ufswrite_filtops;
2210 break;
2211 case EVFILT_VNODE:
2212 kn->kn_fop = &ufsvnode_filtops;
2213 break;
2214 default:
2215 return (1);
2216 }
2217
2218 kn->kn_hook = (caddr_t)vp;
2219
41a01a4d 2220 lwkt_gettoken(&ilock, &vp->v_pollinfo.vpi_token);
984263bc 2221 SLIST_INSERT_HEAD(&vp->v_pollinfo.vpi_selinfo.si_note, kn, kn_selnext);
41a01a4d 2222 lwkt_reltoken(&ilock);
984263bc
MD
2223
2224 return (0);
2225}
2226
2227static void
2228filt_ufsdetach(struct knote *kn)
2229{
2230 struct vnode *vp = (struct vnode *)kn->kn_hook;
41a01a4d 2231 lwkt_tokref ilock;
984263bc 2232
41a01a4d 2233 lwkt_gettoken(&ilock, &vp->v_pollinfo.vpi_token);
984263bc
MD
2234 SLIST_REMOVE(&vp->v_pollinfo.vpi_selinfo.si_note,
2235 kn, knote, kn_selnext);
41a01a4d 2236 lwkt_reltoken(&ilock);
984263bc
MD
2237}
2238
2239/*ARGSUSED*/
2240static int
2241filt_ufsread(struct knote *kn, long hint)
2242{
2243 struct vnode *vp = (struct vnode *)kn->kn_hook;
2244 struct inode *ip = VTOI(vp);
2245
2246 /*
2247 * filesystem is gone, so set the EOF flag and schedule
2248 * the knote for deletion.
2249 */
2250 if (hint == NOTE_REVOKE) {
2251 kn->kn_flags |= (EV_EOF | EV_ONESHOT);
2252 return (1);
2253 }
2254
2255 kn->kn_data = ip->i_size - kn->kn_fp->f_offset;
2256 return (kn->kn_data != 0);
2257}
2258
2259/*ARGSUSED*/
2260static int
2261filt_ufswrite(struct knote *kn, long hint)
2262{
984263bc
MD
2263 /*
2264 * filesystem is gone, so set the EOF flag and schedule
2265 * the knote for deletion.
2266 */
2267 if (hint == NOTE_REVOKE)
2268 kn->kn_flags |= (EV_EOF | EV_ONESHOT);
2269
2270 kn->kn_data = 0;
2271 return (1);
2272}
2273
2274static int
2275filt_ufsvnode(struct knote *kn, long hint)
2276{
984263bc
MD
2277 if (kn->kn_sfflags & hint)
2278 kn->kn_fflags |= hint;
2279 if (hint == NOTE_REVOKE) {
2280 kn->kn_flags |= EV_EOF;
2281 return (1);
2282 }
2283 return (kn->kn_fflags != 0);
2284}
2285
2286/* Global vfs data structures for ufs. */
2d3e977e 2287static struct vop_ops *ufs_vnode_vops;
984263bc 2288static struct vnodeopv_entry_desc ufs_vnodeop_entries[] = {
2d3e977e 2289 { &vop_default_desc, vop_defaultop },
625ddaba
JS
2290 { &vop_fsync_desc, (vnodeopv_entry_t) ufs_missingop },
2291 { &vop_read_desc, (vnodeopv_entry_t) ufs_missingop },
2292 { &vop_reallocblks_desc, (vnodeopv_entry_t) ufs_missingop },
2293 { &vop_write_desc, (vnodeopv_entry_t) ufs_missingop },
2294 { &vop_access_desc, (vnodeopv_entry_t) ufs_access },
2295 { &vop_advlock_desc, (vnodeopv_entry_t) ufs_advlock },
2296 { &vop_bmap_desc, (vnodeopv_entry_t) ufs_bmap },
e62afb5f 2297 { &vop_old_lookup_desc, (vnodeopv_entry_t) ufs_lookup },
625ddaba 2298 { &vop_close_desc, (vnodeopv_entry_t) ufs_close },
e62afb5f 2299 { &vop_old_create_desc, (vnodeopv_entry_t) ufs_create },
625ddaba
JS
2300 { &vop_getattr_desc, (vnodeopv_entry_t) ufs_getattr },
2301 { &vop_inactive_desc, (vnodeopv_entry_t) ufs_inactive },
2302 { &vop_islocked_desc, (vnodeopv_entry_t) vop_stdislocked },
e62afb5f 2303 { &vop_old_link_desc, (vnodeopv_entry_t) ufs_link },
625ddaba 2304 { &vop_lock_desc, (vnodeopv_entry_t) vop_stdlock },
e62afb5f
MD
2305 { &vop_old_mkdir_desc, (vnodeopv_entry_t) ufs_mkdir },
2306 { &vop_old_mknod_desc, (vnodeopv_entry_t) ufs_mknod },
625ddaba
JS
2307 { &vop_mmap_desc, (vnodeopv_entry_t) ufs_mmap },
2308 { &vop_open_desc, (vnodeopv_entry_t) ufs_open },
2309 { &vop_pathconf_desc, (vnodeopv_entry_t) ufs_pathconf },
2310 { &vop_poll_desc, (vnodeopv_entry_t) vop_stdpoll },
2311 { &vop_kqfilter_desc, (vnodeopv_entry_t) ufs_kqfilter },
2312 { &vop_print_desc, (vnodeopv_entry_t) ufs_print },
2313 { &vop_readdir_desc, (vnodeopv_entry_t) ufs_readdir },
2314 { &vop_readlink_desc, (vnodeopv_entry_t) ufs_readlink },
2315 { &vop_reclaim_desc, (vnodeopv_entry_t) ufs_reclaim },
e62afb5f
MD
2316 { &vop_old_remove_desc, (vnodeopv_entry_t) ufs_remove },
2317 { &vop_old_rename_desc, (vnodeopv_entry_t) ufs_rename },
2318 { &vop_old_rmdir_desc, (vnodeopv_entry_t) ufs_rmdir },
625ddaba
JS
2319 { &vop_setattr_desc, (vnodeopv_entry_t) ufs_setattr },
2320 { &vop_strategy_desc, (vnodeopv_entry_t) ufs_strategy },
e62afb5f 2321 { &vop_old_symlink_desc, (vnodeopv_entry_t) ufs_symlink },
625ddaba 2322 { &vop_unlock_desc, (vnodeopv_entry_t) vop_stdunlock },
e62afb5f 2323 { &vop_old_whiteout_desc, (vnodeopv_entry_t) ufs_whiteout },
984263bc
MD
2324 { NULL, NULL }
2325};
2326static struct vnodeopv_desc ufs_vnodeop_opv_desc =
dc1be39c 2327 { &ufs_vnode_vops, ufs_vnodeop_entries, VVF_SUPPORTS_FSMID };
984263bc 2328
2d3e977e 2329static struct vop_ops *ufs_spec_vops;
984263bc 2330static struct vnodeopv_entry_desc ufs_specop_entries[] = {
625ddaba
JS
2331 { &vop_default_desc, (vnodeopv_entry_t) spec_vnoperate },
2332 { &vop_fsync_desc, (vnodeopv_entry_t) ufs_missingop },
2333 { &vop_access_desc, (vnodeopv_entry_t) ufs_access },
2334 { &vop_close_desc, (vnodeopv_entry_t) ufsspec_close },
2335 { &vop_getattr_desc, (vnodeopv_entry_t) ufs_getattr },
2336 { &vop_inactive_desc, (vnodeopv_entry_t) ufs_inactive },
2337 { &vop_islocked_desc, (vnodeopv_entry_t) vop_stdislocked },
2338 { &vop_lock_desc, (vnodeopv_entry_t) vop_stdlock },
2339 { &vop_print_desc, (vnodeopv_entry_t) ufs_print },
2340 { &vop_read_desc, (vnodeopv_entry_t) ufsspec_read },
2341 { &vop_reclaim_desc, (vnodeopv_entry_t) ufs_reclaim },
2342 { &vop_setattr_desc, (vnodeopv_entry_t) ufs_setattr },
2343 { &vop_unlock_desc, (vnodeopv_entry_t) vop_stdunlock },
2344 { &vop_write_desc, (vnodeopv_entry_t) ufsspec_write },
984263bc
MD
2345 { NULL, NULL }
2346};
2347static struct vnodeopv_desc ufs_specop_opv_desc =
dc1be39c 2348 { &ufs_spec_vops, ufs_specop_entries, VVF_SUPPORTS_FSMID };
984263bc 2349
2d3e977e 2350static struct vop_ops *ufs_fifo_vops;
984263bc 2351static struct vnodeopv_entry_desc ufs_fifoop_entries[] = {
625ddaba
JS
2352 { &vop_default_desc, (vnodeopv_entry_t) fifo_vnoperate },
2353 { &vop_fsync_desc, (vnodeopv_entry_t) ufs_missingop },
2354 { &vop_access_desc, (vnodeopv_entry_t) ufs_access },
2355 { &vop_close_desc, (vnodeopv_entry_t) ufsfifo_close },
2356 { &vop_getattr_desc, (vnodeopv_entry_t) ufs_getattr },
2357 { &vop_inactive_desc, (vnodeopv_entry_t) ufs_inactive },
2358 { &vop_islocked_desc, (vnodeopv_entry_t) vop_stdislocked },
2359 { &vop_kqfilter_desc, (vnodeopv_entry_t) ufsfifo_kqfilter },
2360 { &vop_lock_desc, (vnodeopv_entry_t) vop_stdlock },
2361 { &vop_print_desc, (vnodeopv_entry_t) ufs_print },
2362 { &vop_read_desc, (vnodeopv_entry_t) ufsfifo_read },
2363 { &vop_reclaim_desc, (vnodeopv_entry_t) ufs_reclaim },
2364 { &vop_setattr_desc, (vnodeopv_entry_t) ufs_setattr },
2365 { &vop_unlock_desc, (vnodeopv_entry_t) vop_stdunlock },
2366 { &vop_write_desc, (vnodeopv_entry_t) ufsfifo_write },
984263bc
MD
2367 { NULL, NULL }
2368};
2369static struct vnodeopv_desc ufs_fifoop_opv_desc =
dc1be39c 2370 { &ufs_fifo_vops, ufs_fifoop_entries, VVF_SUPPORTS_FSMID };
984263bc
MD
2371
2372VNODEOP_SET(ufs_vnodeop_opv_desc);
2373VNODEOP_SET(ufs_specop_opv_desc);
2374VNODEOP_SET(ufs_fifoop_opv_desc);
2375
0973c589
CP
2376/*
2377 * ufs_vnoperate(struct vnodeop_desc *a_desc)
2378 */
984263bc 2379int
0973c589 2380ufs_vnoperate(struct vop_generic_args *ap)
984263bc 2381{
0961aa92 2382 return (VOCALL(ufs_vnode_vops, ap));
984263bc
MD
2383}
2384
0973c589
CP
2385/*
2386 * ufs_vnoperatefifo(struct vnodeop_desc *a_desc)
2387 */
984263bc 2388int
0973c589 2389ufs_vnoperatefifo(struct vop_generic_args *ap)
984263bc 2390{
0961aa92 2391 return (VOCALL(ufs_fifo_vops, ap));
984263bc
MD
2392}
2393
0973c589
CP
2394/*
2395 * ufs_vnoperatespec(struct vnodeop_desc *a_desc)
2396 */
984263bc 2397int
0973c589 2398ufs_vnoperatespec(struct vop_generic_args *ap)
984263bc 2399{
0961aa92 2400 return (VOCALL(ufs_spec_vops, ap));
984263bc 2401}