xref: /csrg-svn/sys/ufs/lfs/lfs_vnops.c (revision 51558)
123405Smckusick /*
251502Sbostic  * Copyright (c) 1986, 1989, 1991 Regents of the University of California.
337737Smckusick  * All rights reserved.
423405Smckusick  *
544539Sbostic  * %sccs.include.redist.c%
637737Smckusick  *
7*51558Smckusick  *	@(#)lfs_vnops.c	7.71 (Berkeley) 11/05/91
823405Smckusick  */
937Sbill 
1051482Sbostic #include <sys/param.h>
1151482Sbostic #include <sys/systm.h>
1251482Sbostic #include <sys/namei.h>
1351482Sbostic #include <sys/resourcevar.h>
1451482Sbostic #include <sys/kernel.h>
1551482Sbostic #include <sys/file.h>
1651482Sbostic #include <sys/stat.h>
1751482Sbostic #include <sys/buf.h>
1851482Sbostic #include <sys/proc.h>
1951482Sbostic #include <sys/conf.h>
2051482Sbostic #include <sys/mount.h>
2151482Sbostic #include <sys/vnode.h>
2251482Sbostic #include <sys/specdev.h>
2351482Sbostic #include <sys/fifo.h>
2451482Sbostic #include <sys/malloc.h>
2537Sbill 
2651502Sbostic #include <ufs/ufs/quota.h>
2751502Sbostic #include <ufs/ufs/inode.h>
2851502Sbostic #include <ufs/ufs/dir.h>
2951502Sbostic #include <ufs/ufs/ufs_extern.h>
3047571Skarels 
3151502Sbostic #include <ufs/lfs/lfs.h>
3251502Sbostic #include <ufs/lfs/lfs_extern.h>
3351134Sbostic 
3451482Sbostic /* Global vfs data structures for lfs. */
3551482Sbostic struct vnodeops lfs_vnodeops = {
3651482Sbostic 	ufs_lookup,		/* lookup */
3751482Sbostic 	ufs_create,		/* create */
3851482Sbostic 	ufs_mknod,		/* mknod */
3951482Sbostic 	ufs_open,		/* open */
4051482Sbostic 	ufs_close,		/* close */
4151482Sbostic 	ufs_access,		/* access */
4251482Sbostic 	ufs_getattr,		/* getattr */
4351482Sbostic 	ufs_setattr,		/* setattr */
4451482Sbostic 	lfs_read,		/* read */
4551482Sbostic 	lfs_write,		/* write */
4651482Sbostic 	ufs_ioctl,		/* ioctl */
4751482Sbostic 	ufs_select,		/* select */
4851482Sbostic 	ufs_mmap,		/* mmap */
4951482Sbostic 	lfs_fsync,		/* fsync */
5051482Sbostic 	ufs_seek,		/* seek */
5151482Sbostic 	ufs_remove,		/* remove */
5251482Sbostic 	ufs_link,		/* link */
5351482Sbostic 	ufs_rename,		/* rename */
5451482Sbostic 	ufs_mkdir,		/* mkdir */
5551482Sbostic 	ufs_rmdir,		/* rmdir */
5651482Sbostic 	ufs_symlink,		/* symlink */
5751482Sbostic 	ufs_readdir,		/* readdir */
5851482Sbostic 	ufs_readlink,		/* readlink */
5951482Sbostic 	ufs_abortop,		/* abortop */
60*51558Smckusick 	lfs_inactive,		/* inactive */
6151482Sbostic 	ufs_reclaim,		/* reclaim */
6251482Sbostic 	ufs_lock,		/* lock */
6351482Sbostic 	ufs_unlock,		/* unlock */
64*51558Smckusick 	lfs_bmap,		/* bmap */
6551482Sbostic 	ufs_strategy,		/* strategy */
6651482Sbostic 	ufs_print,		/* print */
6751482Sbostic 	ufs_islocked,		/* islocked */
6851482Sbostic 	ufs_advlock,		/* advlock */
69*51558Smckusick 	lfs_blkatoff,		/* blkatoff */
70*51558Smckusick 	lfs_vget,		/* vget */
71*51558Smckusick 	lfs_valloc,		/* valloc */
72*51558Smckusick 	lfs_vfree,		/* vfree */
73*51558Smckusick 	lfs_truncate,		/* truncate */
74*51558Smckusick 	lfs_update,		/* update */
75*51558Smckusick 	lfs_bwrite,		/* bwrite */
7651482Sbostic };
776254Sroot 
78*51558Smckusick struct vnodeops lfs_specops = {
79*51558Smckusick 	spec_lookup,		/* lookup */
80*51558Smckusick 	spec_create,		/* create */
81*51558Smckusick 	spec_mknod,		/* mknod */
82*51558Smckusick 	spec_open,		/* open */
83*51558Smckusick 	ufsspec_close,		/* close */
84*51558Smckusick 	ufs_access,		/* access */
85*51558Smckusick 	ufs_getattr,		/* getattr */
86*51558Smckusick 	ufs_setattr,		/* setattr */
87*51558Smckusick 	ufsspec_read,		/* read */
88*51558Smckusick 	ufsspec_write,		/* write */
89*51558Smckusick 	spec_ioctl,		/* ioctl */
90*51558Smckusick 	spec_select,		/* select */
91*51558Smckusick 	spec_mmap,		/* mmap */
92*51558Smckusick 	spec_fsync,		/* fsync */
93*51558Smckusick 	spec_seek,		/* seek */
94*51558Smckusick 	spec_remove,		/* remove */
95*51558Smckusick 	spec_link,		/* link */
96*51558Smckusick 	spec_rename,		/* rename */
97*51558Smckusick 	spec_mkdir,		/* mkdir */
98*51558Smckusick 	spec_rmdir,		/* rmdir */
99*51558Smckusick 	spec_symlink,		/* symlink */
100*51558Smckusick 	spec_readdir,		/* readdir */
101*51558Smckusick 	spec_readlink,		/* readlink */
102*51558Smckusick 	spec_abortop,		/* abortop */
103*51558Smckusick 	lfs_inactive,		/* inactive */
104*51558Smckusick 	ufs_reclaim,		/* reclaim */
105*51558Smckusick 	ufs_lock,		/* lock */
106*51558Smckusick 	ufs_unlock,		/* unlock */
107*51558Smckusick 	spec_bmap,		/* bmap */
108*51558Smckusick 	spec_strategy,		/* strategy */
109*51558Smckusick 	ufs_print,		/* print */
110*51558Smckusick 	ufs_islocked,		/* islocked */
111*51558Smckusick 	spec_advlock,		/* advlock */
112*51558Smckusick 	spec_blkatoff,		/* blkatoff */
113*51558Smckusick 	spec_vget,		/* vget */
114*51558Smckusick 	spec_valloc,		/* valloc */
115*51558Smckusick 	spec_vfree,		/* vfree */
116*51558Smckusick 	spec_truncate,		/* truncate */
117*51558Smckusick 	lfs_update,		/* update */
118*51558Smckusick 	lfs_bwrite,		/* bwrite */
119*51558Smckusick };
120*51558Smckusick 
121*51558Smckusick #ifdef FIFO
122*51558Smckusick struct vnodeops lfs_fifoops = {
123*51558Smckusick 	fifo_lookup,		/* lookup */
124*51558Smckusick 	fifo_create,		/* create */
125*51558Smckusick 	fifo_mknod,		/* mknod */
126*51558Smckusick 	fifo_open,		/* open */
127*51558Smckusick 	ufsfifo_close,		/* close */
128*51558Smckusick 	ufs_access,		/* access */
129*51558Smckusick 	ufs_getattr,		/* getattr */
130*51558Smckusick 	ufs_setattr,		/* setattr */
131*51558Smckusick 	ufsfifo_read,		/* read */
132*51558Smckusick 	ufsfifo_write,		/* write */
133*51558Smckusick 	fifo_ioctl,		/* ioctl */
134*51558Smckusick 	fifo_select,		/* select */
135*51558Smckusick 	fifo_mmap,		/* mmap */
136*51558Smckusick 	fifo_fsync,		/* fsync */
137*51558Smckusick 	fifo_seek,		/* seek */
138*51558Smckusick 	fifo_remove,		/* remove */
139*51558Smckusick 	fifo_link,		/* link */
140*51558Smckusick 	fifo_rename,		/* rename */
141*51558Smckusick 	fifo_mkdir,		/* mkdir */
142*51558Smckusick 	fifo_rmdir,		/* rmdir */
143*51558Smckusick 	fifo_symlink,		/* symlink */
144*51558Smckusick 	fifo_readdir,		/* readdir */
145*51558Smckusick 	fifo_readlink,		/* readlink */
146*51558Smckusick 	fifo_abortop,		/* abortop */
147*51558Smckusick 	lfs_inactive,		/* inactive */
148*51558Smckusick 	ufs_reclaim,		/* reclaim */
149*51558Smckusick 	ufs_lock,		/* lock */
150*51558Smckusick 	ufs_unlock,		/* unlock */
151*51558Smckusick 	fifo_bmap,		/* bmap */
152*51558Smckusick 	fifo_strategy,		/* strategy */
153*51558Smckusick 	ufs_print,		/* print */
154*51558Smckusick 	ufs_islocked,		/* islocked */
155*51558Smckusick 	fifo_advlock,		/* advlock */
156*51558Smckusick 	fifo_blkatoff,		/* blkatoff */
157*51558Smckusick 	fifo_vget,		/* vget */
158*51558Smckusick 	fifo_valloc,		/* valloc */
159*51558Smckusick 	fifo_vfree,		/* vfree */
160*51558Smckusick 	fifo_truncate,		/* truncate */
161*51558Smckusick 	lfs_update,		/* update */
162*51558Smckusick 	lfs_bwrite,		/* bwrite */
163*51558Smckusick };
164*51558Smckusick #endif /* FIFO */
165*51558Smckusick 
16637Sbill /*
16739608Smckusick  * Vnode op for reading.
16839608Smckusick  */
16937737Smckusick /* ARGSUSED */
17051134Sbostic lfs_read(vp, uio, ioflag, cred)
17139608Smckusick 	struct vnode *vp;
17239608Smckusick 	register struct uio *uio;
17339608Smckusick 	int ioflag;
17439608Smckusick 	struct ucred *cred;
17539608Smckusick {
17639608Smckusick 	register struct inode *ip = VTOI(vp);
17751502Sbostic 	register struct lfs *fs;				/* LFS */
17839608Smckusick 	struct buf *bp;
17939608Smckusick 	daddr_t lbn, bn, rablock;
18039896Smckusick 	int size, diff, error = 0;
18139608Smckusick 	long n, on, type;
18239608Smckusick 
18351155Sbostic printf("lfs_read: ino %d\n", ip->i_number);
18448039Smckusick #ifdef DIAGNOSTIC
18539608Smckusick 	if (uio->uio_rw != UIO_READ)
18639608Smckusick 		panic("ufs_read mode");
18739608Smckusick 	type = ip->i_mode & IFMT;
18839608Smckusick 	if (type != IFDIR && type != IFREG && type != IFLNK)
18939608Smckusick 		panic("ufs_read type");
19048039Smckusick #endif
19139608Smckusick 	if (uio->uio_resid == 0)
19239608Smckusick 		return (0);
19339608Smckusick 	if (uio->uio_offset < 0)
19439608Smckusick 		return (EINVAL);
19539608Smckusick 	ip->i_flag |= IACC;
19651155Sbostic 
19751155Sbostic 	fs = ip->i_lfs;						/* LFS */
19839608Smckusick 	do {
19939608Smckusick 		lbn = lblkno(fs, uio->uio_offset);
20039608Smckusick 		on = blkoff(fs, uio->uio_offset);
20151155Sbostic 		n = MIN((unsigned)(fs->lfs_bsize - on), uio->uio_resid);
20239608Smckusick 		diff = ip->i_size - uio->uio_offset;
20339608Smckusick 		if (diff <= 0)
20439608Smckusick 			return (0);
20539608Smckusick 		if (diff < n)
20639608Smckusick 			n = diff;
20751155Sbostic 		size = blksize(fs);				/* LFS */
20839674Smckusick 		rablock = lbn + 1;
20939896Smckusick 		if (vp->v_lastr + 1 == lbn &&
21039896Smckusick 		    lblktosize(fs, rablock) < ip->i_size)
21139896Smckusick 			error = breada(ITOV(ip), lbn, size, rablock,
21251155Sbostic 				blksize(fs), NOCRED, &bp);
21339608Smckusick 		else
21439674Smckusick 			error = bread(ITOV(ip), lbn, size, NOCRED, &bp);
21539815Smckusick 		vp->v_lastr = lbn;
21639608Smckusick 		n = MIN(n, size - bp->b_resid);
21739608Smckusick 		if (error) {
21839608Smckusick 			brelse(bp);
21939608Smckusick 			return (error);
22039608Smckusick 		}
22139608Smckusick 		error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
22251155Sbostic 		if (n + on == fs->lfs_bsize || uio->uio_offset == ip->i_size)
22339608Smckusick 			bp->b_flags |= B_AGE;
22439608Smckusick 		brelse(bp);
22539608Smckusick 	} while (error == 0 && uio->uio_resid > 0 && n != 0);
22639608Smckusick 	return (error);
22739608Smckusick }
22839608Smckusick 
22939608Smckusick /*
23039608Smckusick  * Vnode op for writing.
23139608Smckusick  */
23251134Sbostic lfs_write(vp, uio, ioflag, cred)
23339608Smckusick 	register struct vnode *vp;
23439608Smckusick 	struct uio *uio;
23539608Smckusick 	int ioflag;
23639608Smckusick 	struct ucred *cred;
23739608Smckusick {
23848039Smckusick 	struct proc *p = uio->uio_procp;
23939608Smckusick 	register struct inode *ip = VTOI(vp);
24051502Sbostic 	register struct lfs *fs;				/* LFS */
24139608Smckusick 	struct buf *bp;
24239608Smckusick 	daddr_t lbn, bn;
24339608Smckusick 	u_long osize;
24445722Smckusick 	int n, on, flags;
24545722Smckusick 	int size, resid, error = 0;
24639608Smckusick 
24751155Sbostic printf("lfs_write ino %d\n", ip->i_number);
24848039Smckusick #ifdef DIAGNOSTIC
24939608Smckusick 	if (uio->uio_rw != UIO_WRITE)
25039608Smckusick 		panic("ufs_write mode");
25148039Smckusick #endif
25239608Smckusick 	switch (vp->v_type) {
25339608Smckusick 	case VREG:
25439608Smckusick 		if (ioflag & IO_APPEND)
25539608Smckusick 			uio->uio_offset = ip->i_size;
25639608Smckusick 		/* fall through */
25739608Smckusick 	case VLNK:
25839608Smckusick 		break;
25939608Smckusick 
26039608Smckusick 	case VDIR:
26139608Smckusick 		if ((ioflag & IO_SYNC) == 0)
26239608Smckusick 			panic("ufs_write nonsync dir write");
26339608Smckusick 		break;
26439608Smckusick 
26539608Smckusick 	default:
26639608Smckusick 		panic("ufs_write type");
26739608Smckusick 	}
26839608Smckusick 	if (uio->uio_offset < 0)
26939608Smckusick 		return (EINVAL);
27039608Smckusick 	if (uio->uio_resid == 0)
27139608Smckusick 		return (0);
27239608Smckusick 	/*
27339608Smckusick 	 * Maybe this should be above the vnode op call, but so long as
27439608Smckusick 	 * file servers have no limits, i don't think it matters
27539608Smckusick 	 */
27649679Smckusick 	if (vp->v_type == VREG && p &&
27739608Smckusick 	    uio->uio_offset + uio->uio_resid >
27847571Skarels 	      p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
27947571Skarels 		psignal(p, SIGXFSZ);
28039608Smckusick 		return (EFBIG);
28139608Smckusick 	}
28239608Smckusick 	resid = uio->uio_resid;
28339608Smckusick 	osize = ip->i_size;
28451183Sbostic 	fs = ip->i_lfs;						/* LFS */
28539674Smckusick 	flags = 0;
28651183Sbostic #ifdef NOTLFS
28739674Smckusick 	if (ioflag & IO_SYNC)
28839674Smckusick 		flags = B_SYNC;
28951183Sbostic #endif
29039608Smckusick 	do {
29139608Smckusick 		lbn = lblkno(fs, uio->uio_offset);
29251183Sbostic 		on = blkoff(fs, uio->uio_offset);		/* LFS */
29351183Sbostic 		n = MIN((unsigned)(fs->lfs_bsize - on), uio->uio_resid);
29451183Sbostic 		if (n < fs->lfs_bsize)				/* LFS */
29539674Smckusick 			flags |= B_CLRBUF;
29639608Smckusick 		else
29751183Sbostic 			flags &= ~B_CLRBUF;			/* LFS */
29851183Sbostic 		if (error = bread(vp, lbn, fs->lfs_bsize, NOCRED, &bp))
29939608Smckusick 			break;
30039674Smckusick 		bn = bp->b_blkno;
30145722Smckusick 		if (uio->uio_offset + n > ip->i_size) {
30239608Smckusick 			ip->i_size = uio->uio_offset + n;
30345722Smckusick 			vnode_pager_setsize(vp, ip->i_size);
30445722Smckusick 		}
30551183Sbostic 		size = blksize(fs);
30645722Smckusick 		(void) vnode_pager_uncache(vp);
30739608Smckusick 		n = MIN(n, size - bp->b_resid);
30839608Smckusick 		error = uiomove(bp->b_un.b_addr + on, n, uio);
30951183Sbostic #ifdef NOTLFS							/* LFS */
31039608Smckusick 		if (ioflag & IO_SYNC)
31139608Smckusick 			(void) bwrite(bp);
31239608Smckusick 		else if (n + on == fs->fs_bsize) {
31339608Smckusick 			bp->b_flags |= B_AGE;
31439608Smckusick 			bawrite(bp);
31539608Smckusick 		} else
31639608Smckusick 			bdwrite(bp);
31751183Sbostic #else
31851183Sbostic 		/*
31951183Sbostic 		 * Update segment usage information; call segment
32051183Sbostic 		 * writer if necessary.
32151183Sbostic 		 */
32251183Sbostic 		lfs_bwrite(bp);
32351183Sbostic #endif
32439608Smckusick 		ip->i_flag |= IUPD|ICHG;
32539608Smckusick 		if (cred->cr_uid != 0)
32639608Smckusick 			ip->i_mode &= ~(ISUID|ISGID);
32739608Smckusick 	} while (error == 0 && uio->uio_resid > 0 && n != 0);
32839608Smckusick 	if (error && (ioflag & IO_UNIT)) {
32951183Sbostic #ifdef NOTLFS
33051183Sbostic 	/* This just doesn't work... */
331*51558Smckusick 		(void) lfs_itrunc(vp, osize, ioflag & IO_SYNC);
33251183Sbostic #endif
33339608Smckusick 		uio->uio_offset -= resid - uio->uio_resid;
33439608Smckusick 		uio->uio_resid = resid;
33539608Smckusick 	}
33642493Smckusick 	if (!error && (ioflag & IO_SYNC))
33751183Sbostic 		ITIMES(ip, &time, &time);			/* LFS */
33839608Smckusick 	return (error);
33939608Smckusick }
34039608Smckusick 
3419167Ssam /*
34237737Smckusick  * Synch an open file.
3439167Ssam  */
34437737Smckusick /* ARGSUSED */
34551134Sbostic lfs_fsync(vp, fflags, cred, waitfor, p)
34637737Smckusick 	struct vnode *vp;
34737737Smckusick 	int fflags;
34837737Smckusick 	struct ucred *cred;
34939597Smckusick 	int waitfor;
35048039Smckusick 	struct proc *p;
3517701Ssam {
35239597Smckusick 	struct inode *ip = VTOI(vp);
3537701Ssam 
35448039Smckusick 	if (fflags & FWRITE)
35537737Smckusick 		ip->i_flag |= ICHG;
35649737Smckusick 	/*
35751482Sbostic 	 * XXX
35851482Sbostic 	 * Sync the mounted file system associated with the file
35951482Sbostic 	 * descriptor.
36049737Smckusick 	 */
36151183Sbostic 	ITIMES(ip, &time, &time);				/* LFS */
36237737Smckusick 	return (0);
36337737Smckusick }
364*51558Smckusick 
365*51558Smckusick /*
366*51558Smckusick  * Last reference to an inode, write the inode out and if necessary,
367*51558Smckusick  * truncate and deallocate the file.
368*51558Smckusick  */
369*51558Smckusick int
370*51558Smckusick lfs_inactive(vp, p)
371*51558Smckusick 	struct vnode *vp;
372*51558Smckusick 	struct proc *p;
373*51558Smckusick {
374*51558Smckusick 	register struct inode *ip;
375*51558Smckusick 	int mode, error;
376*51558Smckusick 	extern int prtactive;
377*51558Smckusick 
378*51558Smckusick 	if (prtactive && vp->v_usecount != 0)
379*51558Smckusick 		vprint("lfs_inactive: pushing active", vp);
380*51558Smckusick 
381*51558Smckusick 	/* Get rid of inodes related to stale file handles. */
382*51558Smckusick 	ip = VTOI(vp);
383*51558Smckusick 	if (ip->i_mode == 0) {
384*51558Smckusick 		if ((vp->v_flag & VXLOCK) == 0)
385*51558Smckusick 			vgone(vp);
386*51558Smckusick 		return (0);
387*51558Smckusick 	}
388*51558Smckusick 
389*51558Smckusick 	error = 0;
390*51558Smckusick 	ILOCK(ip);
391*51558Smckusick 	if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
392*51558Smckusick #ifdef QUOTA
393*51558Smckusick 		if (!getinoquota(ip))
394*51558Smckusick 			(void)chkiq(ip, -1, NOCRED, 0);
395*51558Smckusick #endif
396*51558Smckusick 		error = lfs_truncate(vp, (u_long)0, 0);
397*51558Smckusick 		mode = ip->i_mode;
398*51558Smckusick 		ip->i_mode = 0;
399*51558Smckusick 		ip->i_rdev = 0;
400*51558Smckusick 		ip->i_flag |= IUPD|ICHG;
401*51558Smckusick 		lfs_vfree(vp, ip->i_number, mode);
402*51558Smckusick 	}
403*51558Smckusick 	if (ip->i_flag&(IUPD|IACC|ICHG|IMOD))
404*51558Smckusick 		lfs_update(vp, &time, &time, 0);
405*51558Smckusick 	IUNLOCK(ip);
406*51558Smckusick 	ip->i_flag = 0;
407*51558Smckusick 	/*
408*51558Smckusick 	 * If we are done with the inode, reclaim it
409*51558Smckusick 	 * so that it can be reused immediately.
410*51558Smckusick 	 */
411*51558Smckusick 	if (vp->v_usecount == 0 && ip->i_mode == 0)
412*51558Smckusick 		vgone(vp);
413*51558Smckusick 	return (error);
414*51558Smckusick }
415