xref: /csrg-svn/sys/ufs/ffs/ufs_readwrite.c (revision 64412)
1*64412Smckusick /*-
2*64412Smckusick  * Copyright (c) 1993 The Regents of the University of California.
3*64412Smckusick  * All rights reserved.
4*64412Smckusick  *
5*64412Smckusick  * %sccs.include.redist.c%
6*64412Smckusick  *
7*64412Smckusick  *	@(#)ufs_readwrite.c	8.1 (Berkeley) 09/05/93
8*64412Smckusick  */
9*64412Smckusick 
10*64412Smckusick #ifdef LFS_READWRITE
11*64412Smckusick #define	BLKSIZE(a, b, c)	blksize(a)
12*64412Smckusick #define	FS			struct lfs
13*64412Smckusick #define	I_FS			i_lfs
14*64412Smckusick #define	READ			lfs_read
15*64412Smckusick #define	WRITE			lfs_write
16*64412Smckusick #define	fs_bsize		lfs_bsize
17*64412Smckusick #define	fs_maxfilesize		lfs_maxfilesize
18*64412Smckusick #else
19*64412Smckusick #define	BLKSIZE(a, b, c)	blksize(a, b, c)
20*64412Smckusick #define	FS			struct fs
21*64412Smckusick #define	I_FS			i_fs
22*64412Smckusick #define	READ			ffs_read
23*64412Smckusick #define	WRITE			ffs_write
24*64412Smckusick #endif
25*64412Smckusick 
26*64412Smckusick /*
27*64412Smckusick  * Vnode op for reading.
28*64412Smckusick  */
29*64412Smckusick /* ARGSUSED */
30*64412Smckusick READ(ap)
31*64412Smckusick 	struct vop_read_args /* {
32*64412Smckusick 		struct vnode *a_vp;
33*64412Smckusick 		struct uio *a_uio;
34*64412Smckusick 		int a_ioflag;
35*64412Smckusick 		struct ucred *a_cred;
36*64412Smckusick 	} */ *ap;
37*64412Smckusick {
38*64412Smckusick 	register struct vnode *vp;
39*64412Smckusick 	register struct inode *ip;
40*64412Smckusick 	register struct uio *uio;
41*64412Smckusick 	register FS *fs;
42*64412Smckusick 	struct buf *bp;
43*64412Smckusick 	daddr_t lbn, nextlbn;
44*64412Smckusick 	off_t bytesinfile;
45*64412Smckusick 	long size, xfersize, blkoffset;
46*64412Smckusick 	int type, nextsize, error;
47*64412Smckusick 	u_short mode;
48*64412Smckusick 
49*64412Smckusick 	vp = ap->a_vp;
50*64412Smckusick 	ip = VTOI(vp);
51*64412Smckusick 	mode = ip->i_mode;
52*64412Smckusick 	uio = ap->a_uio;
53*64412Smckusick 
54*64412Smckusick #ifdef DIAGNOSTIC
55*64412Smckusick 	if (uio->uio_rw != UIO_READ)
56*64412Smckusick 		panic("%s: mode", READ);
57*64412Smckusick 
58*64412Smckusick 	if (vp->v_type == VLNK) {
59*64412Smckusick 		if ((int)ip->i_size < vp->v_mount->mnt_maxsymlinklen)
60*64412Smckusick 			panic("%s: short symlink", READ);
61*64412Smckusick 	} else if (vp->v_type != VREG && vp->v_type != VDIR)
62*64412Smckusick 		panic("%s: type", READ);
63*64412Smckusick #endif
64*64412Smckusick 	fs = ip->I_FS;
65*64412Smckusick 	if ((u_quad_t)uio->uio_offset > fs->fs_maxfilesize)
66*64412Smckusick 		return (EFBIG);
67*64412Smckusick 
68*64412Smckusick 	for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
69*64412Smckusick 		if ((bytesinfile = ip->i_size - uio->uio_offset) <= 0)
70*64412Smckusick 			break;
71*64412Smckusick 		lbn = lblkno(fs, uio->uio_offset);
72*64412Smckusick 		nextlbn = lbn + 1;
73*64412Smckusick 		size = BLKSIZE(fs, ip, lbn);
74*64412Smckusick 		blkoffset = blkoff(fs, uio->uio_offset);
75*64412Smckusick 		xfersize = fs->fs_bsize - blkoffset;
76*64412Smckusick 		if (uio->uio_resid < xfersize)
77*64412Smckusick 			xfersize = uio->uio_resid;
78*64412Smckusick 		if (bytesinfile < xfersize)
79*64412Smckusick 			xfersize = bytesinfile;
80*64412Smckusick 
81*64412Smckusick #ifdef LFS_READWRITE
82*64412Smckusick 		(void)lfs_check(vp, lbn);
83*64412Smckusick 		error = cluster_read(vp, ip->i_size, lbn, size, NOCRED, &bp);
84*64412Smckusick #else
85*64412Smckusick 		if (lblktosize(fs, nextlbn) > ip->i_size) {
86*64412Smckusick 			error = bread(vp, lbn, size, NOCRED, &bp);
87*64412Smckusick 		} else {
88*64412Smckusick 			if (doclusterread) {
89*64412Smckusick 				error = cluster_read(vp,
90*64412Smckusick 				    ip->i_size, lbn, size, NOCRED, &bp);
91*64412Smckusick 			} else if (lbn - 1 == vp->v_lastr) {
92*64412Smckusick 				nextsize = BLKSIZE(fs, ip, nextlbn);
93*64412Smckusick 				error = breadn(vp, lbn,
94*64412Smckusick 				    size, &nextlbn, &nextsize, 1, NOCRED, &bp);
95*64412Smckusick 			} else {
96*64412Smckusick 				error = bread(vp, lbn, size, NOCRED, &bp);
97*64412Smckusick 			}
98*64412Smckusick 		}
99*64412Smckusick #endif
100*64412Smckusick 		if (error)
101*64412Smckusick 			break;
102*64412Smckusick 		vp->v_lastr = lbn;
103*64412Smckusick 
104*64412Smckusick 		/*
105*64412Smckusick 		 * We should only get non-zero b_resid when an I/O error
106*64412Smckusick 		 * has occurred, which should cause us to break above.
107*64412Smckusick 		 * However, if the short read did not cause an error,
108*64412Smckusick 		 * then we want to ensure that we do not uiomove bad
109*64412Smckusick 		 * or uninitialized data.
110*64412Smckusick 		 */
111*64412Smckusick 		size -= bp->b_resid;
112*64412Smckusick 		if (size < xfersize) {
113*64412Smckusick 			if (size == 0)
114*64412Smckusick 				break;
115*64412Smckusick 			xfersize = size;
116*64412Smckusick 		}
117*64412Smckusick 		if (error =
118*64412Smckusick 		    uiomove(bp->b_un.b_addr + blkoffset, (int)xfersize, uio))
119*64412Smckusick 			break;
120*64412Smckusick 
121*64412Smckusick 		if (S_ISREG(mode) && (xfersize + blkoffset == fs->fs_bsize ||
122*64412Smckusick 		    uio->uio_offset == ip->i_size))
123*64412Smckusick 			bp->b_flags |= B_AGE;
124*64412Smckusick 		brelse(bp);
125*64412Smckusick 	}
126*64412Smckusick 	if (bp != NULL)
127*64412Smckusick 		brelse(bp);
128*64412Smckusick 	ip->i_flag |= IACC;
129*64412Smckusick 	return (error);
130*64412Smckusick }
131*64412Smckusick 
132*64412Smckusick /*
133*64412Smckusick  * Vnode op for writing.
134*64412Smckusick  */
135*64412Smckusick WRITE(ap)
136*64412Smckusick 	struct vop_write_args /* {
137*64412Smckusick 		struct vnode *a_vp;
138*64412Smckusick 		struct uio *a_uio;
139*64412Smckusick 		int a_ioflag;
140*64412Smckusick 		struct ucred *a_cred;
141*64412Smckusick 	} */ *ap;
142*64412Smckusick {
143*64412Smckusick 	register struct vnode *vp;
144*64412Smckusick 	register struct uio *uio;
145*64412Smckusick 	register struct inode *ip;
146*64412Smckusick 	register FS *fs;
147*64412Smckusick 	struct buf *bp;
148*64412Smckusick 	struct proc *p;
149*64412Smckusick 	daddr_t lbn;
150*64412Smckusick 	off_t osize;
151*64412Smckusick 	int blkoffset, error, flags, ioflag, newblock, resid, size, xfersize;
152*64412Smckusick 
153*64412Smckusick 	ioflag = ap->a_ioflag;
154*64412Smckusick 	uio = ap->a_uio;
155*64412Smckusick 	vp = ap->a_vp;
156*64412Smckusick 	ip = VTOI(vp);
157*64412Smckusick 
158*64412Smckusick #ifdef DIAGNOSTIC
159*64412Smckusick 	if (uio->uio_rw != UIO_WRITE)
160*64412Smckusick 		panic("%s: mode", WRITE);
161*64412Smckusick #endif
162*64412Smckusick 
163*64412Smckusick 	switch (vp->v_type) {
164*64412Smckusick 	case VREG:
165*64412Smckusick 		if (ioflag & IO_APPEND)
166*64412Smckusick 			uio->uio_offset = ip->i_size;
167*64412Smckusick 		if ((ip->i_flags & APPEND) && uio->uio_offset != ip->i_size)
168*64412Smckusick 			return (EPERM);
169*64412Smckusick 		/* FALLTHROUGH */
170*64412Smckusick 	case VLNK:
171*64412Smckusick 		break;
172*64412Smckusick 	case VDIR:
173*64412Smckusick 		if ((ioflag & IO_SYNC) == 0)
174*64412Smckusick 			panic("%s: nonsync dir write", WRITE);
175*64412Smckusick 		break;
176*64412Smckusick 	default:
177*64412Smckusick 		panic("%s: type", WRITE);
178*64412Smckusick 	}
179*64412Smckusick 
180*64412Smckusick 	fs = ip->I_FS;
181*64412Smckusick 	if (uio->uio_offset < 0 ||
182*64412Smckusick 	    (u_quad_t)uio->uio_offset + uio->uio_resid > fs->fs_maxfilesize)
183*64412Smckusick 		return (EFBIG);
184*64412Smckusick 	/*
185*64412Smckusick 	 * Maybe this should be above the vnode op call, but so long as
186*64412Smckusick 	 * file servers have no limits, I don't think it matters.
187*64412Smckusick 	 */
188*64412Smckusick 	p = uio->uio_procp;
189*64412Smckusick 	if (vp->v_type == VREG && p &&
190*64412Smckusick 	    uio->uio_offset + uio->uio_resid >
191*64412Smckusick 	    p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
192*64412Smckusick 		psignal(p, SIGXFSZ);
193*64412Smckusick 		return (EFBIG);
194*64412Smckusick 	}
195*64412Smckusick 
196*64412Smckusick 	resid = uio->uio_resid;
197*64412Smckusick 	osize = ip->i_size;
198*64412Smckusick 	flags = ioflag & IO_SYNC ? B_SYNC : 0;
199*64412Smckusick 
200*64412Smckusick 	for (error = 0; uio->uio_resid > 0;) {
201*64412Smckusick 		lbn = lblkno(fs, uio->uio_offset);
202*64412Smckusick 		blkoffset = blkoff(fs, uio->uio_offset);
203*64412Smckusick 		xfersize = fs->fs_bsize - blkoffset;
204*64412Smckusick 		if (uio->uio_resid < xfersize)
205*64412Smckusick 			xfersize = uio->uio_resid;
206*64412Smckusick #ifdef LFS_READWRITE
207*64412Smckusick 		(void)lfs_check(vp, lbn);
208*64412Smckusick 		error = lfs_balloc(vp, xfersize, lbn, &bp);
209*64412Smckusick #else
210*64412Smckusick 		if (fs->fs_bsize > xfersize)
211*64412Smckusick 			flags |= B_CLRBUF;
212*64412Smckusick 		else
213*64412Smckusick 			flags &= ~B_CLRBUF;
214*64412Smckusick 
215*64412Smckusick 		error = ffs_balloc(ip,
216*64412Smckusick 		    lbn, blkoffset + xfersize, ap->a_cred, &bp, flags);
217*64412Smckusick #endif
218*64412Smckusick 		if (error)
219*64412Smckusick 			break;
220*64412Smckusick 		if (uio->uio_offset + xfersize > ip->i_size) {
221*64412Smckusick 			ip->i_size = uio->uio_offset + xfersize;
222*64412Smckusick 			vnode_pager_setsize(vp, (u_long)ip->i_size);
223*64412Smckusick 		}
224*64412Smckusick 		(void)vnode_pager_uncache(vp);
225*64412Smckusick 
226*64412Smckusick 		size = BLKSIZE(fs, ip, lbn) - bp->b_resid;
227*64412Smckusick 		if (size < xfersize)
228*64412Smckusick 			xfersize = size;
229*64412Smckusick 
230*64412Smckusick 		error =
231*64412Smckusick 		    uiomove(bp->b_un.b_addr + blkoffset, (int)xfersize, uio);
232*64412Smckusick #ifdef LFS_READWRITE
233*64412Smckusick 		(void)VOP_BWRITE(bp);
234*64412Smckusick #else
235*64412Smckusick 		if (ioflag & IO_SYNC)
236*64412Smckusick 			(void)bwrite(bp);
237*64412Smckusick 		else if (xfersize + blkoffset == fs->fs_bsize)
238*64412Smckusick 			if (doclusterwrite)
239*64412Smckusick 				cluster_write(bp, ip->i_size);
240*64412Smckusick 			else {
241*64412Smckusick 				bp->b_flags |= B_AGE;
242*64412Smckusick 				bawrite(bp);
243*64412Smckusick 			}
244*64412Smckusick 		else
245*64412Smckusick 			bdwrite(bp);
246*64412Smckusick #endif
247*64412Smckusick 		if (error || xfersize == 0)
248*64412Smckusick 			break;
249*64412Smckusick 		ip->i_flag |= IUPD | ICHG;
250*64412Smckusick 	}
251*64412Smckusick 	/*
252*64412Smckusick 	 * If we successfully wrote any data, and we are not the superuser
253*64412Smckusick 	 * we clear the setuid and setgid bits as a precaution against
254*64412Smckusick 	 * tampering.
255*64412Smckusick 	 */
256*64412Smckusick 	if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0)
257*64412Smckusick 		ip->i_mode &= ~(ISUID | ISGID);
258*64412Smckusick 	if (error) {
259*64412Smckusick 		if (ioflag & IO_UNIT) {
260*64412Smckusick 			(void)VOP_TRUNCATE(vp, osize,
261*64412Smckusick 			    ioflag & IO_SYNC, ap->a_cred, uio->uio_procp);
262*64412Smckusick 			uio->uio_offset -= resid - uio->uio_resid;
263*64412Smckusick 			uio->uio_resid = resid;
264*64412Smckusick 		}
265*64412Smckusick 	} else if (resid > uio->uio_resid && (ioflag & IO_SYNC))
266*64412Smckusick 		error = VOP_UPDATE(vp, &time, &time, 1);
267*64412Smckusick 	return (error);
268*64412Smckusick }
269