|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution is only permitted until one year after the first shipment
6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
7: * binary forms are permitted provided that: (1) source distributions retain
8: * this entire copyright notice and comment, and (2) distributions including
9: * binaries display the following acknowledgement: This product includes
10: * software developed by the University of California, Berkeley and its
11: * contributors'' in the documentation or other materials provided with the
12: * distribution and in all advertising materials mentioning features or use
13: * of this software. Neither the name of the University nor the names of
14: * its contributors may be used to endorse or promote products derived from
15: * this software without specific prior written permission.
16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19: *
20: * @(#)ufs_vnops.c 7.45 (Berkeley) 6/28/90
21: */
22:
23: #include "param.h"
24: #include "systm.h"
25: #include "user.h"
26: #include "kernel.h"
27: #include "file.h"
28: #include "stat.h"
29: #include "buf.h"
30: #include "proc.h"
31: #include "socket.h"
32: #include "socketvar.h"
33: #include "conf.h"
34: #include "mount.h"
35: #include "vnode.h"
36: #include "specdev.h"
37: #include "../ufs/quota.h"
38: #include "../ufs/inode.h"
39: #include "../ufs/fs.h"
40:
41: /*
42: * Global vfs data structures for ufs
43: */
44:
45: int ufs_lookup(),
46: ufs_create(),
47: ufs_mknod(),
48: ufs_open(),
49: ufs_close(),
50: ufs_access(),
51: ufs_getattr(),
52: ufs_setattr(),
53: ufs_read(),
54: ufs_write(),
55: ufs_ioctl(),
56: ufs_select(),
57: ufs_mmap(),
58: ufs_fsync(),
59: ufs_seek(),
60: ufs_remove(),
61: ufs_link(),
62: ufs_rename(),
63: ufs_mkdir(),
64: ufs_rmdir(),
65: ufs_symlink(),
66: ufs_readdir(),
67: ufs_readlink(),
68: ufs_abortop(),
69: ufs_inactive(),
70: ufs_reclaim(),
71: ufs_lock(),
72: ufs_unlock(),
73: ufs_bmap(),
74: ufs_strategy(),
75: ufs_print(),
76: ufs_islocked();
77:
78: struct vnodeops ufs_vnodeops = {
79: ufs_lookup, /* lookup */
80: ufs_create, /* create */
81: ufs_mknod, /* mknod */
82: ufs_open, /* open */
83: ufs_close, /* close */
84: ufs_access, /* access */
85: ufs_getattr, /* getattr */
86: ufs_setattr, /* setattr */
87: ufs_read, /* read */
88: ufs_write, /* write */
89: ufs_ioctl, /* ioctl */
90: ufs_select, /* select */
91: ufs_mmap, /* mmap */
92: ufs_fsync, /* fsync */
93: ufs_seek, /* seek */
94: ufs_remove, /* remove */
95: ufs_link, /* link */
96: ufs_rename, /* rename */
97: ufs_mkdir, /* mkdir */
98: ufs_rmdir, /* rmdir */
99: ufs_symlink, /* symlink */
100: ufs_readdir, /* readdir */
101: ufs_readlink, /* readlink */
102: ufs_abortop, /* abortop */
103: ufs_inactive, /* inactive */
104: ufs_reclaim, /* reclaim */
105: ufs_lock, /* lock */
106: ufs_unlock, /* unlock */
107: ufs_bmap, /* bmap */
108: ufs_strategy, /* strategy */
109: ufs_print, /* print */
110: ufs_islocked, /* islocked */
111: };
112:
113: int spec_lookup(),
114: spec_open(),
115: ufsspec_read(),
116: ufsspec_write(),
117: spec_strategy(),
118: spec_bmap(),
119: spec_ioctl(),
120: spec_select(),
121: ufsspec_close(),
122: spec_badop(),
123: spec_nullop();
124:
125: struct vnodeops spec_inodeops = {
126: spec_lookup, /* lookup */
127: spec_badop, /* create */
128: spec_badop, /* mknod */
129: spec_open, /* open */
130: ufsspec_close, /* close */
131: ufs_access, /* access */
132: ufs_getattr, /* getattr */
133: ufs_setattr, /* setattr */
134: ufsspec_read, /* read */
135: ufsspec_write, /* write */
136: spec_ioctl, /* ioctl */
137: spec_select, /* select */
138: spec_badop, /* mmap */
139: spec_nullop, /* fsync */
140: spec_badop, /* seek */
141: spec_badop, /* remove */
142: spec_badop, /* link */
143: spec_badop, /* rename */
144: spec_badop, /* mkdir */
145: spec_badop, /* rmdir */
146: spec_badop, /* symlink */
147: spec_badop, /* readdir */
148: spec_badop, /* readlink */
149: spec_badop, /* abortop */
150: ufs_inactive, /* inactive */
151: ufs_reclaim, /* reclaim */
152: ufs_lock, /* lock */
153: ufs_unlock, /* unlock */
154: spec_bmap, /* bmap */
155: spec_strategy, /* strategy */
156: ufs_print, /* print */
157: ufs_islocked, /* islocked */
158: };
159:
160: #ifdef FIFO
161: int fifo_lookup(),
162: fifo_open(),
163: ufsfifo_read(),
164: ufsfifo_write(),
165: fifo_bmap(),
166: fifo_ioctl(),
167: fifo_select(),
168: ufsfifo_close(),
169: fifo_print(),
170: fifo_badop(),
171: fifo_nullop();
172:
173: struct vnodeops fifo_inodeops = {
174: fifo_lookup, /* lookup */
175: fifo_badop, /* create */
176: fifo_badop, /* mknod */
177: fifo_open, /* open */
178: ufsfifo_close, /* close */
179: ufs_access, /* access */
180: ufs_getattr, /* getattr */
181: ufs_setattr, /* setattr */
182: ufsfifo_read, /* read */
183: ufsfifo_write, /* write */
184: fifo_ioctl, /* ioctl */
185: fifo_select, /* select */
186: fifo_badop, /* mmap */
187: fifo_nullop, /* fsync */
188: fifo_badop, /* seek */
189: fifo_badop, /* remove */
190: fifo_badop, /* link */
191: fifo_badop, /* rename */
192: fifo_badop, /* mkdir */
193: fifo_badop, /* rmdir */
194: fifo_badop, /* symlink */
195: fifo_badop, /* readdir */
196: fifo_badop, /* readlink */
197: fifo_badop, /* abortop */
198: ufs_inactive, /* inactive */
199: ufs_reclaim, /* reclaim */
200: ufs_lock, /* lock */
201: ufs_unlock, /* unlock */
202: fifo_bmap, /* bmap */
203: fifo_badop, /* strategy */
204: ufs_print, /* print */
205: ufs_islocked, /* islocked */
206: };
207: #endif /* FIFO */
208:
209: enum vtype iftovt_tab[16] = {
210: VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
211: VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD,
212: };
213: int vttoif_tab[9] = {
214: 0, IFREG, IFDIR, IFBLK, IFCHR, IFLNK, IFSOCK, IFIFO, IFMT,
215: };
216:
217: /*
218: * Create a regular file
219: */
220: ufs_create(ndp, vap)
221: struct nameidata *ndp;
222: struct vattr *vap;
223: {
224: struct inode *ip;
225: int error;
226:
227: if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip))
228: return (error);
229: ndp->ni_vp = ITOV(ip);
230: return (0);
231: }
232:
233: /*
234: * Mknod vnode call
235: */
236: /* ARGSUSED */
237: ufs_mknod(ndp, vap, cred)
238: struct nameidata *ndp;
239: struct ucred *cred;
240: struct vattr *vap;
241: {
242: register struct vnode *vp;
243: struct inode *ip;
244: int error;
245:
246: if (error = maknode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &ip))
247: return (error);
248: ip->i_flag |= IACC|IUPD|ICHG;
249: if (vap->va_rdev != VNOVAL) {
250: /*
251: * Want to be able to use this to make badblock
252: * inodes, so don't truncate the dev number.
253: */
254: ip->i_rdev = vap->va_rdev;
255: }
256: /*
257: * Remove inode so that it will be reloaded by iget and
258: * checked to see if it is an alias of an existing entry
259: * in the inode cache.
260: */
261: vp = ITOV(ip);
262: vput(vp);
263: vp->v_type = VNON;
264: vgone(vp);
265: return (0);
266: }
267:
268: /*
269: * Open called.
270: *
271: * Nothing to do.
272: */
273: /* ARGSUSED */
274: ufs_open(vp, mode, cred)
275: struct vnode *vp;
276: int mode;
277: struct ucred *cred;
278: {
279:
280: return (0);
281: }
282:
283: /*
284: * Close called
285: *
286: * Update the times on the inode.
287: */
288: /* ARGSUSED */
289: ufs_close(vp, fflag, cred)
290: struct vnode *vp;
291: int fflag;
292: struct ucred *cred;
293: {
294: register struct inode *ip = VTOI(vp);
295:
296: if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED))
297: ITIMES(ip, &time, &time);
298: return (0);
299: }
300:
301: /*
302: * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
303: * The mode is shifted to select the owner/group/other fields. The
304: * super user is granted all permissions.
305: */
306: ufs_access(vp, mode, cred)
307: struct vnode *vp;
308: register int mode;
309: struct ucred *cred;
310: {
311: register struct inode *ip = VTOI(vp);
312: register gid_t *gp;
313: int i, error;
314:
315: #ifdef DIAGNOSTIC
316: if (!VOP_ISLOCKED(vp)) {
317: vprint("ufs_access: not locked", vp);
318: panic("ufs_access: not locked");
319: }
320: #endif
321: #ifdef QUOTA
322: if (mode & VWRITE) {
323: switch (vp->v_type) {
324: case VREG: case VDIR: case VLNK:
325: if (error = getinoquota(ip))
326: return (error);
327: }
328: }
329: #endif /* QUOTA */
330: /*
331: * If you're the super-user, you always get access.
332: */
333: if (cred->cr_uid == 0)
334: return (0);
335: /*
336: * Access check is based on only one of owner, group, public.
337: * If not owner, then check group. If not a member of the
338: * group, then check public access.
339: */
340: if (cred->cr_uid != ip->i_uid) {
341: mode >>= 3;
342: gp = cred->cr_groups;
343: for (i = 0; i < cred->cr_ngroups; i++, gp++)
344: if (ip->i_gid == *gp)
345: goto found;
346: mode >>= 3;
347: found:
348: ;
349: }
350: if ((ip->i_mode & mode) != 0)
351: return (0);
352: return (EACCES);
353: }
354:
355: /* ARGSUSED */
356: ufs_getattr(vp, vap, cred)
357: struct vnode *vp;
358: register struct vattr *vap;
359: struct ucred *cred;
360: {
361: register struct inode *ip = VTOI(vp);
362:
363: ITIMES(ip, &time, &time);
364: /*
365: * Copy from inode table
366: */
367: vap->va_fsid = ip->i_dev;
368: vap->va_fileid = ip->i_number;
369: vap->va_mode = ip->i_mode & ~IFMT;
370: vap->va_nlink = ip->i_nlink;
371: vap->va_uid = ip->i_uid;
372: vap->va_gid = ip->i_gid;
373: vap->va_rdev = (dev_t)ip->i_rdev;
374: #ifdef tahoe
375: vap->va_size = ip->i_size;
376: vap->va_size_rsv = 0;
377: #else
378: vap->va_qsize = ip->i_din.di_qsize;
379: #endif
380: vap->va_atime.tv_sec = ip->i_atime;
381: vap->va_atime.tv_usec = 0;
382: vap->va_mtime.tv_sec = ip->i_mtime;
383: vap->va_mtime.tv_usec = 0;
384: vap->va_ctime.tv_sec = ip->i_ctime;
385: vap->va_ctime.tv_usec = 0;
386: vap->va_flags = ip->i_flags;
387: vap->va_gen = ip->i_gen;
388: /* this doesn't belong here */
389: if (vp->v_type == VBLK)
390: vap->va_blocksize = BLKDEV_IOSIZE;
391: else if (vp->v_type == VCHR)
392: vap->va_blocksize = MAXBSIZE;
393: else
394: vap->va_blocksize = ip->i_fs->fs_bsize;
395: vap->va_bytes = dbtob(ip->i_blocks);
396: vap->va_bytes_rsv = 0;
397: vap->va_type = vp->v_type;
398: return (0);
399: }
400:
401: /*
402: * Set attribute vnode op. called from several syscalls
403: */
404: ufs_setattr(vp, vap, cred)
405: register struct vnode *vp;
406: register struct vattr *vap;
407: register struct ucred *cred;
408: {
409: register struct inode *ip = VTOI(vp);
410: int error = 0;
411:
412: /*
413: * Check for unsetable attributes.
414: */
415: if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
416: (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
417: (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
418: ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
419: return (EINVAL);
420: }
421: /*
422: * Go through the fields and update iff not VNOVAL.
423: */
424: if (vap->va_uid != (u_short)VNOVAL || vap->va_gid != (u_short)VNOVAL)
425: if (error = chown1(vp, vap->va_uid, vap->va_gid, cred))
426: return (error);
427: if (vap->va_size != VNOVAL) {
428: if (vp->v_type == VDIR)
429: return (EISDIR);
430: if (error = itrunc(ip, vap->va_size, 0)) /* XXX IO_SYNC? */
431: return (error);
432: }
433: if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
434: if (cred->cr_uid != ip->i_uid &&
435: (error = suser(cred, &u.u_acflag)))
436: return (error);
437: if (vap->va_atime.tv_sec != VNOVAL)
438: ip->i_flag |= IACC;
439: if (vap->va_mtime.tv_sec != VNOVAL)
440: ip->i_flag |= IUPD;
441: ip->i_flag |= ICHG;
442: if (error = iupdat(ip, &vap->va_atime, &vap->va_mtime, 1))
443: return (error);
444: }
445: if (vap->va_mode != (u_short)VNOVAL)
446: error = chmod1(vp, (int)vap->va_mode, cred);
447: if (vap->va_flags != VNOVAL) {
448: if (cred->cr_uid != ip->i_uid &&
449: (error = suser(cred, &u.u_acflag)))
450: return (error);
451: if (cred->cr_uid == 0) {
452: ip->i_flags = vap->va_flags;
453: } else {
454: ip->i_flags &= 0xffff0000;
455: ip->i_flags |= (vap->va_flags & 0xffff);
456: }
457: ip->i_flag |= ICHG;
458: }
459: return (error);
460: }
461:
462: /*
463: * Change the mode on a file.
464: * Inode must be locked before calling.
465: */
466: chmod1(vp, mode, cred)
467: register struct vnode *vp;
468: register int mode;
469: struct ucred *cred;
470: {
471: register struct inode *ip = VTOI(vp);
472: int error;
473:
474: if (cred->cr_uid != ip->i_uid &&
475: (error = suser(cred, &u.u_acflag)))
476: return (error);
477: ip->i_mode &= ~07777;
478: if (cred->cr_uid) {
479: if (vp->v_type != VDIR)
480: mode &= ~ISVTX;
481: if (!groupmember(ip->i_gid, cred))
482: mode &= ~ISGID;
483: }
484: ip->i_mode |= mode & 07777;
485: ip->i_flag |= ICHG;
486: if ((vp->v_flag & VTEXT) && (ip->i_mode & ISVTX) == 0)
487: xrele(vp);
488: return (0);
489: }
490:
491: /*
492: * Perform chown operation on inode ip;
493: * inode must be locked prior to call.
494: */
495: chown1(vp, uid, gid, cred)
496: register struct vnode *vp;
497: uid_t uid;
498: gid_t gid;
499: struct ucred *cred;
500: {
501: register struct inode *ip = VTOI(vp);
502: uid_t ouid;
503: gid_t ogid;
504: int error = 0;
505: #ifdef QUOTA
506: register int i;
507: long change;
508: #endif
509:
510: if (uid == (u_short)VNOVAL)
511: uid = ip->i_uid;
512: if (gid == (u_short)VNOVAL)
513: gid = ip->i_gid;
514: /*
515: * If we don't own the file, are trying to change the owner
516: * of the file, or are not a member of the target group,
517: * the caller must be superuser or the call fails.
518: */
519: if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid ||
520: !groupmember((gid_t)gid, cred)) &&
521: (error = suser(cred, &u.u_acflag)))
522: return (error);
523: ouid = ip->i_uid;
524: ogid = ip->i_gid;
525: #ifdef QUOTA
526: if (error = getinoquota(ip))
527: return (error);
528: if (ouid == uid) {
529: dqrele(vp, ip->i_dquot[USRQUOTA]);
530: ip->i_dquot[USRQUOTA] = NODQUOT;
531: }
532: if (ogid == gid) {
533: dqrele(vp, ip->i_dquot[GRPQUOTA]);
534: ip->i_dquot[GRPQUOTA] = NODQUOT;
535: }
536: change = ip->i_blocks;
537: (void) chkdq(ip, -change, cred, CHOWN);
538: (void) chkiq(ip, -1, cred, CHOWN);
539: for (i = 0; i < MAXQUOTAS; i++) {
540: dqrele(vp, ip->i_dquot[i]);
541: ip->i_dquot[i] = NODQUOT;
542: }
543: #endif
544: ip->i_uid = uid;
545: ip->i_gid = gid;
546: #ifdef QUOTA
547: if ((error = getinoquota(ip)) == 0) {
548: if (ouid == uid) {
549: dqrele(vp, ip->i_dquot[USRQUOTA]);
550: ip->i_dquot[USRQUOTA] = NODQUOT;
551: }
552: if (ogid == gid) {
553: dqrele(vp, ip->i_dquot[GRPQUOTA]);
554: ip->i_dquot[GRPQUOTA] = NODQUOT;
555: }
556: if ((error = chkdq(ip, change, cred, CHOWN)) == 0) {
557: if ((error = chkiq(ip, 1, cred, CHOWN)) == 0)
558: goto good;
559: else
560: (void) chkdq(ip, -change, cred, CHOWN|FORCE);
561: }
562: for (i = 0; i < MAXQUOTAS; i++) {
563: dqrele(vp, ip->i_dquot[i]);
564: ip->i_dquot[i] = NODQUOT;
565: }
566: }
567: ip->i_uid = ouid;
568: ip->i_gid = ogid;
569: if (getinoquota(ip) == 0) {
570: if (ouid == uid) {
571: dqrele(vp, ip->i_dquot[USRQUOTA]);
572: ip->i_dquot[USRQUOTA] = NODQUOT;
573: }
574: if (ogid == gid) {
575: dqrele(vp, ip->i_dquot[GRPQUOTA]);
576: ip->i_dquot[GRPQUOTA] = NODQUOT;
577: }
578: (void) chkdq(ip, change, cred, FORCE|CHOWN);
579: (void) chkiq(ip, 1, cred, FORCE|CHOWN);
580: (void) getinoquota(ip);
581: }
582: return (error);
583: good:
584: if (getinoquota(ip))
585: panic("chown: lost quota");
586: #endif /* QUOTA */
587: if (ouid != uid || ogid != gid)
588: ip->i_flag |= ICHG;
589: if (ouid != uid && cred->cr_uid != 0)
590: ip->i_mode &= ~ISUID;
591: if (ogid != gid && cred->cr_uid != 0)
592: ip->i_mode &= ~ISGID;
593: return (0);
594: }
595:
596: /*
597: * Vnode op for reading.
598: */
599: /* ARGSUSED */
600: ufs_read(vp, uio, ioflag, cred)
601: struct vnode *vp;
602: register struct uio *uio;
603: int ioflag;
604: struct ucred *cred;
605: {
606: register struct inode *ip = VTOI(vp);
607: register struct fs *fs;
608: struct buf *bp;
609: daddr_t lbn, bn, rablock;
610: int size, diff, error = 0;
611: long n, on, type;
612:
613: if (uio->uio_rw != UIO_READ)
614: panic("ufs_read mode");
615: type = ip->i_mode & IFMT;
616: if (type != IFDIR && type != IFREG && type != IFLNK)
617: panic("ufs_read type");
618: if (uio->uio_resid == 0)
619: return (0);
620: if (uio->uio_offset < 0)
621: return (EINVAL);
622: ip->i_flag |= IACC;
623: fs = ip->i_fs;
624: do {
625: lbn = lblkno(fs, uio->uio_offset);
626: on = blkoff(fs, uio->uio_offset);
627: n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid);
628: diff = ip->i_size - uio->uio_offset;
629: if (diff <= 0)
630: return (0);
631: if (diff < n)
632: n = diff;
633: size = blksize(fs, ip, lbn);
634: rablock = lbn + 1;
635: if (vp->v_lastr + 1 == lbn &&
636: lblktosize(fs, rablock) < ip->i_size)
637: error = breada(ITOV(ip), lbn, size, rablock,
638: blksize(fs, ip, rablock), NOCRED, &bp);
639: else
640: error = bread(ITOV(ip), lbn, size, NOCRED, &bp);
641: vp->v_lastr = lbn;
642: n = MIN(n, size - bp->b_resid);
643: if (error) {
644: brelse(bp);
645: return (error);
646: }
647: error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
648: if (n + on == fs->fs_bsize || uio->uio_offset == ip->i_size)
649: bp->b_flags |= B_AGE;
650: brelse(bp);
651: } while (error == 0 && uio->uio_resid > 0 && n != 0);
652: return (error);
653: }
654:
655: /*
656: * Vnode op for writing.
657: */
658: ufs_write(vp, uio, ioflag, cred)
659: register struct vnode *vp;
660: struct uio *uio;
661: int ioflag;
662: struct ucred *cred;
663: {
664: register struct inode *ip = VTOI(vp);
665: register struct fs *fs;
666: struct buf *bp;
667: daddr_t lbn, bn;
668: u_long osize;
669: int i, n, on, flags;
670: int count, size, resid, error = 0;
671:
672: if (uio->uio_rw != UIO_WRITE)
673: panic("ufs_write mode");
674: switch (vp->v_type) {
675: case VREG:
676: if (ioflag & IO_APPEND)
677: uio->uio_offset = ip->i_size;
678: /* fall through */
679: case VLNK:
680: break;
681:
682: case VDIR:
683: if ((ioflag & IO_SYNC) == 0)
684: panic("ufs_write nonsync dir write");
685: break;
686:
687: default:
688: panic("ufs_write type");
689: }
690: if (uio->uio_offset < 0)
691: return (EINVAL);
692: if (uio->uio_resid == 0)
693: return (0);
694: /*
695: * Maybe this should be above the vnode op call, but so long as
696: * file servers have no limits, i don't think it matters
697: */
698: if (vp->v_type == VREG &&
699: uio->uio_offset + uio->uio_resid >
700: u.u_rlimit[RLIMIT_FSIZE].rlim_cur) {
701: psignal(u.u_procp, SIGXFSZ);
702: return (EFBIG);
703: }
704: resid = uio->uio_resid;
705: osize = ip->i_size;
706: fs = ip->i_fs;
707: flags = 0;
708: if (ioflag & IO_SYNC)
709: flags = B_SYNC;
710: do {
711: lbn = lblkno(fs, uio->uio_offset);
712: on = blkoff(fs, uio->uio_offset);
713: n = MIN((unsigned)(fs->fs_bsize - on), uio->uio_resid);
714: if (n < fs->fs_bsize)
715: flags |= B_CLRBUF;
716: else
717: flags &= ~B_CLRBUF;
718: if (error = balloc(ip, lbn, (int)(on + n), &bp, flags))
719: break;
720: bn = bp->b_blkno;
721: if (uio->uio_offset + n > ip->i_size)
722: ip->i_size = uio->uio_offset + n;
723: size = blksize(fs, ip, lbn);
724: count = howmany(size, CLBYTES);
725: for (i = 0; i < count; i++)
726: munhash(ip->i_devvp, bn + i * CLBYTES / DEV_BSIZE);
727: n = MIN(n, size - bp->b_resid);
728: error = uiomove(bp->b_un.b_addr + on, n, uio);
729: if (ioflag & IO_SYNC)
730: (void) bwrite(bp);
731: else if (n + on == fs->fs_bsize) {
732: bp->b_flags |= B_AGE;
733: bawrite(bp);
734: } else
735: bdwrite(bp);
736: ip->i_flag |= IUPD|ICHG;
737: if (cred->cr_uid != 0)
738: ip->i_mode &= ~(ISUID|ISGID);
739: } while (error == 0 && uio->uio_resid > 0 && n != 0);
740: if (error && (ioflag & IO_UNIT)) {
741: (void) itrunc(ip, osize, ioflag & IO_SYNC);
742: uio->uio_offset -= resid - uio->uio_resid;
743: uio->uio_resid = resid;
744: }
745: if (!error && (ioflag & IO_SYNC))
746: error = iupdat(ip, &time, &time, 1);
747: return (error);
748: }
749:
750: /* ARGSUSED */
751: ufs_ioctl(vp, com, data, fflag, cred)
752: struct vnode *vp;
753: int com;
754: caddr_t data;
755: int fflag;
756: struct ucred *cred;
757: {
758:
759: return (ENOTTY);
760: }
761:
762: /* ARGSUSED */
763: ufs_select(vp, which, fflags, cred)
764: struct vnode *vp;
765: int which, fflags;
766: struct ucred *cred;
767: {
768:
769: return (1); /* XXX */
770: }
771:
772: /*
773: * Mmap a file
774: *
775: * NB Currently unsupported.
776: */
777: /* ARGSUSED */
778: ufs_mmap(vp, fflags, cred)
779: struct vnode *vp;
780: int fflags;
781: struct ucred *cred;
782: {
783:
784: return (EINVAL);
785: }
786:
787: /*
788: * Synch an open file.
789: */
790: /* ARGSUSED */
791: ufs_fsync(vp, fflags, cred, waitfor)
792: struct vnode *vp;
793: int fflags;
794: struct ucred *cred;
795: int waitfor;
796: {
797: struct inode *ip = VTOI(vp);
798:
799: if (fflags&FWRITE)
800: ip->i_flag |= ICHG;
801: vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0);
802: return (iupdat(ip, &time, &time, waitfor == MNT_WAIT));
803: }
804:
805: /*
806: * Seek on a file
807: *
808: * Nothing to do, so just return.
809: */
810: /* ARGSUSED */
811: ufs_seek(vp, oldoff, newoff, cred)
812: struct vnode *vp;
813: off_t oldoff, newoff;
814: struct ucred *cred;
815: {
816:
817: return (0);
818: }
819:
820: /*
821: * ufs remove
822: * Hard to avoid races here, especially
823: * in unlinking directories.
824: */
825: ufs_remove(ndp)
826: struct nameidata *ndp;
827: {
828: register struct inode *ip, *dp;
829: int error;
830:
831: ip = VTOI(ndp->ni_vp);
832: dp = VTOI(ndp->ni_dvp);
833: error = dirremove(ndp);
834: if (!error) {
835: ip->i_nlink--;
836: ip->i_flag |= ICHG;
837: }
838: if (dp == ip)
839: vrele(ITOV(ip));
840: else
841: iput(ip);
842: iput(dp);
843: return (error);
844: }
845:
846: /*
847: * link vnode call
848: */
849: ufs_link(vp, ndp)
850: register struct vnode *vp;
851: register struct nameidata *ndp;
852: {
853: register struct inode *ip = VTOI(vp);
854: int error;
855:
856: if (ndp->ni_dvp != vp)
857: ILOCK(ip);
858: if (ip->i_nlink == LINK_MAX - 1) {
859: error = EMLINK;
860: goto out;
861: }
862: ip->i_nlink++;
863: ip->i_flag |= ICHG;
864: error = iupdat(ip, &time, &time, 1);
865: if (!error)
866: error = direnter(ip, ndp);
867: out:
868: if (ndp->ni_dvp != vp)
869: IUNLOCK(ip);
870: if (error) {
871: ip->i_nlink--;
872: ip->i_flag |= ICHG;
873: }
874: return (error);
875: }
876:
877: /*
878: * Rename system call.
879: * rename("foo", "bar");
880: * is essentially
881: * unlink("bar");
882: * link("foo", "bar");
883: * unlink("foo");
884: * but ``atomically''. Can't do full commit without saving state in the
885: * inode on disk which isn't feasible at this time. Best we can do is
886: * always guarantee the target exists.
887: *
888: * Basic algorithm is:
889: *
890: * 1) Bump link count on source while we're linking it to the
891: * target. This also ensure the inode won't be deleted out
892: * from underneath us while we work (it may be truncated by
893: * a concurrent `trunc' or `open' for creation).
894: * 2) Link source to destination. If destination already exists,
895: * delete it first.
896: * 3) Unlink source reference to inode if still around. If a
897: * directory was moved and the parent of the destination
898: * is different from the source, patch the ".." entry in the
899: * directory.
900: */
901: ufs_rename(fndp, tndp)
902: register struct nameidata *fndp, *tndp;
903: {
904: register struct inode *ip, *xp, *dp;
905: struct dirtemplate dirbuf;
906: int doingdirectory = 0, oldparent = 0, newparent = 0;
907: int error = 0;
908:
909: dp = VTOI(fndp->ni_dvp);
910: ip = VTOI(fndp->ni_vp);
911: ILOCK(ip);
912: if ((ip->i_mode&IFMT) == IFDIR) {
913: register struct direct *d = &fndp->ni_dent;
914:
915: /*
916: * Avoid ".", "..", and aliases of "." for obvious reasons.
917: */
918: if ((d->d_namlen == 1 && d->d_name[0] == '.') || dp == ip ||
919: fndp->ni_isdotdot || (ip->i_flag & IRENAME)) {
920: VOP_ABORTOP(tndp);
921: vput(tndp->ni_dvp);
922: if (tndp->ni_vp)
923: vput(tndp->ni_vp);
924: VOP_ABORTOP(fndp);
925: vrele(fndp->ni_dvp);
926: vput(fndp->ni_vp);
927: return (EINVAL);
928: }
929: ip->i_flag |= IRENAME;
930: oldparent = dp->i_number;
931: doingdirectory++;
932: }
933: vrele(fndp->ni_dvp);
934:
935: /*
936: * 1) Bump link count while we're moving stuff
937: * around. If we crash somewhere before
938: * completing our work, the link count
939: * may be wrong, but correctable.
940: */
941: ip->i_nlink++;
942: ip->i_flag |= ICHG;
943: error = iupdat(ip, &time, &time, 1);
944: IUNLOCK(ip);
945:
946: /*
947: * When the target exists, both the directory
948: * and target vnodes are returned locked.
949: */
950: dp = VTOI(tndp->ni_dvp);
951: xp = NULL;
952: if (tndp->ni_vp)
953: xp = VTOI(tndp->ni_vp);
954: /*
955: * If ".." must be changed (ie the directory gets a new
956: * parent) then the source directory must not be in the
957: * directory heirarchy above the target, as this would
958: * orphan everything below the source directory. Also
959: * the user must have write permission in the source so
960: * as to be able to change "..". We must repeat the call
961: * to namei, as the parent directory is unlocked by the
962: * call to checkpath().
963: */
964: if (oldparent != dp->i_number)
965: newparent = dp->i_number;
966: if (doingdirectory && newparent) {
967: VOP_LOCK(fndp->ni_vp);
968: error = ufs_access(fndp->ni_vp, VWRITE, tndp->ni_cred);
969: VOP_UNLOCK(fndp->ni_vp);
970: if (error)
971: goto bad;
972: tndp->ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
973: do {
974: dp = VTOI(tndp->ni_dvp);
975: if (xp != NULL)
976: iput(xp);
977: if (error = checkpath(ip, dp, tndp->ni_cred))
978: goto out;
979: if (error = namei(tndp))
980: goto out;
981: xp = NULL;
982: if (tndp->ni_vp)
983: xp = VTOI(tndp->ni_vp);
984: } while (dp != VTOI(tndp->ni_dvp));
985: }
986: /*
987: * 2) If target doesn't exist, link the target
988: * to the source and unlink the source.
989: * Otherwise, rewrite the target directory
990: * entry to reference the source inode and
991: * expunge the original entry's existence.
992: */
993: if (xp == NULL) {
994: if (dp->i_dev != ip->i_dev)
995: panic("rename: EXDEV");
996: /*
997: * Account for ".." in new directory.
998: * When source and destination have the same
999: * parent we don't fool with the link count.
1000: */
1001: if (doingdirectory && newparent) {
1002: dp->i_nlink++;
1003: dp->i_flag |= ICHG;
1004: error = iupdat(dp, &time, &time, 1);
1005: }
1006: if (error = direnter(ip, tndp))
1007: goto out;
1008: } else {
1009: if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
1010: panic("rename: EXDEV");
1011: /*
1012: * Short circuit rename(foo, foo).
1013: */
1014: if (xp->i_number == ip->i_number)
1015: panic("rename: same file");
1016: /*
1017: * If the parent directory is "sticky", then the user must
1018: * own the parent directory, or the destination of the rename,
1019: * otherwise the destination may not be changed (except by
1020: * root). This implements append-only directories.
1021: */
1022: if ((dp->i_mode & ISVTX) && tndp->ni_cred->cr_uid != 0 &&
1023: tndp->ni_cred->cr_uid != dp->i_uid &&
1024: xp->i_uid != tndp->ni_cred->cr_uid) {
1025: error = EPERM;
1026: goto bad;
1027: }
1028: /*
1029: * Target must be empty if a directory
1030: * and have no links to it.
1031: * Also, insure source and target are
1032: * compatible (both directories, or both
1033: * not directories).
1034: */
1035: if ((xp->i_mode&IFMT) == IFDIR) {
1036: if (!dirempty(xp, dp->i_number, tndp->ni_cred) ||
1037: xp->i_nlink > 2) {
1038: error = ENOTEMPTY;
1039: goto bad;
1040: }
1041: if (!doingdirectory) {
1042: error = ENOTDIR;
1043: goto bad;
1044: }
1045: cache_purge(ITOV(dp));
1046: } else if (doingdirectory) {
1047: error = EISDIR;
1048: goto bad;
1049: }
1050: if (error = dirrewrite(dp, ip, tndp))
1051: goto bad;
1052: vput(ITOV(dp));
1053: /*
1054: * Adjust the link count of the target to
1055: * reflect the dirrewrite above. If this is
1056: * a directory it is empty and there are
1057: * no links to it, so we can squash the inode and
1058: * any space associated with it. We disallowed
1059: * renaming over top of a directory with links to
1060: * it above, as the remaining link would point to
1061: * a directory without "." or ".." entries.
1062: */
1063: xp->i_nlink--;
1064: if (doingdirectory) {
1065: if (--xp->i_nlink != 0)
1066: panic("rename: linked directory");
1067: error = itrunc(xp, (u_long)0, IO_SYNC);
1068: }
1069: xp->i_flag |= ICHG;
1070: iput(xp);
1071: xp = NULL;
1072: }
1073:
1074: /*
1075: * 3) Unlink the source.
1076: */
1077: fndp->ni_nameiop = DELETE | LOCKPARENT | LOCKLEAF;
1078: (void)namei(fndp);
1079: if (fndp->ni_vp != NULL) {
1080: xp = VTOI(fndp->ni_vp);
1081: dp = VTOI(fndp->ni_dvp);
1082: } else {
1083: if (fndp->ni_dvp != NULL)
1084: vput(fndp->ni_dvp);
1085: xp = NULL;
1086: dp = NULL;
1087: }
1088: /*
1089: * Ensure that the directory entry still exists and has not
1090: * changed while the new name has been entered. If the source is
1091: * a file then the entry may have been unlinked or renamed. In
1092: * either case there is no further work to be done. If the source
1093: * is a directory then it cannot have been rmdir'ed; its link
1094: * count of three would cause a rmdir to fail with ENOTEMPTY.
1095: * The IRENAME flag ensures that it cannot be moved by another
1096: * rename.
1097: */
1098: if (xp != ip) {
1099: if (doingdirectory)
1100: panic("rename: lost dir entry");
1101: } else {
1102: /*
1103: * If the source is a directory with a
1104: * new parent, the link count of the old
1105: * parent directory must be decremented
1106: * and ".." set to point to the new parent.
1107: */
1108: if (doingdirectory && newparent) {
1109: dp->i_nlink--;
1110: dp->i_flag |= ICHG;
1111: error = vn_rdwr(UIO_READ, ITOV(xp), (caddr_t)&dirbuf,
1112: sizeof (struct dirtemplate), (off_t)0,
1113: UIO_SYSSPACE, IO_NODELOCKED,
1114: tndp->ni_cred, (int *)0);
1115: if (error == 0) {
1116: if (dirbuf.dotdot_namlen != 2 ||
1117: dirbuf.dotdot_name[0] != '.' ||
1118: dirbuf.dotdot_name[1] != '.') {
1119: dirbad(xp, 12, "rename: mangled dir");
1120: } else {
1121: dirbuf.dotdot_ino = newparent;
1122: (void) vn_rdwr(UIO_WRITE, ITOV(xp),
1123: (caddr_t)&dirbuf,
1124: sizeof (struct dirtemplate),
1125: (off_t)0, UIO_SYSSPACE,
1126: IO_NODELOCKED|IO_SYNC,
1127: tndp->ni_cred, (int *)0);
1128: cache_purge(ITOV(dp));
1129: }
1130: }
1131: }
1132: error = dirremove(fndp);
1133: if (!error) {
1134: xp->i_nlink--;
1135: xp->i_flag |= ICHG;
1136: }
1137: xp->i_flag &= ~IRENAME;
1138: }
1139: if (dp)
1140: vput(ITOV(dp));
1141: if (xp)
1142: vput(ITOV(xp));
1143: vrele(ITOV(ip));
1144: return (error);
1145:
1146: bad:
1147: if (xp)
1148: vput(ITOV(xp));
1149: vput(ITOV(dp));
1150: out:
1151: ip->i_nlink--;
1152: ip->i_flag |= ICHG;
1153: vrele(ITOV(ip));
1154: return (error);
1155: }
1156:
1157: /*
1158: * A virgin directory (no blushing please).
1159: */
1160: struct dirtemplate mastertemplate = {
1161: 0, 12, 1, ".",
1162: 0, DIRBLKSIZ - 12, 2, ".."
1163: };
1164:
1165: /*
1166: * Mkdir system call
1167: */
1168: ufs_mkdir(ndp, vap)
1169: struct nameidata *ndp;
1170: struct vattr *vap;
1171: {
1172: register struct inode *ip, *dp;
1173: struct inode *tip;
1174: struct vnode *dvp;
1175: struct dirtemplate dirtemplate;
1176: int error;
1177: int dmode;
1178:
1179: dvp = ndp->ni_dvp;
1180: dp = VTOI(dvp);
1181: dmode = vap->va_mode&0777;
1182: dmode |= IFDIR;
1183: /*
1184: * Must simulate part of maknode here
1185: * in order to acquire the inode, but
1186: * not have it entered in the parent
1187: * directory. The entry is made later
1188: * after writing "." and ".." entries out.
1189: */
1190: if (error = ialloc(dp, dirpref(dp->i_fs), dmode, ndp->ni_cred, &tip)) {
1191: iput(dp);
1192: return (error);
1193: }
1194: ip = tip;
1195: ip->i_uid = ndp->ni_cred->cr_uid;
1196: ip->i_gid = dp->i_gid;
1197: #ifdef QUOTA
1198: if ((error = getinoquota(ip)) ||
1199: (error = chkiq(ip, 1, ndp->ni_cred, 0))) {
1200: ifree(ip, ip->i_number, dmode);
1201: iput(ip);
1202: iput(dp);
1203: return (error);
1204: }
1205: #endif
1206: ip->i_flag |= IACC|IUPD|ICHG;
1207: ip->i_mode = dmode;
1208: ITOV(ip)->v_type = VDIR; /* Rest init'd in iget() */
1209: ip->i_nlink = 2;
1210: error = iupdat(ip, &time, &time, 1);
1211:
1212: /*
1213: * Bump link count in parent directory
1214: * to reflect work done below. Should
1215: * be done before reference is created
1216: * so reparation is possible if we crash.
1217: */
1218: dp->i_nlink++;
1219: dp->i_flag |= ICHG;
1220: error = iupdat(dp, &time, &time, 1);
1221:
1222: /*
1223: * Initialize directory with "."
1224: * and ".." from static template.
1225: */
1226: dirtemplate = mastertemplate;
1227: dirtemplate.dot_ino = ip->i_number;
1228: dirtemplate.dotdot_ino = dp->i_number;
1229: error = vn_rdwr(UIO_WRITE, ITOV(ip), (caddr_t)&dirtemplate,
1230: sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
1231: IO_NODELOCKED|IO_SYNC, ndp->ni_cred, (int *)0);
1232: if (error) {
1233: dp->i_nlink--;
1234: dp->i_flag |= ICHG;
1235: goto bad;
1236: }
1237: if (DIRBLKSIZ > dp->i_fs->fs_fsize) {
1238: panic("mkdir: blksize"); /* XXX - should grow w/balloc() */
1239: } else {
1240: ip->i_size = DIRBLKSIZ;
1241: ip->i_flag |= ICHG;
1242: }
1243: /*
1244: * Directory all set up, now
1245: * install the entry for it in
1246: * the parent directory.
1247: */
1248: error = direnter(ip, ndp);
1249: dp = NULL;
1250: if (error) {
1251: ndp->ni_nameiop = LOOKUP | NOCACHE;
1252: error = namei(ndp);
1253: if (!error) {
1254: dp = VTOI(ndp->ni_vp);
1255: dp->i_nlink--;
1256: dp->i_flag |= ICHG;
1257: }
1258: }
1259: bad:
1260: /*
1261: * No need to do an explicit itrunc here,
1262: * vrele will do this for us because we set
1263: * the link count to 0.
1264: */
1265: if (error) {
1266: ip->i_nlink = 0;
1267: ip->i_flag |= ICHG;
1268: iput(ip);
1269: } else
1270: ndp->ni_vp = ITOV(ip);
1271: if (dp)
1272: iput(dp);
1273: return (error);
1274: }
1275:
1276: /*
1277: * Rmdir system call.
1278: */
1279: ufs_rmdir(ndp)
1280: register struct nameidata *ndp;
1281: {
1282: register struct inode *ip, *dp;
1283: int error = 0;
1284:
1285: ip = VTOI(ndp->ni_vp);
1286: dp = VTOI(ndp->ni_dvp);
1287: /*
1288: * No rmdir "." please.
1289: */
1290: if (dp == ip) {
1291: vrele(ITOV(dp));
1292: iput(ip);
1293: return (EINVAL);
1294: }
1295: /*
1296: * Verify the directory is empty (and valid).
1297: * (Rmdir ".." won't be valid since
1298: * ".." will contain a reference to
1299: * the current directory and thus be
1300: * non-empty.)
1301: */
1302: if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number, ndp->ni_cred)) {
1303: error = ENOTEMPTY;
1304: goto out;
1305: }
1306: /*
1307: * Delete reference to directory before purging
1308: * inode. If we crash in between, the directory
1309: * will be reattached to lost+found,
1310: */
1311: if (error = dirremove(ndp))
1312: goto out;
1313: dp->i_nlink--;
1314: dp->i_flag |= ICHG;
1315: cache_purge(ITOV(dp));
1316: iput(dp);
1317: ndp->ni_dvp = NULL;
1318: /*
1319: * Truncate inode. The only stuff left
1320: * in the directory is "." and "..". The
1321: * "." reference is inconsequential since
1322: * we're quashing it. The ".." reference
1323: * has already been adjusted above. We've
1324: * removed the "." reference and the reference
1325: * in the parent directory, but there may be
1326: * other hard links so decrement by 2 and
1327: * worry about them later.
1328: */
1329: ip->i_nlink -= 2;
1330: error = itrunc(ip, (u_long)0, IO_SYNC);
1331: cache_purge(ITOV(ip));
1332: out:
1333: if (ndp->ni_dvp)
1334: iput(dp);
1335: iput(ip);
1336: return (error);
1337: }
1338:
1339: /*
1340: * symlink -- make a symbolic link
1341: */
1342: ufs_symlink(ndp, vap, target)
1343: struct nameidata *ndp;
1344: struct vattr *vap;
1345: char *target;
1346: {
1347: struct inode *ip;
1348: int error;
1349:
1350: error = maknode(IFLNK | vap->va_mode, ndp, &ip);
1351: if (error)
1352: return (error);
1353: error = vn_rdwr(UIO_WRITE, ITOV(ip), target, strlen(target), (off_t)0,
1354: UIO_SYSSPACE, IO_NODELOCKED, ndp->ni_cred, (int *)0);
1355: iput(ip);
1356: return (error);
1357: }
1358:
1359: /*
1360: * Vnode op for read and write
1361: */
1362: ufs_readdir(vp, uio, cred, eofflagp)
1363: struct vnode *vp;
1364: register struct uio *uio;
1365: struct ucred *cred;
1366: int *eofflagp;
1367: {
1368: int count, lost, error;
1369:
1370: count = uio->uio_resid;
1371: count &= ~(DIRBLKSIZ - 1);
1372: lost = uio->uio_resid - count;
1373: if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1)))
1374: return (EINVAL);
1375: uio->uio_resid = count;
1376: uio->uio_iov->iov_len = count;
1377: error = ufs_read(vp, uio, 0, cred);
1378: uio->uio_resid += lost;
1379: if ((VTOI(vp)->i_size - uio->uio_offset) <= 0)
1380: *eofflagp = 1;
1381: else
1382: *eofflagp = 0;
1383: return (error);
1384: }
1385:
1386: /*
1387: * Return target name of a symbolic link
1388: */
1389: ufs_readlink(vp, uiop, cred)
1390: struct vnode *vp;
1391: struct uio *uiop;
1392: struct ucred *cred;
1393: {
1394:
1395: return (ufs_read(vp, uiop, 0, cred));
1396: }
1397:
1398: /*
1399: * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
1400: * done. Nothing to do at the moment.
1401: */
1402: /* ARGSUSED */
1403: ufs_abortop(ndp)
1404: struct nameidata *ndp;
1405: {
1406:
1407: return (0);
1408: }
1409:
1410: /*
1411: * Lock an inode.
1412: */
1413: ufs_lock(vp)
1414: struct vnode *vp;
1415: {
1416: register struct inode *ip = VTOI(vp);
1417:
1418: ILOCK(ip);
1419: return (0);
1420: }
1421:
1422: /*
1423: * Unlock an inode.
1424: */
1425: ufs_unlock(vp)
1426: struct vnode *vp;
1427: {
1428: register struct inode *ip = VTOI(vp);
1429:
1430: if (!(ip->i_flag & ILOCKED))
1431: panic("ufs_unlock NOT LOCKED");
1432: IUNLOCK(ip);
1433: return (0);
1434: }
1435:
1436: /*
1437: * Check for a locked inode.
1438: */
1439: ufs_islocked(vp)
1440: struct vnode *vp;
1441: {
1442:
1443: if (VTOI(vp)->i_flag & ILOCKED)
1444: return (1);
1445: return (0);
1446: }
1447:
1448: /*
1449: * Get access to bmap
1450: */
1451: ufs_bmap(vp, bn, vpp, bnp)
1452: struct vnode *vp;
1453: daddr_t bn;
1454: struct vnode **vpp;
1455: daddr_t *bnp;
1456: {
1457: struct inode *ip = VTOI(vp);
1458:
1459: if (vpp != NULL)
1460: *vpp = ip->i_devvp;
1461: if (bnp == NULL)
1462: return (0);
1463: return (bmap(ip, bn, bnp));
1464: }
1465:
1466: /*
1467: * Calculate the logical to physical mapping if not done already,
1468: * then call the device strategy routine.
1469: */
1470: int checkoverlap = 0;
1471:
1472: ufs_strategy(bp)
1473: register struct buf *bp;
1474: {
1475: register struct inode *ip = VTOI(bp->b_vp);
1476: struct vnode *vp;
1477: int error;
1478:
1479: if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR)
1480: panic("ufs_strategy: spec");
1481: if (bp->b_blkno == bp->b_lblkno) {
1482: if (error = bmap(ip, bp->b_lblkno, &bp->b_blkno))
1483: return (error);
1484: if ((long)bp->b_blkno == -1)
1485: clrbuf(bp);
1486: }
1487: if ((long)bp->b_blkno == -1) {
1488: biodone(bp);
1489: return (0);
1490: }
1491: #ifdef DIAGNOSTIC
1492: if (checkoverlap) {
1493: register struct buf *ep;
1494: struct buf *ebp;
1495: daddr_t start, last;
1496:
1497: ebp = &buf[nbuf];
1498: start = bp->b_blkno;
1499: last = start + btodb(bp->b_bcount) - 1;
1500: for (ep = buf; ep < ebp; ep++) {
1501: if (ep == bp || (ep->b_flags & B_INVAL) ||
1502: ep->b_vp == NULLVP)
1503: continue;
1504: if (VOP_BMAP(ep->b_vp, (daddr_t)0, &vp, (daddr_t)0))
1505: continue;
1506: if (vp != ip->i_devvp)
1507: continue;
1508: /* look for overlap */
1509: if (ep->b_bcount == 0 || ep->b_blkno > last ||
1510: ep->b_blkno + btodb(ep->b_bcount) <= start)
1511: continue;
1512: vprint("Disk overlap", vp);
1513: printf("\tstart %d, end %d overlap start %d, end %d\n",
1514: start, last, ep->b_blkno,
1515: ep->b_blkno + btodb(ep->b_bcount) - 1);
1516: panic("Disk buffer overlap");
1517: }
1518: }
1519: #endif /* DIAGNOSTIC */
1520: vp = ip->i_devvp;
1521: bp->b_dev = vp->v_rdev;
1522: (*(vp->v_op->vn_strategy))(bp);
1523: return (0);
1524: }
1525:
1526: /*
1527: * Print out the contents of an inode.
1528: */
1529: ufs_print(vp)
1530: struct vnode *vp;
1531: {
1532: register struct inode *ip = VTOI(vp);
1533:
1534: printf("tag VT_UFS, ino %d, on dev %d, %d", ip->i_number,
1535: major(ip->i_dev), minor(ip->i_dev));
1536: #ifdef FIFO
1537: if (vp->v_type == VFIFO)
1538: fifo_printinfo(vp);
1539: #endif /* FIFO */
1540: printf("%s\n", (ip->i_flag & ILOCKED) ? " (LOCKED)" : "");
1541: if (ip->i_spare0 == 0)
1542: return;
1543: printf("\towner pid %d", ip->i_spare0);
1544: if (ip->i_spare1)
1545: printf(" waiting pid %d", ip->i_spare1);
1546: printf("\n");
1547: }
1548:
1549: /*
1550: * Read wrapper for special devices.
1551: */
1552: ufsspec_read(vp, uio, ioflag, cred)
1553: struct vnode *vp;
1554: struct uio *uio;
1555: int ioflag;
1556: struct ucred *cred;
1557: {
1558:
1559: /*
1560: * Set access flag.
1561: */
1562: VTOI(vp)->i_flag |= IACC;
1563: return (spec_read(vp, uio, ioflag, cred));
1564: }
1565:
1566: /*
1567: * Write wrapper for special devices.
1568: */
1569: ufsspec_write(vp, uio, ioflag, cred)
1570: struct vnode *vp;
1571: struct uio *uio;
1572: int ioflag;
1573: struct ucred *cred;
1574: {
1575:
1576: /*
1577: * Set update and change flags.
1578: */
1579: VTOI(vp)->i_flag |= IUPD|ICHG;
1580: return (spec_write(vp, uio, ioflag, cred));
1581: }
1582:
1583: /*
1584: * Close wrapper for special devices.
1585: *
1586: * Update the times on the inode then do device close.
1587: */
1588: ufsspec_close(vp, fflag, cred)
1589: struct vnode *vp;
1590: int fflag;
1591: struct ucred *cred;
1592: {
1593: register struct inode *ip = VTOI(vp);
1594:
1595: if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED))
1596: ITIMES(ip, &time, &time);
1597: return (spec_close(vp, fflag, cred));
1598: }
1599:
1600: #ifdef FIFO
1601: /*
1602: * Read wrapper for fifo's
1603: */
1604: ufsfifo_read(vp, uio, ioflag, cred)
1605: struct vnode *vp;
1606: struct uio *uio;
1607: int ioflag;
1608: struct ucred *cred;
1609: {
1610:
1611: /*
1612: * Set access flag.
1613: */
1614: VTOI(vp)->i_flag |= IACC;
1615: return (fifo_read(vp, uio, ioflag, cred));
1616: }
1617:
1618: /*
1619: * Write wrapper for fifo's.
1620: */
1621: ufsfifo_write(vp, uio, ioflag, cred)
1622: struct vnode *vp;
1623: struct uio *uio;
1624: int ioflag;
1625: struct ucred *cred;
1626: {
1627:
1628: /*
1629: * Set update and change flags.
1630: */
1631: VTOI(vp)->i_flag |= IUPD|ICHG;
1632: return (fifo_write(vp, uio, ioflag, cred));
1633: }
1634:
1635: /*
1636: * Close wrapper for fifo's.
1637: *
1638: * Update the times on the inode then do device close.
1639: */
1640: ufsfifo_close(vp, fflag, cred)
1641: struct vnode *vp;
1642: int fflag;
1643: struct ucred *cred;
1644: {
1645: register struct inode *ip = VTOI(vp);
1646:
1647: if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED))
1648: ITIMES(ip, &time, &time);
1649: return (fifo_close(vp, fflag, cred));
1650: }
1651: #endif /* FIFO */
1652:
1653: /*
1654: * Make a new file.
1655: */
1656: maknode(mode, ndp, ipp)
1657: int mode;
1658: register struct nameidata *ndp;
1659: struct inode **ipp;
1660: {
1661: register struct inode *ip;
1662: struct inode *tip;
1663: register struct inode *pdir = VTOI(ndp->ni_dvp);
1664: ino_t ipref;
1665: int error;
1666:
1667: *ipp = 0;
1668: if ((mode & IFMT) == 0)
1669: mode |= IFREG;
1670: if ((mode & IFMT) == IFDIR)
1671: ipref = dirpref(pdir->i_fs);
1672: else
1673: ipref = pdir->i_number;
1674: if (error = ialloc(pdir, ipref, mode, ndp->ni_cred, &tip)) {
1675: iput(pdir);
1676: return (error);
1677: }
1678: ip = tip;
1679: ip->i_uid = ndp->ni_cred->cr_uid;
1680: ip->i_gid = pdir->i_gid;
1681: #ifdef QUOTA
1682: if ((error = getinoquota(ip)) ||
1683: (error = chkiq(ip, 1, ndp->ni_cred, 0))) {
1684: ifree(ip, ip->i_number, mode);
1685: iput(ip);
1686: iput(pdir);
1687: return (error);
1688: }
1689: #endif
1690: ip->i_flag |= IACC|IUPD|ICHG;
1691: ip->i_mode = mode;
1692: ITOV(ip)->v_type = IFTOVT(mode); /* Rest init'd in iget() */
1693: ip->i_nlink = 1;
1694: if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, ndp->ni_cred) &&
1695: suser(ndp->ni_cred, NULL))
1696: ip->i_mode &= ~ISGID;
1697:
1698: /*
1699: * Make sure inode goes to disk before directory entry.
1700: */
1701: if (error = iupdat(ip, &time, &time, 1))
1702: goto bad;
1703: if (error = direnter(ip, ndp)) {
1704: pdir = NULL;
1705: goto bad;
1706: }
1707: *ipp = ip;
1708: return (0);
1709:
1710: bad:
1711: /*
1712: * Write error occurred trying to update the inode
1713: * or the directory so must deallocate the inode.
1714: */
1715: if (pdir)
1716: iput(pdir);
1717: ip->i_nlink = 0;
1718: ip->i_flag |= ICHG;
1719: iput(ip);
1720: return (error);
1721: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.