xref: /csrg-svn/sys/ufs/lfs/lfs_vnops.c (revision 53321)
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*53321Smckusick  *	@(#)lfs_vnops.c	7.80 (Berkeley) 05/04/92
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 
26*53321Smckusick #include <vm/vm.h>
27*53321Smckusick 
2851502Sbostic #include <ufs/ufs/quota.h>
2951502Sbostic #include <ufs/ufs/inode.h>
3051502Sbostic #include <ufs/ufs/dir.h>
3151502Sbostic #include <ufs/ufs/ufs_extern.h>
3247571Skarels 
3351502Sbostic #include <ufs/lfs/lfs.h>
3451502Sbostic #include <ufs/lfs/lfs_extern.h>
3551134Sbostic 
3651482Sbostic /* Global vfs data structures for lfs. */
3751482Sbostic struct vnodeops lfs_vnodeops = {
3851482Sbostic 	ufs_lookup,		/* lookup */
3951482Sbostic 	ufs_create,		/* create */
4051482Sbostic 	ufs_mknod,		/* mknod */
4151482Sbostic 	ufs_open,		/* open */
4251482Sbostic 	ufs_close,		/* close */
4351482Sbostic 	ufs_access,		/* access */
4451482Sbostic 	ufs_getattr,		/* getattr */
4551482Sbostic 	ufs_setattr,		/* setattr */
4651482Sbostic 	lfs_read,		/* read */
4751482Sbostic 	lfs_write,		/* write */
4851482Sbostic 	ufs_ioctl,		/* ioctl */
4951482Sbostic 	ufs_select,		/* select */
5051482Sbostic 	ufs_mmap,		/* mmap */
5151482Sbostic 	lfs_fsync,		/* fsync */
5251482Sbostic 	ufs_seek,		/* seek */
5351482Sbostic 	ufs_remove,		/* remove */
5451482Sbostic 	ufs_link,		/* link */
5551482Sbostic 	ufs_rename,		/* rename */
5651482Sbostic 	ufs_mkdir,		/* mkdir */
5751482Sbostic 	ufs_rmdir,		/* rmdir */
5851482Sbostic 	ufs_symlink,		/* symlink */
5951482Sbostic 	ufs_readdir,		/* readdir */
6051482Sbostic 	ufs_readlink,		/* readlink */
6151482Sbostic 	ufs_abortop,		/* abortop */
6251558Smckusick 	lfs_inactive,		/* inactive */
6351482Sbostic 	ufs_reclaim,		/* reclaim */
6451482Sbostic 	ufs_lock,		/* lock */
6551482Sbostic 	ufs_unlock,		/* unlock */
6651558Smckusick 	lfs_bmap,		/* bmap */
6751482Sbostic 	ufs_strategy,		/* strategy */
6851482Sbostic 	ufs_print,		/* print */
6951482Sbostic 	ufs_islocked,		/* islocked */
7051482Sbostic 	ufs_advlock,		/* advlock */
7151558Smckusick 	lfs_blkatoff,		/* blkatoff */
7251558Smckusick 	lfs_vget,		/* vget */
7351558Smckusick 	lfs_valloc,		/* valloc */
7451558Smckusick 	lfs_vfree,		/* vfree */
7551558Smckusick 	lfs_truncate,		/* truncate */
7651558Smckusick 	lfs_update,		/* update */
7751558Smckusick 	lfs_bwrite,		/* bwrite */
7851482Sbostic };
796254Sroot 
8051558Smckusick struct vnodeops lfs_specops = {
8151558Smckusick 	spec_lookup,		/* lookup */
8251558Smckusick 	spec_create,		/* create */
8351558Smckusick 	spec_mknod,		/* mknod */
8451558Smckusick 	spec_open,		/* open */
8551558Smckusick 	ufsspec_close,		/* close */
8651558Smckusick 	ufs_access,		/* access */
8751558Smckusick 	ufs_getattr,		/* getattr */
8851558Smckusick 	ufs_setattr,		/* setattr */
8951558Smckusick 	ufsspec_read,		/* read */
9051558Smckusick 	ufsspec_write,		/* write */
9151558Smckusick 	spec_ioctl,		/* ioctl */
9251558Smckusick 	spec_select,		/* select */
9351558Smckusick 	spec_mmap,		/* mmap */
9451558Smckusick 	spec_fsync,		/* fsync */
9551558Smckusick 	spec_seek,		/* seek */
9651558Smckusick 	spec_remove,		/* remove */
9751558Smckusick 	spec_link,		/* link */
9851558Smckusick 	spec_rename,		/* rename */
9951558Smckusick 	spec_mkdir,		/* mkdir */
10051558Smckusick 	spec_rmdir,		/* rmdir */
10151558Smckusick 	spec_symlink,		/* symlink */
10251558Smckusick 	spec_readdir,		/* readdir */
10351558Smckusick 	spec_readlink,		/* readlink */
10451558Smckusick 	spec_abortop,		/* abortop */
10551558Smckusick 	lfs_inactive,		/* inactive */
10651558Smckusick 	ufs_reclaim,		/* reclaim */
10751558Smckusick 	ufs_lock,		/* lock */
10851558Smckusick 	ufs_unlock,		/* unlock */
10951558Smckusick 	spec_bmap,		/* bmap */
11051558Smckusick 	spec_strategy,		/* strategy */
11151558Smckusick 	ufs_print,		/* print */
11251558Smckusick 	ufs_islocked,		/* islocked */
11351558Smckusick 	spec_advlock,		/* advlock */
11451558Smckusick 	spec_blkatoff,		/* blkatoff */
11551558Smckusick 	spec_vget,		/* vget */
11651558Smckusick 	spec_valloc,		/* valloc */
11751558Smckusick 	spec_vfree,		/* vfree */
11851558Smckusick 	spec_truncate,		/* truncate */
11951558Smckusick 	lfs_update,		/* update */
12051558Smckusick 	lfs_bwrite,		/* bwrite */
12151558Smckusick };
12251558Smckusick 
12351558Smckusick #ifdef FIFO
12451558Smckusick struct vnodeops lfs_fifoops = {
12551558Smckusick 	fifo_lookup,		/* lookup */
12651558Smckusick 	fifo_create,		/* create */
12751558Smckusick 	fifo_mknod,		/* mknod */
12851558Smckusick 	fifo_open,		/* open */
12951558Smckusick 	ufsfifo_close,		/* close */
13051558Smckusick 	ufs_access,		/* access */
13151558Smckusick 	ufs_getattr,		/* getattr */
13251558Smckusick 	ufs_setattr,		/* setattr */
13351558Smckusick 	ufsfifo_read,		/* read */
13451558Smckusick 	ufsfifo_write,		/* write */
13551558Smckusick 	fifo_ioctl,		/* ioctl */
13651558Smckusick 	fifo_select,		/* select */
13751558Smckusick 	fifo_mmap,		/* mmap */
13851558Smckusick 	fifo_fsync,		/* fsync */
13951558Smckusick 	fifo_seek,		/* seek */
14051558Smckusick 	fifo_remove,		/* remove */
14151558Smckusick 	fifo_link,		/* link */
14251558Smckusick 	fifo_rename,		/* rename */
14351558Smckusick 	fifo_mkdir,		/* mkdir */
14451558Smckusick 	fifo_rmdir,		/* rmdir */
14551558Smckusick 	fifo_symlink,		/* symlink */
14651558Smckusick 	fifo_readdir,		/* readdir */
14751558Smckusick 	fifo_readlink,		/* readlink */
14851558Smckusick 	fifo_abortop,		/* abortop */
14951558Smckusick 	lfs_inactive,		/* inactive */
15051558Smckusick 	ufs_reclaim,		/* reclaim */
15151558Smckusick 	ufs_lock,		/* lock */
15251558Smckusick 	ufs_unlock,		/* unlock */
15351558Smckusick 	fifo_bmap,		/* bmap */
15451558Smckusick 	fifo_strategy,		/* strategy */
15551558Smckusick 	ufs_print,		/* print */
15651558Smckusick 	ufs_islocked,		/* islocked */
15751558Smckusick 	fifo_advlock,		/* advlock */
15851558Smckusick 	fifo_blkatoff,		/* blkatoff */
15951558Smckusick 	fifo_vget,		/* vget */
16051558Smckusick 	fifo_valloc,		/* valloc */
16151558Smckusick 	fifo_vfree,		/* vfree */
16251558Smckusick 	fifo_truncate,		/* truncate */
16351558Smckusick 	lfs_update,		/* update */
16451558Smckusick 	lfs_bwrite,		/* bwrite */
16551558Smckusick };
16651558Smckusick #endif /* FIFO */
16751558Smckusick 
16837Sbill /*
16939608Smckusick  * Vnode op for reading.
17039608Smckusick  */
17137737Smckusick /* ARGSUSED */
17251134Sbostic lfs_read(vp, uio, ioflag, cred)
17339608Smckusick 	struct vnode *vp;
17439608Smckusick 	register struct uio *uio;
17539608Smckusick 	int ioflag;
17639608Smckusick 	struct ucred *cred;
17739608Smckusick {
17839608Smckusick 	register struct inode *ip = VTOI(vp);
17951502Sbostic 	register struct lfs *fs;				/* LFS */
18039608Smckusick 	struct buf *bp;
18139608Smckusick 	daddr_t lbn, bn, rablock;
18253233Smckusick 	int size, error = 0;
18339608Smckusick 	long n, on, type;
18453233Smckusick 	off_t diff;
18539608Smckusick 
18651852Sbostic #ifdef VERBOSE
18751852Sbostic 	printf("lfs_read: ino %d\n", ip->i_number);
18851852Sbostic #endif
18948039Smckusick #ifdef DIAGNOSTIC
19039608Smckusick 	if (uio->uio_rw != UIO_READ)
19139608Smckusick 		panic("ufs_read mode");
19239608Smckusick 	type = ip->i_mode & IFMT;
19339608Smckusick 	if (type != IFDIR && type != IFREG && type != IFLNK)
19439608Smckusick 		panic("ufs_read type");
19548039Smckusick #endif
19639608Smckusick 	if (uio->uio_resid == 0)
19739608Smckusick 		return (0);
19839608Smckusick 	if (uio->uio_offset < 0)
19939608Smckusick 		return (EINVAL);
20039608Smckusick 	ip->i_flag |= IACC;
20151155Sbostic 
20251155Sbostic 	fs = ip->i_lfs;						/* LFS */
20339608Smckusick 	do {
20439608Smckusick 		lbn = lblkno(fs, uio->uio_offset);
20539608Smckusick 		on = blkoff(fs, uio->uio_offset);
20651155Sbostic 		n = MIN((unsigned)(fs->lfs_bsize - on), uio->uio_resid);
20739608Smckusick 		diff = ip->i_size - uio->uio_offset;
20839608Smckusick 		if (diff <= 0)
20939608Smckusick 			return (0);
21039608Smckusick 		if (diff < n)
21139608Smckusick 			n = diff;
21251155Sbostic 		size = blksize(fs);				/* LFS */
21339674Smckusick 		rablock = lbn + 1;
21439896Smckusick 		if (vp->v_lastr + 1 == lbn &&
21539896Smckusick 		    lblktosize(fs, rablock) < ip->i_size)
21652195Smckusick 			error = breadn(ITOV(ip), lbn, size, &rablock,
21752195Smckusick 				&size, 1, NOCRED, &bp);
21839608Smckusick 		else
21939674Smckusick 			error = bread(ITOV(ip), lbn, size, NOCRED, &bp);
22039815Smckusick 		vp->v_lastr = lbn;
22139608Smckusick 		n = MIN(n, size - bp->b_resid);
22239608Smckusick 		if (error) {
22339608Smckusick 			brelse(bp);
22439608Smckusick 			return (error);
22539608Smckusick 		}
22639608Smckusick 		error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
22751155Sbostic 		if (n + on == fs->lfs_bsize || uio->uio_offset == ip->i_size)
22839608Smckusick 			bp->b_flags |= B_AGE;
22939608Smckusick 		brelse(bp);
23039608Smckusick 	} while (error == 0 && uio->uio_resid > 0 && n != 0);
23139608Smckusick 	return (error);
23239608Smckusick }
23339608Smckusick 
23439608Smckusick /*
23539608Smckusick  * Vnode op for writing.
23639608Smckusick  */
23751134Sbostic lfs_write(vp, uio, ioflag, cred)
23839608Smckusick 	register struct vnode *vp;
23939608Smckusick 	struct uio *uio;
24039608Smckusick 	int ioflag;
24139608Smckusick 	struct ucred *cred;
24239608Smckusick {
24348039Smckusick 	struct proc *p = uio->uio_procp;
24439608Smckusick 	register struct inode *ip = VTOI(vp);
24552091Sbostic 	register struct lfs *fs;
24639608Smckusick 	struct buf *bp;
24752091Sbostic 	daddr_t lbn;
24853233Smckusick 	off_t osize;
24952091Sbostic 	int n, on, flags, newblock;
25045722Smckusick 	int size, resid, error = 0;
25139608Smckusick 
25251852Sbostic #ifdef VERBOSE
25351852Sbostic 	printf("lfs_write ino %d\n", ip->i_number);
25451852Sbostic #endif
25548039Smckusick #ifdef DIAGNOSTIC
25639608Smckusick 	if (uio->uio_rw != UIO_WRITE)
25752091Sbostic 		panic("lfs_write mode");
25848039Smckusick #endif
25939608Smckusick 	switch (vp->v_type) {
26039608Smckusick 	case VREG:
26139608Smckusick 		if (ioflag & IO_APPEND)
26239608Smckusick 			uio->uio_offset = ip->i_size;
26339608Smckusick 		/* fall through */
26439608Smckusick 	case VLNK:
26539608Smckusick 		break;
26639608Smckusick 
26739608Smckusick 	case VDIR:
26852091Sbostic 		/* XXX This may not be correct for LFS. */
26939608Smckusick 		if ((ioflag & IO_SYNC) == 0)
27052091Sbostic 			panic("lfs_write nonsync dir write");
27139608Smckusick 		break;
27239608Smckusick 
27339608Smckusick 	default:
27452091Sbostic 		panic("lfs_write type");
27539608Smckusick 	}
27639608Smckusick 	if (uio->uio_offset < 0)
27739608Smckusick 		return (EINVAL);
27839608Smckusick 	if (uio->uio_resid == 0)
27939608Smckusick 		return (0);
28039608Smckusick 	/*
28139608Smckusick 	 * Maybe this should be above the vnode op call, but so long as
28239608Smckusick 	 * file servers have no limits, i don't think it matters
28339608Smckusick 	 */
28449679Smckusick 	if (vp->v_type == VREG && p &&
28539608Smckusick 	    uio->uio_offset + uio->uio_resid >
28647571Skarels 	      p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
28747571Skarels 		psignal(p, SIGXFSZ);
28839608Smckusick 		return (EFBIG);
28939608Smckusick 	}
29039608Smckusick 	resid = uio->uio_resid;
29139608Smckusick 	osize = ip->i_size;
29251183Sbostic 	fs = ip->i_lfs;						/* LFS */
29339674Smckusick 	flags = 0;
29451183Sbostic #ifdef NOTLFS
29539674Smckusick 	if (ioflag & IO_SYNC)
29639674Smckusick 		flags = B_SYNC;
29751183Sbostic #endif
29839608Smckusick 	do {
29939608Smckusick 		lbn = lblkno(fs, uio->uio_offset);
30051932Sbostic 		on = blkoff(fs, uio->uio_offset);
30151183Sbostic 		n = MIN((unsigned)(fs->lfs_bsize - on), uio->uio_resid);
30252091Sbostic 		if (error = lfs_balloc(vp, n, lbn, &bp))
30339608Smckusick 			break;
30445722Smckusick 		if (uio->uio_offset + n > ip->i_size) {
30539608Smckusick 			ip->i_size = uio->uio_offset + n;
30652019Smckusick 			vnode_pager_setsize(vp, (u_long)ip->i_size);
30745722Smckusick 		}
30851183Sbostic 		size = blksize(fs);
30945722Smckusick 		(void) vnode_pager_uncache(vp);
31039608Smckusick 		n = MIN(n, size - bp->b_resid);
31139608Smckusick 		error = uiomove(bp->b_un.b_addr + on, n, uio);
31251183Sbostic #ifdef NOTLFS							/* LFS */
31339608Smckusick 		if (ioflag & IO_SYNC)
31439608Smckusick 			(void) bwrite(bp);
31539608Smckusick 		else if (n + on == fs->fs_bsize) {
31639608Smckusick 			bp->b_flags |= B_AGE;
31739608Smckusick 			bawrite(bp);
31839608Smckusick 		} else
31939608Smckusick 			bdwrite(bp);
32052091Sbostic 		ip->i_flag |= IUPD|ICHG;
32151183Sbostic #else
32252091Sbostic 		/* XXX This doesn't handle IO_SYNC. */
32352091Sbostic 		LFS_UBWRITE(bp);
32451183Sbostic #endif
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)) {
32953242Smckusick 		(void)lfs_truncate(vp, osize, ioflag & IO_SYNC, cred);
33039608Smckusick 		uio->uio_offset -= resid - uio->uio_resid;
33139608Smckusick 		uio->uio_resid = resid;
33239608Smckusick 	}
33342493Smckusick 	if (!error && (ioflag & IO_SYNC))
33451932Sbostic 		error = lfs_update(vp, &time, &time, 1);
33539608Smckusick 	return (error);
33639608Smckusick }
33739608Smckusick 
3389167Ssam /*
33937737Smckusick  * Synch an open file.
3409167Ssam  */
34137737Smckusick /* ARGSUSED */
34251134Sbostic lfs_fsync(vp, fflags, cred, waitfor, p)
34337737Smckusick 	struct vnode *vp;
34437737Smckusick 	int fflags;
34537737Smckusick 	struct ucred *cred;
34639597Smckusick 	int waitfor;
34748039Smckusick 	struct proc *p;
3487701Ssam {
34951852Sbostic 	struct inode *ip;
3507701Ssam 
35151852Sbostic #ifdef VERBOSE
35251852Sbostic 	printf("lfs_fsync\n");
35351852Sbostic #endif
35451852Sbostic 	ip = VTOI(vp);
35548039Smckusick 	if (fflags & FWRITE)
35637737Smckusick 		ip->i_flag |= ICHG;
35752329Sbostic 	return (lfs_update(vp, &time, &time, waitfor == MNT_WAIT));
35837737Smckusick }
35951558Smckusick 
36051558Smckusick /*
36151558Smckusick  * Last reference to an inode, write the inode out and if necessary,
36251558Smckusick  * truncate and deallocate the file.
36351558Smckusick  */
36451558Smckusick int
36551558Smckusick lfs_inactive(vp, p)
36651558Smckusick 	struct vnode *vp;
36751558Smckusick 	struct proc *p;
36851558Smckusick {
36951852Sbostic 	extern int prtactive;
37051558Smckusick 	register struct inode *ip;
37151558Smckusick 	int mode, error;
37251558Smckusick 
37351852Sbostic #ifdef VERBOSE
37451852Sbostic 	printf("lfs_inactive\n");
37551852Sbostic #endif
37651558Smckusick 	if (prtactive && vp->v_usecount != 0)
37751558Smckusick 		vprint("lfs_inactive: pushing active", vp);
37851558Smckusick 
37951558Smckusick 	/* Get rid of inodes related to stale file handles. */
38051558Smckusick 	ip = VTOI(vp);
38151558Smckusick 	if (ip->i_mode == 0) {
38251558Smckusick 		if ((vp->v_flag & VXLOCK) == 0)
38351558Smckusick 			vgone(vp);
38451558Smckusick 		return (0);
38551558Smckusick 	}
38651558Smckusick 
38751558Smckusick 	error = 0;
38851558Smckusick 	ILOCK(ip);
38951558Smckusick 	if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
39051558Smckusick #ifdef QUOTA
39151558Smckusick 		if (!getinoquota(ip))
39251558Smckusick 			(void)chkiq(ip, -1, NOCRED, 0);
39351558Smckusick #endif
39453242Smckusick 		error = lfs_truncate(vp, (off_t)0, 0, NOCRED);
39551558Smckusick 		mode = ip->i_mode;
39651558Smckusick 		ip->i_mode = 0;
39751558Smckusick 		ip->i_rdev = 0;
39851558Smckusick 		ip->i_flag |= IUPD|ICHG;
39951558Smckusick 		lfs_vfree(vp, ip->i_number, mode);
40051558Smckusick 	}
40151558Smckusick 	if (ip->i_flag&(IUPD|IACC|ICHG|IMOD))
40251558Smckusick 		lfs_update(vp, &time, &time, 0);
40351558Smckusick 	IUNLOCK(ip);
40451558Smckusick 	ip->i_flag = 0;
40551558Smckusick 	/*
40651558Smckusick 	 * If we are done with the inode, reclaim it
40751558Smckusick 	 * so that it can be reused immediately.
40851558Smckusick 	 */
40951558Smckusick 	if (vp->v_usecount == 0 && ip->i_mode == 0)
41051558Smckusick 		vgone(vp);
41151558Smckusick 	return (error);
41251558Smckusick }
413