Annotation of sys/ufs/ext2fs/ext2fs_vnops.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: ext2fs_vnops.c,v 1.48 2007/06/17 20:15:25 jasper Exp $ */
2: /* $NetBSD: ext2fs_vnops.c,v 1.1 1997/06/11 09:34:09 bouyer Exp $ */
3:
4: /*
5: * Copyright (c) 1997 Manuel Bouyer.
6: * Copyright (c) 1982, 1986, 1989, 1993
7: * The Regents of the University of California. All rights reserved.
8: * (c) UNIX System Laboratories, Inc.
9: * All or some portions of this file are derived from material licensed
10: * to the University of California by American Telephone and Telegraph
11: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
12: * the permission of UNIX System Laboratories, Inc.
13: *
14: * Redistribution and use in source and binary forms, with or without
15: * modification, are permitted provided that the following conditions
16: * are met:
17: * 1. Redistributions of source code must retain the above copyright
18: * notice, this list of conditions and the following disclaimer.
19: * 2. Redistributions in binary form must reproduce the above copyright
20: * notice, this list of conditions and the following disclaimer in the
21: * documentation and/or other materials provided with the distribution.
22: * 3. 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.14 (Berkeley) 10/26/94
39: * Modified for ext2fs by Manuel Bouyer.
40: */
41:
42: #include <sys/param.h>
43: #include <sys/systm.h>
44: #include <sys/resourcevar.h>
45: #include <sys/kernel.h>
46: #include <sys/file.h>
47: #include <sys/stat.h>
48: #include <sys/buf.h>
49: #include <sys/proc.h>
50: #include <sys/conf.h>
51: #include <sys/mount.h>
52: #include <sys/namei.h>
53: #include <sys/vnode.h>
54: #include <sys/lockf.h>
55: #include <sys/malloc.h>
56: #include <sys/pool.h>
57: #include <sys/signalvar.h>
58:
59: #include <uvm/uvm_extern.h>
60:
61: #include <miscfs/fifofs/fifo.h>
62: #include <miscfs/specfs/specdev.h>
63:
64: #include <ufs/ufs/quota.h>
65: #include <ufs/ufs/inode.h>
66: #include <ufs/ufs/ufs_extern.h>
67: #include <ufs/ufs/ufsmount.h>
68:
69: #include <ufs/ext2fs/ext2fs.h>
70: #include <ufs/ext2fs/ext2fs_extern.h>
71: #include <ufs/ext2fs/ext2fs_dir.h>
72:
73: static int ext2fs_chmod(struct vnode *, mode_t, struct ucred *, struct proc *);
74: static int ext2fs_chown(struct vnode *, uid_t, gid_t, struct ucred *, struct proc *);
75:
76: /*
77: * Create a regular file
78: */
79: int
80: ext2fs_create(void *v)
81: {
82: struct vop_create_args *ap = v;
83: return ext2fs_makeinode(MAKEIMODE(ap->a_vap->va_type,
84: ap->a_vap->va_mode),
85: ap->a_dvp, ap->a_vpp, ap->a_cnp);
86: }
87:
88: /*
89: * Mknod vnode call
90: */
91: /* ARGSUSED */
92: int
93: ext2fs_mknod(void *v)
94: {
95: struct vop_mknod_args *ap = v;
96: struct vattr *vap = ap->a_vap;
97: struct vnode **vpp = ap->a_vpp;
98: struct inode *ip;
99: int error;
100:
101: if ((error =
102: ext2fs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
103: ap->a_dvp, vpp, ap->a_cnp)) != 0)
104: return (error);
105: ip = VTOI(*vpp);
106: ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
107: if (vap->va_rdev != VNOVAL) {
108: /*
109: * Want to be able to use this to make badblock
110: * inodes, so don't truncate the dev number.
111: */
112: ip->i_e2din->e2di_rdev = h2fs32(vap->va_rdev);
113: }
114: /*
115: * Remove inode so that it will be reloaded by VFS_VGET and
116: * checked to see if it is an alias of an existing entry in
117: * the inode cache.
118: */
119: vput(*vpp);
120: (*vpp)->v_type = VNON;
121: vgone(*vpp);
122: *vpp = 0;
123: return (0);
124: }
125:
126: /*
127: * Open called.
128: *
129: * Just check the APPEND flag.
130: */
131: /* ARGSUSED */
132: int
133: ext2fs_open(void *v)
134: {
135: struct vop_open_args *ap = v;
136:
137: /*
138: * Files marked append-only must be opened for appending.
139: */
140: if ((VTOI(ap->a_vp)->i_e2fs_flags & EXT2_APPEND) &&
141: (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
142: return (EPERM);
143: return (0);
144: }
145:
146: int
147: ext2fs_access(void *v)
148: {
149: struct vop_access_args *ap = v;
150: struct vnode *vp = ap->a_vp;
151: struct inode *ip = VTOI(vp);
152: mode_t mode = ap->a_mode;
153:
154: /* If immutable bit set, nobody gets to write it. */
155: if ((mode & VWRITE) && (ip->i_e2fs_flags & EXT2_IMMUTABLE))
156: return (EPERM);
157:
158: return (vaccess(ip->i_e2fs_mode, ip->i_e2fs_uid, ip->i_e2fs_gid, mode,
159: ap->a_cred));
160: }
161:
162: /* ARGSUSED */
163: int
164: ext2fs_getattr(void *v)
165: {
166: struct vop_getattr_args *ap = v;
167: struct vnode *vp = ap->a_vp;
168: struct inode *ip = VTOI(vp);
169: struct vattr *vap = ap->a_vap;
170: struct timeval tv;
171:
172: getmicrotime(&tv);
173: EXT2FS_ITIMES(ip, &tv, &tv);
174: /*
175: * Copy from inode table
176: */
177: vap->va_fsid = ip->i_dev;
178: vap->va_fileid = ip->i_number;
179: vap->va_mode = ip->i_e2fs_mode & ALLPERMS;
180: vap->va_nlink = ip->i_e2fs_nlink;
181: vap->va_uid = ip->i_e2fs_uid;
182: vap->va_gid = ip->i_e2fs_gid;
183: vap->va_rdev = (dev_t)fs2h32(ip->i_e2din->e2di_rdev);
184: vap->va_size = ext2fs_size(ip);
185: vap->va_atime.tv_sec = ip->i_e2fs_atime;
186: vap->va_atime.tv_nsec = 0;
187: vap->va_mtime.tv_sec = ip->i_e2fs_mtime;
188: vap->va_mtime.tv_nsec = 0;
189: vap->va_ctime.tv_sec = ip->i_e2fs_ctime;
190: vap->va_ctime.tv_nsec = 0;
191: #ifdef EXT2FS_SYSTEM_FLAGS
192: vap->va_flags = (ip->i_e2fs_flags & EXT2_APPEND) ? SF_APPEND : 0;
193: vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? SF_IMMUTABLE : 0;
194: #else
195: vap->va_flags = (ip->i_e2fs_flags & EXT2_APPEND) ? UF_APPEND : 0;
196: vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? UF_IMMUTABLE : 0;
197: #endif
198: vap->va_gen = ip->i_e2fs_gen;
199: /* this doesn't belong here */
200: if (vp->v_type == VBLK)
201: vap->va_blocksize = BLKDEV_IOSIZE;
202: else if (vp->v_type == VCHR)
203: vap->va_blocksize = MAXBSIZE;
204: else
205: vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
206: vap->va_bytes = dbtob((u_quad_t)ip->i_e2fs_nblock);
207: vap->va_type = vp->v_type;
208: vap->va_filerev = ip->i_modrev;
209: return (0);
210: }
211:
212: /*
213: * Set attribute vnode op. called from several syscalls
214: */
215: int
216: ext2fs_setattr(void *v)
217: {
218: struct vop_setattr_args *ap = v;
219: struct vattr *vap = ap->a_vap;
220: struct vnode *vp = ap->a_vp;
221: struct inode *ip = VTOI(vp);
222: struct ucred *cred = ap->a_cred;
223: struct proc *p = ap->a_p;
224: int error;
225:
226: /*
227: * Check for unsettable attributes.
228: */
229: if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
230: (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
231: (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
232: ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
233: return (EINVAL);
234: }
235: if (vap->va_flags != VNOVAL) {
236: if (vp->v_mount->mnt_flag & MNT_RDONLY)
237: return (EROFS);
238: if (cred->cr_uid != ip->i_e2fs_uid &&
239: (error = suser_ucred(cred)))
240: return (error);
241: #ifdef EXT2FS_SYSTEM_FLAGS
242: if (cred->cr_uid == 0) {
243: if ((ip->i_e2fs_flags &
244: (EXT2_APPEND | EXT2_IMMUTABLE)) && securelevel > 0)
245: return (EPERM);
246: ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
247: ip->i_e2fs_flags |=
248: (vap->va_flags & SF_APPEND) ? EXT2_APPEND : 0 |
249: (vap->va_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE: 0;
250: } else {
251: return (EPERM);
252: }
253: #else
254: ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
255: ip->i_e2fs_flags |=
256: (vap->va_flags & UF_APPEND) ? EXT2_APPEND : 0 |
257: (vap->va_flags & UF_IMMUTABLE) ? EXT2_IMMUTABLE: 0;
258: #endif
259: ip->i_flag |= IN_CHANGE;
260: if (vap->va_flags & (IMMUTABLE | APPEND))
261: return (0);
262: }
263: if (ip->i_e2fs_flags & (EXT2_APPEND | EXT2_IMMUTABLE))
264: return (EPERM);
265: /*
266: * Go through the fields and update iff not VNOVAL.
267: */
268: if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
269: if (vp->v_mount->mnt_flag & MNT_RDONLY)
270: return (EROFS);
271: error = ext2fs_chown(vp, vap->va_uid, vap->va_gid, cred, p);
272: if (error)
273: return (error);
274: }
275: if (vap->va_size != VNOVAL) {
276: /*
277: * Disallow write attempts on read-only file systems;
278: * unless the file is a socket, fifo, or a block or
279: * character device resident on the file system.
280: */
281: switch (vp->v_type) {
282: case VDIR:
283: return (EISDIR);
284: case VLNK:
285: case VREG:
286: if (vp->v_mount->mnt_flag & MNT_RDONLY)
287: return (EROFS);
288: default:
289: break;
290: }
291: error = ext2fs_truncate(ip, vap->va_size, 0, cred);
292: if (error)
293: return (error);
294: }
295: if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
296: if (vp->v_mount->mnt_flag & MNT_RDONLY)
297: return (EROFS);
298: if (cred->cr_uid != ip->i_e2fs_uid &&
299: (error = suser_ucred(cred)) &&
300: ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
301: (error = VOP_ACCESS(vp, VWRITE, cred, p))))
302: return (error);
303: if (vap->va_atime.tv_sec != VNOVAL)
304: if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
305: ip->i_flag |= IN_ACCESS;
306: if (vap->va_mtime.tv_sec != VNOVAL)
307: ip->i_flag |= IN_CHANGE | IN_UPDATE;
308: error = ext2fs_update(ip, &vap->va_atime, &vap->va_mtime, 1);
309: if (error)
310: return (error);
311: }
312: error = 0;
313: if (vap->va_mode != (mode_t)VNOVAL) {
314: if (vp->v_mount->mnt_flag & MNT_RDONLY)
315: return (EROFS);
316: error = ext2fs_chmod(vp, (int)vap->va_mode, cred, p);
317: }
318: return (error);
319: }
320:
321: /*
322: * Change the mode on a file.
323: * Inode must be locked before calling.
324: */
325: static int
326: ext2fs_chmod(struct vnode *vp, mode_t mode, struct ucred *cred, struct proc *p)
327: {
328: struct inode *ip = VTOI(vp);
329: int error;
330:
331: if (cred->cr_uid != ip->i_e2fs_uid && (error = suser_ucred(cred)))
332: return (error);
333: if (cred->cr_uid) {
334: if (vp->v_type != VDIR && (mode & S_ISTXT))
335: return (EFTYPE);
336: if (!groupmember(ip->i_e2fs_gid, cred) && (mode & ISGID))
337: return (EPERM);
338: }
339: ip->i_e2fs_mode &= ~ALLPERMS;
340: ip->i_e2fs_mode |= (mode & ALLPERMS);
341: ip->i_flag |= IN_CHANGE;
342: if ((vp->v_flag & VTEXT) && (ip->i_e2fs_mode & S_ISTXT) == 0)
343: (void) uvm_vnp_uncache(vp);
344: return (0);
345: }
346:
347: /*
348: * Perform chown operation on inode ip;
349: * inode must be locked prior to call.
350: */
351: static int
352: ext2fs_chown(struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred, struct proc *p)
353: {
354: struct inode *ip = VTOI(vp);
355: uid_t ouid;
356: gid_t ogid;
357: int error = 0;
358:
359: if (uid == (uid_t)VNOVAL)
360: uid = ip->i_e2fs_uid;
361: if (gid == (gid_t)VNOVAL)
362: gid = ip->i_e2fs_gid;
363: /*
364: * If we don't own the file, are trying to change the owner
365: * of the file, or are not a member of the target group,
366: * the caller must be superuser or the call fails.
367: */
368: if ((cred->cr_uid != ip->i_e2fs_uid || uid != ip->i_e2fs_uid ||
369: (gid != ip->i_e2fs_gid && !groupmember((gid_t)gid, cred))) &&
370: (error = suser_ucred(cred)))
371: return (error);
372: ogid = ip->i_e2fs_gid;
373: ouid = ip->i_e2fs_uid;
374:
375: ip->i_e2fs_gid = gid;
376: ip->i_e2fs_uid = uid;
377: if (ouid != uid || ogid != gid)
378: ip->i_flag |= IN_CHANGE;
379: if (ouid != uid && cred->cr_uid != 0)
380: ip->i_e2fs_mode &= ~ISUID;
381: if (ogid != gid && cred->cr_uid != 0)
382: ip->i_e2fs_mode &= ~ISGID;
383: return (0);
384: }
385:
386: int
387: ext2fs_remove(void *v)
388: {
389: struct vop_remove_args *ap = v;
390: struct inode *ip;
391: struct vnode *vp = ap->a_vp;
392: struct vnode *dvp = ap->a_dvp;
393: int error;
394:
395: ip = VTOI(vp);
396: if (vp->v_type == VDIR ||
397: (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
398: (VTOI(dvp)->i_e2fs_flags & EXT2_APPEND)) {
399: error = EPERM;
400: goto out;
401: }
402: error = ext2fs_dirremove(dvp, ap->a_cnp);
403: if (error == 0) {
404: ip->i_e2fs_nlink--;
405: ip->i_flag |= IN_CHANGE;
406: }
407: out:
408: if (dvp == vp)
409: vrele(vp);
410: else
411: vput(vp);
412: vput(dvp);
413: return (error);
414: }
415:
416: /*
417: * link vnode call
418: */
419: int
420: ext2fs_link(void *v)
421: {
422: struct vop_link_args *ap = v;
423: struct vnode *dvp = ap->a_dvp;
424: struct vnode *vp = ap->a_vp;
425: struct componentname *cnp = ap->a_cnp;
426: struct proc *p = cnp->cn_proc;
427: struct inode *ip;
428: int error;
429:
430: #ifdef DIAGNOSTIC
431: if ((cnp->cn_flags & HASBUF) == 0)
432: panic("ext2fs_link: no name");
433: #endif
434: if (vp->v_type == VDIR) {
435: VOP_ABORTOP(dvp, cnp);
436: error = EISDIR;
437: goto out2;
438: }
439: if (dvp->v_mount != vp->v_mount) {
440: VOP_ABORTOP(dvp, cnp);
441: error = EXDEV;
442: goto out2;
443: }
444: if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, p))) {
445: VOP_ABORTOP(dvp, cnp);
446: goto out2;
447: }
448: ip = VTOI(vp);
449: if ((nlink_t)ip->i_e2fs_nlink >= LINK_MAX) {
450: VOP_ABORTOP(dvp, cnp);
451: error = EMLINK;
452: goto out1;
453: }
454: if (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) {
455: VOP_ABORTOP(dvp, cnp);
456: error = EPERM;
457: goto out1;
458: }
459: ip->i_e2fs_nlink++;
460: ip->i_flag |= IN_CHANGE;
461: error = ext2fs_update(ip, NULL, NULL, 1);
462: if (!error)
463: error = ext2fs_direnter(ip, dvp, cnp);
464: if (error) {
465: ip->i_e2fs_nlink--;
466: ip->i_flag |= IN_CHANGE;
467: }
468: pool_put(&namei_pool, cnp->cn_pnbuf);
469: out1:
470: if (dvp != vp)
471: VOP_UNLOCK(vp, 0, p);
472: out2:
473: vput(dvp);
474: return (error);
475: }
476:
477: /*
478: * Rename system call.
479: * rename("foo", "bar");
480: * is essentially
481: * unlink("bar");
482: * link("foo", "bar");
483: * unlink("foo");
484: * but ``atomically''. Can't do full commit without saving state in the
485: * inode on disk which isn't feasible at this time. Best we can do is
486: * always guarantee the target exists.
487: *
488: * Basic algorithm is:
489: *
490: * 1) Bump link count on source while we're linking it to the
491: * target. This also ensure the inode won't be deleted out
492: * from underneath us while we work (it may be truncated by
493: * a concurrent `trunc' or `open' for creation).
494: * 2) Link source to destination. If destination already exists,
495: * delete it first.
496: * 3) Unlink source reference to inode if still around. If a
497: * directory was moved and the parent of the destination
498: * is different from the source, patch the ".." entry in the
499: * directory.
500: */
501: int
502: ext2fs_rename(void *v)
503: {
504: struct vop_rename_args *ap = v;
505: struct vnode *tvp = ap->a_tvp;
506: struct vnode *tdvp = ap->a_tdvp;
507: struct vnode *fvp = ap->a_fvp;
508: struct vnode *fdvp = ap->a_fdvp;
509: struct componentname *tcnp = ap->a_tcnp;
510: struct componentname *fcnp = ap->a_fcnp;
511: struct inode *ip, *xp, *dp;
512: struct proc *p = fcnp->cn_proc;
513: struct ext2fs_dirtemplate dirbuf;
514: /* struct timespec ts; */
515: int doingdirectory = 0, oldparent = 0, newparent = 0;
516: int error = 0;
517: u_char namlen;
518:
519: #ifdef DIAGNOSTIC
520: if ((tcnp->cn_flags & HASBUF) == 0 ||
521: (fcnp->cn_flags & HASBUF) == 0)
522: panic("ext2fs_rename: no name");
523: #endif
524: /*
525: * Check for cross-device rename.
526: */
527: if ((fvp->v_mount != tdvp->v_mount) ||
528: (tvp && (fvp->v_mount != tvp->v_mount))) {
529: error = EXDEV;
530: abortit:
531: VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
532: if (tdvp == tvp)
533: vrele(tdvp);
534: else
535: vput(tdvp);
536: if (tvp)
537: vput(tvp);
538: VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
539: vrele(fdvp);
540: vrele(fvp);
541: return (error);
542: }
543:
544: /*
545: * Check if just deleting a link name.
546: */
547: if (tvp && ((VTOI(tvp)->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
548: (VTOI(tdvp)->i_e2fs_flags & EXT2_APPEND))) {
549: error = EPERM;
550: goto abortit;
551: }
552: if (fvp == tvp) {
553: if (fvp->v_type == VDIR) {
554: error = EINVAL;
555: goto abortit;
556: }
557:
558: /* Release destination completely. */
559: VOP_ABORTOP(tdvp, tcnp);
560: vput(tdvp);
561: vput(tvp);
562:
563: /* Delete source. */
564: vrele(fdvp);
565: vrele(fvp);
566: fcnp->cn_flags &= ~MODMASK;
567: fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
568: if ((fcnp->cn_flags & SAVESTART) == 0)
569: panic("ext2fs_rename: lost from startdir");
570: fcnp->cn_nameiop = DELETE;
571: (void) relookup(fdvp, &fvp, fcnp);
572: return (VOP_REMOVE(fdvp, fvp, fcnp));
573: }
574: if ((error = vn_lock(fvp, LK_EXCLUSIVE, p)) != 0)
575: goto abortit;
576: dp = VTOI(fdvp);
577: ip = VTOI(fvp);
578: if ((nlink_t)ip->i_e2fs_nlink >= LINK_MAX) {
579: VOP_UNLOCK(fvp, 0, p);
580: error = EMLINK;
581: goto abortit;
582: }
583: if ((ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
584: (dp->i_e2fs_flags & EXT2_APPEND)) {
585: VOP_UNLOCK(fvp, 0, p);
586: error = EPERM;
587: goto abortit;
588: }
589: if ((ip->i_e2fs_mode & IFMT) == IFDIR) {
590: error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
591: if (!error && tvp)
592: error = VOP_ACCESS(tvp, VWRITE, tcnp->cn_cred,
593: tcnp->cn_proc);
594: if (error) {
595: VOP_UNLOCK(fvp, 0, p);
596: error = EACCES;
597: goto abortit;
598: }
599: /*
600: * Avoid ".", "..", and aliases of "." for obvious reasons.
601: */
602: if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
603: dp == ip ||
604: (fcnp->cn_flags&ISDOTDOT) ||
605: (tcnp->cn_flags & ISDOTDOT) ||
606: (ip->i_flag & IN_RENAME)) {
607: VOP_UNLOCK(fvp, 0, p);
608: error = EINVAL;
609: goto abortit;
610: }
611: ip->i_flag |= IN_RENAME;
612: oldparent = dp->i_number;
613: doingdirectory++;
614: }
615: vrele(fdvp);
616:
617: /*
618: * When the target exists, both the directory
619: * and target vnodes are returned locked.
620: */
621: dp = VTOI(tdvp);
622: xp = NULL;
623: if (tvp)
624: xp = VTOI(tvp);
625:
626: /*
627: * 1) Bump link count while we're moving stuff
628: * around. If we crash somewhere before
629: * completing our work, the link count
630: * may be wrong, but correctable.
631: */
632: ip->i_e2fs_nlink++;
633: ip->i_flag |= IN_CHANGE;
634: if ((error = ext2fs_update(ip, NULL, NULL, 1)) != 0) {
635: VOP_UNLOCK(fvp, 0, p);
636: goto bad;
637: }
638:
639: /*
640: * If ".." must be changed (ie the directory gets a new
641: * parent) then the source directory must not be in the
642: * directory hierarchy above the target, as this would
643: * orphan everything below the source directory. Also
644: * the user must have write permission in the source so
645: * as to be able to change "..". We must repeat the call
646: * to namei, as the parent directory is unlocked by the
647: * call to checkpath().
648: */
649: error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
650: VOP_UNLOCK(fvp, 0, p);
651: if (oldparent != dp->i_number)
652: newparent = dp->i_number;
653: if (doingdirectory && newparent) {
654: if (error) /* write access check above */
655: goto bad;
656: if (xp != NULL)
657: vput(tvp);
658: error = ext2fs_checkpath(ip, dp, tcnp->cn_cred);
659: if (error != 0)
660: goto out;
661: if ((tcnp->cn_flags & SAVESTART) == 0)
662: panic("ext2fs_rename: lost to startdir");
663: if ((error = relookup(tdvp, &tvp, tcnp)) != 0)
664: goto out;
665: dp = VTOI(tdvp);
666: xp = NULL;
667: if (tvp)
668: xp = VTOI(tvp);
669: }
670: /*
671: * 2) If target doesn't exist, link the target
672: * to the source and unlink the source.
673: * Otherwise, rewrite the target directory
674: * entry to reference the source inode and
675: * expunge the original entry's existence.
676: */
677: if (xp == NULL) {
678: if (dp->i_dev != ip->i_dev)
679: panic("rename: EXDEV");
680: /*
681: * Account for ".." in new directory.
682: * When source and destination have the same
683: * parent we don't fool with the link count.
684: */
685: if (doingdirectory && newparent) {
686: if ((nlink_t)dp->i_e2fs_nlink >= LINK_MAX) {
687: error = EMLINK;
688: goto bad;
689: }
690: dp->i_e2fs_nlink++;
691: dp->i_flag |= IN_CHANGE;
692: if ((error = ext2fs_update(dp, NULL, NULL, 1)) != 0)
693: goto bad;
694: }
695: error = ext2fs_direnter(ip, tdvp, tcnp);
696: if (error != 0) {
697: if (doingdirectory && newparent) {
698: dp->i_e2fs_nlink--;
699: dp->i_flag |= IN_CHANGE;
700: (void)ext2fs_update(dp, NULL, NULL, 1);
701: }
702: goto bad;
703: }
704: vput(tdvp);
705: } else {
706: if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
707: panic("rename: EXDEV");
708: /*
709: * Short circuit rename(foo, foo).
710: */
711: if (xp->i_number == ip->i_number)
712: panic("rename: same file");
713: /*
714: * If the parent directory is "sticky", then the user must
715: * own the parent directory, or the destination of the rename,
716: * otherwise the destination may not be changed (except by
717: * root). This implements append-only directories.
718: */
719: if ((dp->i_e2fs_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 &&
720: tcnp->cn_cred->cr_uid != dp->i_e2fs_uid &&
721: xp->i_e2fs_uid != tcnp->cn_cred->cr_uid) {
722: error = EPERM;
723: goto bad;
724: }
725: /*
726: * Target must be empty if a directory and have no links
727: * to it. Also, ensure source and target are compatible
728: * (both directories, or both not directories).
729: */
730: if ((xp->i_e2fs_mode & IFMT) == IFDIR) {
731: if (!ext2fs_dirempty(xp, dp->i_number, tcnp->cn_cred) ||
732: xp->i_e2fs_nlink > 2) {
733: error = ENOTEMPTY;
734: goto bad;
735: }
736: if (!doingdirectory) {
737: error = ENOTDIR;
738: goto bad;
739: }
740: cache_purge(tdvp);
741: } else if (doingdirectory) {
742: error = EISDIR;
743: goto bad;
744: }
745: error = ext2fs_dirrewrite(dp, ip, tcnp);
746: if (error != 0)
747: goto bad;
748: /*
749: * If the target directory is in the same
750: * directory as the source directory,
751: * decrement the link count on the parent
752: * of the target directory.
753: */
754: if (doingdirectory && !newparent) {
755: dp->i_e2fs_nlink--;
756: dp->i_flag |= IN_CHANGE;
757: }
758: vput(tdvp);
759: /*
760: * Adjust the link count of the target to
761: * reflect the dirrewrite above. If this is
762: * a directory it is empty and there are
763: * no links to it, so we can squash the inode and
764: * any space associated with it. We disallowed
765: * renaming over top of a directory with links to
766: * it above, as the remaining link would point to
767: * a directory without "." or ".." entries.
768: */
769: xp->i_e2fs_nlink--;
770: if (doingdirectory) {
771: if (--xp->i_e2fs_nlink != 0)
772: panic("rename: linked directory");
773: error = ext2fs_truncate(xp, (off_t)0, IO_SYNC,
774: tcnp->cn_cred);
775: }
776: xp->i_flag |= IN_CHANGE;
777: vput(tvp);
778: xp = NULL;
779: }
780:
781: /*
782: * 3) Unlink the source.
783: */
784: fcnp->cn_flags &= ~MODMASK;
785: fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
786: if ((fcnp->cn_flags & SAVESTART) == 0)
787: panic("ext2fs_rename: lost from startdir");
788: (void) relookup(fdvp, &fvp, fcnp);
789: if (fvp != NULL) {
790: xp = VTOI(fvp);
791: dp = VTOI(fdvp);
792: } else {
793: /*
794: * From name has disappeared.
795: */
796: if (doingdirectory)
797: panic("ext2fs_rename: lost dir entry");
798: vrele(ap->a_fvp);
799: return (0);
800: }
801: /*
802: * Ensure that the directory entry still exists and has not
803: * changed while the new name has been entered. If the source is
804: * a file then the entry may have been unlinked or renamed. In
805: * either case there is no further work to be done. If the source
806: * is a directory then it cannot have been rmdir'ed; its link
807: * count of three would cause a rmdir to fail with ENOTEMPTY.
808: * The IRENAME flag ensures that it cannot be moved by another
809: * rename.
810: */
811: if (xp != ip) {
812: if (doingdirectory)
813: panic("ext2fs_rename: lost dir entry");
814: } else {
815: /*
816: * If the source is a directory with a
817: * new parent, the link count of the old
818: * parent directory must be decremented
819: * and ".." set to point to the new parent.
820: */
821: if (doingdirectory && newparent) {
822: dp->i_e2fs_nlink--;
823: dp->i_flag |= IN_CHANGE;
824: error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf,
825: sizeof (struct ext2fs_dirtemplate), (off_t)0,
826: UIO_SYSSPACE, IO_NODELOCKED,
827: tcnp->cn_cred, (size_t *)0, (struct proc *)0);
828: if (error == 0) {
829: namlen = dirbuf.dotdot_namlen;
830: if (namlen != 2 ||
831: dirbuf.dotdot_name[0] != '.' ||
832: dirbuf.dotdot_name[1] != '.') {
833: ufs_dirbad(xp, (doff_t)12,
834: "ext2fs_rename: mangled dir");
835: } else {
836: dirbuf.dotdot_ino = h2fs32(newparent);
837: (void) vn_rdwr(UIO_WRITE, fvp,
838: (caddr_t)&dirbuf,
839: sizeof (struct dirtemplate),
840: (off_t)0, UIO_SYSSPACE,
841: IO_NODELOCKED|IO_SYNC,
842: tcnp->cn_cred, (size_t *)0,
843: (struct proc *)0);
844: cache_purge(fdvp);
845: }
846: }
847: }
848: error = ext2fs_dirremove(fdvp, fcnp);
849: if (!error) {
850: xp->i_e2fs_nlink--;
851: xp->i_flag |= IN_CHANGE;
852: }
853: xp->i_flag &= ~IN_RENAME;
854: }
855: if (dp)
856: vput(fdvp);
857: if (xp)
858: vput(fvp);
859: vrele(ap->a_fvp);
860: return (error);
861:
862: bad:
863: if (xp)
864: vput(ITOV(xp));
865: vput(ITOV(dp));
866: out:
867: if (doingdirectory)
868: ip->i_flag &= ~IN_RENAME;
869: if (vn_lock(fvp, LK_EXCLUSIVE, p) == 0) {
870: ip->i_e2fs_nlink--;
871: ip->i_flag |= IN_CHANGE;
872: vput(fvp);
873: } else
874: vrele(fvp);
875: return (error);
876: }
877:
878: /*
879: * Mkdir system call
880: */
881: int
882: ext2fs_mkdir(void *v)
883: {
884: struct vop_mkdir_args *ap = v;
885: struct vnode *dvp = ap->a_dvp;
886: struct vattr *vap = ap->a_vap;
887: struct componentname *cnp = ap->a_cnp;
888: struct inode *ip, *dp;
889: struct vnode *tvp;
890: struct ext2fs_dirtemplate dirtemplate;
891: mode_t dmode;
892: int error;
893:
894: #ifdef DIAGNOSTIC
895: if ((cnp->cn_flags & HASBUF) == 0)
896: panic("ext2fs_mkdir: no name");
897: #endif
898: dp = VTOI(dvp);
899: if ((nlink_t)dp->i_e2fs_nlink >= LINK_MAX) {
900: error = EMLINK;
901: goto out;
902: }
903: dmode = vap->va_mode & ACCESSPERMS;
904: dmode |= IFDIR;
905: /*
906: * Must simulate part of ext2fs_makeinode here to acquire the inode,
907: * but not have it entered in the parent directory. The entry is
908: * made later after writing "." and ".." entries.
909: */
910: if ((error = ext2fs_inode_alloc(dp, dmode, cnp->cn_cred, &tvp)) != 0)
911: goto out;
912: ip = VTOI(tvp);
913: ip->i_e2fs_uid = cnp->cn_cred->cr_uid;
914: ip->i_e2fs_gid = dp->i_e2fs_gid;
915: ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
916: ip->i_e2fs_mode = dmode;
917: tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */
918: ip->i_e2fs_nlink = 2;
919: error = ext2fs_update(ip, NULL, NULL, 1);
920:
921: /*
922: * Bump link count in parent directory
923: * to reflect work done below. Should
924: * be done before reference is created
925: * so reparation is possible if we crash.
926: */
927: dp->i_e2fs_nlink++;
928: dp->i_flag |= IN_CHANGE;
929: if ((error = ext2fs_update(dp, NULL, NULL, 1)) != 0)
930: goto bad;
931:
932: /* Initialize directory with "." and ".." from static template. */
933: bzero(&dirtemplate, sizeof(dirtemplate));
934: dirtemplate.dot_ino = h2fs32(ip->i_number);
935: dirtemplate.dot_reclen = h2fs16(12);
936: dirtemplate.dot_namlen = 1;
937: if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
938: (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
939: dirtemplate.dot_type = EXT2_FT_DIR;
940: }
941: dirtemplate.dot_name[0] = '.';
942: dirtemplate.dotdot_ino = h2fs32(dp->i_number);
943: dirtemplate.dotdot_reclen = h2fs16(VTOI(dvp)->i_e2fs->e2fs_bsize - 12);
944: dirtemplate.dotdot_namlen = 2;
945: if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
946: (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
947: dirtemplate.dotdot_type = EXT2_FT_DIR;
948: }
949: dirtemplate.dotdot_name[0] = dirtemplate.dotdot_name[1] = '.';
950: error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate,
951: sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
952: IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (size_t *)0, (struct proc *)0);
953: if (error) {
954: dp->i_e2fs_nlink--;
955: dp->i_flag |= IN_CHANGE;
956: goto bad;
957: }
958: if (VTOI(dvp)->i_e2fs->e2fs_bsize >
959: VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
960: panic("ext2fs_mkdir: blksize"); /* XXX should grow with balloc() */
961: else {
962: error = ext2fs_setsize(ip, VTOI(dvp)->i_e2fs->e2fs_bsize);
963: if (error) {
964: dp->i_e2fs_nlink--;
965: dp->i_flag |= IN_CHANGE;
966: goto bad;
967: }
968: ip->i_flag |= IN_CHANGE;
969: }
970:
971: /* Directory set up, now install its entry in the parent directory. */
972: error = ext2fs_direnter(ip, dvp, cnp);
973: if (error != 0) {
974: dp->i_e2fs_nlink--;
975: dp->i_flag |= IN_CHANGE;
976: }
977: bad:
978: /*
979: * No need to do an explicit VOP_TRUNCATE here, vrele will do this
980: * for us because we set the link count to 0.
981: */
982: if (error) {
983: ip->i_e2fs_nlink = 0;
984: ip->i_flag |= IN_CHANGE;
985: vput(tvp);
986: } else
987: *ap->a_vpp = tvp;
988: out:
989: pool_put(&namei_pool, cnp->cn_pnbuf);
990: vput(dvp);
991: return (error);
992: }
993:
994: /*
995: * Rmdir system call.
996: */
997: int
998: ext2fs_rmdir(void *v)
999: {
1000: struct vop_rmdir_args *ap = v;
1001: struct vnode *vp = ap->a_vp;
1002: struct vnode *dvp = ap->a_dvp;
1003: struct componentname *cnp = ap->a_cnp;
1004: struct inode *ip, *dp;
1005: int error;
1006:
1007: ip = VTOI(vp);
1008: dp = VTOI(dvp);
1009: /*
1010: * No rmdir "." please.
1011: */
1012: if (dp == ip) {
1013: vrele(dvp);
1014: vput(vp);
1015: return (EINVAL);
1016: }
1017: /*
1018: * Verify the directory is empty (and valid).
1019: * (Rmdir ".." won't be valid since
1020: * ".." will contain a reference to
1021: * the current directory and thus be
1022: * non-empty.)
1023: */
1024: error = 0;
1025: if (ip->i_e2fs_nlink != 2 ||
1026: !ext2fs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
1027: error = ENOTEMPTY;
1028: goto out;
1029: }
1030: if ((dp->i_e2fs_flags & EXT2_APPEND) ||
1031: (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND))) {
1032: error = EPERM;
1033: goto out;
1034: }
1035: /*
1036: * Delete reference to directory before purging
1037: * inode. If we crash in between, the directory
1038: * will be reattached to lost+found,
1039: */
1040: error = ext2fs_dirremove(dvp, cnp);
1041: if (error != 0)
1042: goto out;
1043: dp->i_e2fs_nlink--;
1044: dp->i_flag |= IN_CHANGE;
1045: cache_purge(dvp);
1046: vput(dvp);
1047: dvp = NULL;
1048: /*
1049: * Truncate inode. The only stuff left
1050: * in the directory is "." and "..". The
1051: * "." reference is inconsequential since
1052: * we're quashing it. The ".." reference
1053: * has already been adjusted above. We've
1054: * removed the "." reference and the reference
1055: * in the parent directory, but there may be
1056: * other hard links so decrement by 2 and
1057: * worry about them later.
1058: */
1059: ip->i_e2fs_nlink -= 2;
1060: error = ext2fs_truncate(ip, (off_t)0, IO_SYNC, cnp->cn_cred);
1061: cache_purge(ITOV(ip));
1062: out:
1063: if (dvp)
1064: vput(dvp);
1065: vput(vp);
1066: return (error);
1067: }
1068:
1069: /*
1070: * symlink -- make a symbolic link
1071: */
1072: int
1073: ext2fs_symlink(void *v)
1074: {
1075: struct vop_symlink_args *ap = v;
1076: struct vnode *vp, **vpp = ap->a_vpp;
1077: struct inode *ip;
1078: int len, error;
1079:
1080: error = ext2fs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
1081: vpp, ap->a_cnp);
1082: if (error)
1083: return (error);
1084: vp = *vpp;
1085: len = strlen(ap->a_target);
1086: if (len < vp->v_mount->mnt_maxsymlinklen) {
1087: ip = VTOI(vp);
1088: bcopy(ap->a_target, (char *)ip->i_e2din->e2di_shortlink, len);
1089: error = ext2fs_setsize(ip, len);
1090: if (error)
1091: goto bad;
1092: ip->i_flag |= IN_CHANGE | IN_UPDATE;
1093: } else
1094: error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
1095: UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, NULL,
1096: (struct proc *)0);
1097: bad:
1098: vput(vp);
1099: return (error);
1100: }
1101:
1102: /*
1103: * Return target name of a symbolic link
1104: */
1105: int
1106: ext2fs_readlink(void *v)
1107: {
1108: struct vop_readlink_args *ap = v;
1109: struct vnode *vp = ap->a_vp;
1110: struct inode *ip = VTOI(vp);
1111: int isize;
1112:
1113: isize = ext2fs_size(ip);
1114: if (isize < vp->v_mount->mnt_maxsymlinklen ||
1115: (vp->v_mount->mnt_maxsymlinklen == 0 && ip->i_e2fs_nblock == 0)) {
1116: uiomove((char *)ip->i_e2din->e2di_shortlink, isize, ap->a_uio);
1117: return (0);
1118: }
1119: return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
1120: }
1121:
1122: /*
1123: * Advisory record locking support
1124: */
1125: int
1126: ext2fs_advlock(void *v)
1127: {
1128: struct vop_advlock_args *ap = v;
1129: struct inode *ip = VTOI(ap->a_vp);
1130:
1131: return (lf_advlock(&ip->i_lockf, ext2fs_size(ip), ap->a_id, ap->a_op,
1132: ap->a_fl, ap->a_flags));
1133: }
1134:
1135: /*
1136: * Allocate a new inode.
1137: */
1138: int
1139: ext2fs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
1140: struct componentname *cnp)
1141: {
1142: struct inode *ip, *pdir;
1143: struct vnode *tvp;
1144: int error;
1145:
1146: pdir = VTOI(dvp);
1147: #ifdef DIAGNOSTIC
1148: if ((cnp->cn_flags & HASBUF) == 0)
1149: panic("ext2fs_makeinode: no name");
1150: #endif
1151: *vpp = NULL;
1152: if ((mode & IFMT) == 0)
1153: mode |= IFREG;
1154:
1155: if ((error = ext2fs_inode_alloc(pdir, mode, cnp->cn_cred, &tvp))
1156: != 0) {
1157: pool_put(&namei_pool, cnp->cn_pnbuf);
1158: vput(dvp);
1159: return (error);
1160: }
1161: ip = VTOI(tvp);
1162: ip->i_e2fs_gid = pdir->i_e2fs_gid;
1163: ip->i_e2fs_uid = cnp->cn_cred->cr_uid;
1164: ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1165: ip->i_e2fs_mode = mode;
1166: tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */
1167: ip->i_e2fs_nlink = 1;
1168: if ((ip->i_e2fs_mode & ISGID) &&
1169: !groupmember(ip->i_e2fs_gid, cnp->cn_cred) &&
1170: suser_ucred(cnp->cn_cred))
1171: ip->i_e2fs_mode &= ~ISGID;
1172:
1173: /*
1174: * Make sure inode goes to disk before directory entry.
1175: */
1176: if ((error = ext2fs_update(ip, NULL, NULL, 1)) != 0)
1177: goto bad;
1178: error = ext2fs_direnter(ip, dvp, cnp);
1179: if (error != 0)
1180: goto bad;
1181: if ((cnp->cn_flags & SAVESTART) == 0)
1182: pool_put(&namei_pool, cnp->cn_pnbuf);
1183: vput(dvp);
1184: *vpp = tvp;
1185: return (0);
1186:
1187: bad:
1188: /*
1189: * Write error occurred trying to update the inode
1190: * or the directory so must deallocate the inode.
1191: */
1192: pool_put(&namei_pool, cnp->cn_pnbuf);
1193: vput(dvp);
1194: ip->i_e2fs_nlink = 0;
1195: ip->i_flag |= IN_CHANGE;
1196: tvp->v_type = VNON;
1197: vput(tvp);
1198: return (error);
1199: }
1200:
1201: /*
1202: * Synch an open file.
1203: */
1204: /* ARGSUSED */
1205: int
1206: ext2fs_fsync(void *v)
1207: {
1208: struct vop_fsync_args *ap = v;
1209: struct vnode *vp = ap->a_vp;
1210:
1211: vflushbuf(vp, ap->a_waitfor == MNT_WAIT);
1212: return (ext2fs_update(VTOI(ap->a_vp), NULL, NULL,
1213: ap->a_waitfor == MNT_WAIT));
1214: }
1215:
1216: /*
1217: * Reclaim an inode so that it can be used for other purposes.
1218: */
1219: int
1220: ext2fs_reclaim(void *v)
1221: {
1222: struct vop_reclaim_args *ap = v;
1223: struct vnode *vp = ap->a_vp;
1224: struct inode *ip;
1225: #ifdef DIAGNOSTIC
1226: extern int prtactive;
1227:
1228: if (prtactive && vp->v_usecount != 0)
1229: vprint("ext2fs_reclaim: pushing active", vp);
1230: #endif
1231:
1232: /*
1233: * Remove the inode from its hash chain.
1234: */
1235: ip = VTOI(vp);
1236: ufs_ihashrem(ip);
1237:
1238: /*
1239: * Purge old data structures associated with the inode.
1240: */
1241: cache_purge(vp);
1242: if (ip->i_devvp)
1243: vrele(ip->i_devvp);
1244:
1245: if (ip->i_e2din != NULL)
1246: pool_put(&ext2fs_dinode_pool, ip->i_e2din);
1247:
1248: pool_put(&ext2fs_inode_pool, ip);
1249:
1250: vp->v_data = NULL;
1251:
1252: return (0);
1253: }
1254:
1255: /* Global vfs data structures for ext2fs. */
1256: int (**ext2fs_vnodeop_p)(void *);
1257: struct vnodeopv_entry_desc ext2fs_vnodeop_entries[] = {
1258: { &vop_default_desc, vn_default_error },
1259: { &vop_lookup_desc, ext2fs_lookup }, /* lookup */
1260: { &vop_create_desc, ext2fs_create }, /* create */
1261: { &vop_mknod_desc, ext2fs_mknod }, /* mknod */
1262: { &vop_open_desc, ext2fs_open }, /* open */
1263: { &vop_close_desc, ufs_close }, /* close */
1264: { &vop_access_desc, ext2fs_access }, /* access */
1265: { &vop_getattr_desc, ext2fs_getattr }, /* getattr */
1266: { &vop_setattr_desc, ext2fs_setattr }, /* setattr */
1267: { &vop_read_desc, ext2fs_read }, /* read */
1268: { &vop_write_desc, ext2fs_write }, /* write */
1269: { &vop_ioctl_desc, ufs_ioctl }, /* ioctl */
1270: { &vop_poll_desc, ufs_poll }, /* poll */
1271: { &vop_kqfilter_desc, vop_generic_kqfilter }, /* kqfilter */
1272: { &vop_fsync_desc, ext2fs_fsync }, /* fsync */
1273: { &vop_remove_desc, ext2fs_remove }, /* remove */
1274: { &vop_link_desc, ext2fs_link }, /* link */
1275: { &vop_rename_desc, ext2fs_rename }, /* rename */
1276: { &vop_mkdir_desc, ext2fs_mkdir }, /* mkdir */
1277: { &vop_rmdir_desc, ext2fs_rmdir }, /* rmdir */
1278: { &vop_symlink_desc, ext2fs_symlink }, /* symlink */
1279: { &vop_readdir_desc, ext2fs_readdir }, /* readdir */
1280: { &vop_readlink_desc, ext2fs_readlink },/* readlink */
1281: { &vop_abortop_desc, vop_generic_abortop }, /* abortop */
1282: { &vop_inactive_desc, ext2fs_inactive },/* inactive */
1283: { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */
1284: { &vop_lock_desc, ufs_lock }, /* lock */
1285: { &vop_unlock_desc, ufs_unlock }, /* unlock */
1286: { &vop_bmap_desc, ext2fs_bmap }, /* bmap */
1287: { &vop_strategy_desc, ufs_strategy }, /* strategy */
1288: { &vop_print_desc, ufs_print }, /* print */
1289: { &vop_islocked_desc, ufs_islocked }, /* islocked */
1290: { &vop_pathconf_desc, ufs_pathconf }, /* pathconf */
1291: { &vop_advlock_desc, ext2fs_advlock }, /* advlock */
1292: { &vop_bwrite_desc, vop_generic_bwrite }, /* bwrite */
1293: { NULL, NULL }
1294: };
1295: struct vnodeopv_desc ext2fs_vnodeop_opv_desc =
1296: { &ext2fs_vnodeop_p, ext2fs_vnodeop_entries };
1297:
1298: int (**ext2fs_specop_p)(void *);
1299: struct vnodeopv_entry_desc ext2fs_specop_entries[] = {
1300: { &vop_default_desc, spec_vnoperate },
1301: { &vop_close_desc, ufsspec_close }, /* close */
1302: { &vop_access_desc, ext2fs_access }, /* access */
1303: { &vop_getattr_desc, ext2fs_getattr }, /* getattr */
1304: { &vop_setattr_desc, ext2fs_setattr }, /* setattr */
1305: { &vop_read_desc, ufsspec_read }, /* read */
1306: { &vop_write_desc, ufsspec_write }, /* write */
1307: { &vop_fsync_desc, ext2fs_fsync }, /* fsync */
1308: { &vop_inactive_desc, ext2fs_inactive },/* inactive */
1309: { &vop_reclaim_desc, ext2fs_reclaim }, /* reclaim */
1310: { &vop_lock_desc, ufs_lock }, /* lock */
1311: { &vop_unlock_desc, ufs_unlock }, /* unlock */
1312: { &vop_print_desc, ufs_print }, /* print */
1313: { &vop_islocked_desc, ufs_islocked }, /* islocked */
1314: { NULL, NULL }
1315: };
1316: struct vnodeopv_desc ext2fs_specop_opv_desc =
1317: { &ext2fs_specop_p, ext2fs_specop_entries };
1318:
1319: #ifdef FIFO
1320: int (**ext2fs_fifoop_p)(void *);
1321: struct vnodeopv_entry_desc ext2fs_fifoop_entries[] = {
1322: { &vop_default_desc, fifo_vnoperate },
1323: { &vop_close_desc, ufsfifo_close }, /* close */
1324: { &vop_access_desc, ext2fs_access }, /* access */
1325: { &vop_getattr_desc, ext2fs_getattr }, /* getattr */
1326: { &vop_setattr_desc, ext2fs_setattr }, /* setattr */
1327: { &vop_read_desc, ufsfifo_read }, /* read */
1328: { &vop_write_desc, ufsfifo_write }, /* write */
1329: { &vop_fsync_desc, ext2fs_fsync }, /* fsync */
1330: { &vop_inactive_desc, ext2fs_inactive },/* inactive */
1331: { &vop_reclaim_desc, ext2fsfifo_reclaim }, /* reclaim */
1332: { &vop_lock_desc, ufs_lock }, /* lock */
1333: { &vop_unlock_desc, ufs_unlock }, /* unlock */
1334: { &vop_print_desc, ufs_print }, /* print */
1335: { &vop_islocked_desc, ufs_islocked }, /* islocked */
1336: { &vop_bwrite_desc, vop_generic_bwrite }, /* bwrite */
1337: { NULL, NULL }
1338: };
1339: struct vnodeopv_desc ext2fs_fifoop_opv_desc =
1340: { &ext2fs_fifoop_p, ext2fs_fifoop_entries };
1341:
1342: int
1343: ext2fsfifo_reclaim(void *v)
1344: {
1345: fifo_reclaim(v);
1346: return (ext2fs_reclaim(v));
1347: }
1348: #endif /* FIFO */
CVSweb