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