コード例 #1
0
ファイル: nwfs_vnops.c プロジェクト: mihaicarabas/dragonfly
/*
 * nwfs_setattr call from vfs.
 *
 * nwfs_setattr(struct vnode *a_vp, struct vattr *a_vap, struct ucred *a_cred)
 */
static int
nwfs_setattr(struct vop_setattr_args *ap)
{
	thread_t td = curthread; /* XXX */
	struct vnode *vp = ap->a_vp;
	struct nwnode *np = VTONW(vp);
	struct vattr *vap = ap->a_vap;
	u_quad_t tsize=0;
	int error = 0;

	NCPVNDEBUG("\n");
	if (vap->va_flags != VNOVAL)
		return (EOPNOTSUPP);
	/*
	 * Disallow write attempts if the filesystem is mounted read-only.
	 */
  	if ((vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL || 
	     vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
	     vap->va_mode != (mode_t)VNOVAL) &&(vp->v_mount->mnt_flag & MNT_RDONLY))
		return (EROFS);
	if (vap->va_size != VNOVAL) {
 		switch (vp->v_type) {
 		case VDIR:
 			return (EISDIR);
 		case VREG:
			/*
			 * Disallow write attempts if the filesystem is
			 * mounted read-only.
			 */
			if (vp->v_mount->mnt_flag & MNT_RDONLY)
				return (EROFS);
			vnode_pager_setsize(vp, (u_long)vap->va_size);
 			tsize = np->n_size;
 			np->n_size = vap->va_size;
			break;
 		default:
			return EINVAL;
  		}
  	}
	error = ncp_setattr(vp, vap, ap->a_cred, td);
	if (error && vap->va_size != VNOVAL) {
		np->n_size = tsize;
		vnode_pager_setsize(vp, (u_long)tsize);
	}
	np->n_atime = 0;	/* invalidate cache */
	VOP_GETATTR(vp, vap);
	np->n_mtime = vap->va_mtime.tv_sec;
	return (0);
}
コード例 #2
0
ファイル: smbfs_io.c プロジェクト: ChaosJohn/freebsd
int
smbfs_writevnode(struct vnode *vp, struct uio *uiop,
	struct ucred *cred, int ioflag)
{
	struct smbmount *smp = VTOSMBFS(vp);
	struct smbnode *np = VTOSMB(vp);
	struct smb_cred *scred;
	struct thread *td;
	int error = 0;

	if (vp->v_type != VREG) {
		SMBERROR("vn types other than VREG unsupported !\n");
		return EIO;
	}
	SMBVDEBUG("ofs=%jd,resid=%zd\n", (intmax_t)uiop->uio_offset, 
	    uiop->uio_resid);
	if (uiop->uio_offset < 0)
		return EINVAL;
/*	if (uiop->uio_offset + uiop->uio_resid > smp->nm_maxfilesize)
		return (EFBIG);*/
	td = uiop->uio_td;
	if (ioflag & (IO_APPEND | IO_SYNC)) {
		if (np->n_flag & NMODIFIED) {
			smbfs_attr_cacheremove(vp);
			error = smbfs_vinvalbuf(vp, td);
			if (error)
				return error;
		}
		if (ioflag & IO_APPEND) {
#ifdef notyet
			/*
			 * File size can be changed by another client
			 */
			smbfs_attr_cacheremove(vp);
			error = VOP_GETATTR(vp, &vattr, cred);
			if (error) return (error);
#endif
			uiop->uio_offset = np->n_size;
		}
	}
	if (uiop->uio_resid == 0)
		return 0;

	if (vn_rlimit_fsize(vp, uiop, td))
		return (EFBIG);
	
	scred = smbfs_malloc_scred();
	smb_makescred(scred, td, cred);
	error = smb_write(smp->sm_share, np->n_fid, uiop, scred);
	smbfs_free_scred(scred);
	SMBVDEBUG("after: ofs=%jd,resid=%zd\n", (intmax_t)uiop->uio_offset, 
	    uiop->uio_resid);
	if (!error) {
		if (uiop->uio_offset > np->n_size) {
			np->n_size = uiop->uio_offset;
			vnode_pager_setsize(vp, np->n_size);
		}
	}
	return error;
}
コード例 #3
0
int
smbfs_writevnode(struct vnode *vp, struct uio *uiop,
		 struct ucred *cred, int ioflag)
{
	struct thread *td;
	struct smbmount *smp = VTOSMBFS(vp);
	struct smbnode *np = VTOSMB(vp);
	struct smb_cred scred;
	int error = 0;

	if (vp->v_type != VREG) {
		SMBERROR("vn types other than VREG unsupported !\n");
		return EIO;
	}
	SMBVDEBUG("ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid);
	if (uiop->uio_offset < 0)
		return EINVAL;
	td = uiop->uio_td;
	if (ioflag & (IO_APPEND | IO_SYNC)) {
		if (np->n_flag & NMODIFIED) {
			smbfs_attr_cacheremove(vp);
			error = smbfs_vinvalbuf(vp, V_SAVE, 1);
			if (error)
				return error;
		}
		if (ioflag & IO_APPEND) {
#if 0 /* notyet */
			/*
			 * File size can be changed by another client
			 */
			smbfs_attr_cacheremove(vp);
			error = VOP_GETATTR(vp, &vattr);
			if (error) return (error);
#endif
			uiop->uio_offset = np->n_size;
		}
	}
	if (uiop->uio_resid == 0)
		return 0;
	if (td->td_proc &&
	    uiop->uio_offset + uiop->uio_resid >
	    td->td_proc->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
		lwpsignal(td->td_proc, td->td_lwp, SIGXFSZ);
		return EFBIG;
	}
	smb_makescred(&scred, td, cred);
	error = smb_write(smp->sm_share, np->n_fid, uiop, &scred);
	SMBVDEBUG("after: ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid);
	if (!error) {
		if (uiop->uio_offset > np->n_size) {
			np->n_size = uiop->uio_offset;
			vnode_pager_setsize(vp, np->n_size);
		}
	}
	return error;
}
コード例 #4
0
ファイル: nwfs_io.c プロジェクト: mihaicarabas/dragonfly
int
nwfs_writevnode(struct vnode *vp, struct uio *uiop, struct ucred *cred,
		int ioflag)
{
	struct nwmount *nmp = VTONWFS(vp);
	struct nwnode *np = VTONW(vp);
	struct thread *td;
/*	struct vattr vattr;*/
	int error = 0;

	if (vp->v_type != VREG) {
		kprintf("%s: vn types other than VREG unsupported !\n",__func__);
		return EIO;
	}
	NCPVNDEBUG("ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid);
	if (uiop->uio_offset < 0) return EINVAL;
	td = uiop->uio_td;
	if (ioflag & (IO_APPEND | IO_SYNC)) {
		if (np->n_flag & NMODIFIED) {
			nwfs_attr_cacheremove(vp);
			error = nwfs_vinvalbuf(vp, V_SAVE, 1);
			if (error) return (error);
		}
		if (ioflag & IO_APPEND) {
		/* We can relay only on local information about file size,
		 * because until file is closed NetWare will not return
		 * the correct size. */
#if 0 /* notyet */
			nwfs_attr_cacheremove(vp);
			error = VOP_GETATTR(vp, &vattr);
			if (error) return (error);
#endif
			uiop->uio_offset = np->n_size;
		}
	}
	if (uiop->uio_resid == 0) return 0;
	if (td->td_proc && uiop->uio_offset + uiop->uio_resid > 
	    td->td_proc->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
		lwpsignal(td->td_proc, td->td_lwp, SIGXFSZ);
		return (EFBIG);
	}
	error = ncp_write(NWFSTOCONN(nmp), &np->n_fh, uiop, cred);
	NCPVNDEBUG("after: ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid);
	if (!error) {
		if (uiop->uio_offset > np->n_size) {
			np->n_vattr.va_size = np->n_size = uiop->uio_offset;
			vnode_pager_setsize(vp, np->n_size);
		}
	}
	return (error);
}
コード例 #5
0
ファイル: fuse_node.c プロジェクト: FreeBSDFoundation/freebsd
int
fuse_vnode_setsize(struct vnode *vp, struct ucred *cred, off_t newsize)
{
	struct fuse_vnode_data *fvdat = VTOFUD(vp);
	off_t oldsize;
	int err = 0;

	ASSERT_VOP_ELOCKED(vp, "fuse_vnode_setsize");

	oldsize = fvdat->filesize;
	fvdat->filesize = newsize;
	fvdat->flag |= FN_SIZECHANGE;

	if (newsize < oldsize) {
		err = vtruncbuf(vp, cred, newsize, fuse_iosize(vp));
	}
	vnode_pager_setsize(vp, newsize);
	return err;
}
コード例 #6
0
int
fuse_vnode_setsize(struct vnode *vp, struct ucred *cred, off_t newsize)
{
	struct fuse_vnode_data *fvdat = VTOFUD(vp);
	off_t oldsize;
	int err = 0;

	FS_DEBUG("inode=%ju oldsize=%ju newsize=%ju\n",
	    (uintmax_t)VTOI(vp), (uintmax_t)fvdat->filesize,
	    (uintmax_t)newsize);
	ASSERT_VOP_ELOCKED(vp, "fuse_vnode_setsize");

	oldsize = fvdat->filesize;
	fvdat->filesize = newsize;
	fvdat->flag |= FN_SIZECHANGE;

	if (newsize < oldsize) {
		err = vtruncbuf(vp, cred, newsize, fuse_iosize(vp));
	}
	vnode_pager_setsize(vp, newsize);
	fuse_invalidate_attr(vp);

	return err;
}
コード例 #7
0
ファイル: msdosfs_denode.c プロジェクト: 2asoft/freebsd
/*
 * Truncate the file described by dep to the length specified by length.
 */
int
detrunc(struct denode *dep, u_long length, int flags, struct ucred *cred)
{
	int error;
	int allerror;
	u_long eofentry;
	u_long chaintofree;
	daddr_t bn;
	int boff;
	int isadir = dep->de_Attributes & ATTR_DIRECTORY;
	struct buf *bp;
	struct msdosfsmount *pmp = dep->de_pmp;

#ifdef MSDOSFS_DEBUG
	printf("detrunc(): file %s, length %lu, flags %x\n", dep->de_Name, length, flags);
#endif

	/*
	 * Disallow attempts to truncate the root directory since it is of
	 * fixed size.  That's just the way dos filesystems are.  We use
	 * the VROOT bit in the vnode because checking for the directory
	 * bit and a startcluster of 0 in the denode is not adequate to
	 * recognize the root directory at this point in a file or
	 * directory's life.
	 */
	if ((DETOV(dep)->v_vflag & VV_ROOT) && !FAT32(pmp)) {
#ifdef MSDOSFS_DEBUG
		printf("detrunc(): can't truncate root directory, clust %ld, offset %ld\n",
		    dep->de_dirclust, dep->de_diroffset);
#endif
		return (EINVAL);
	}

	if (dep->de_FileSize < length) {
		vnode_pager_setsize(DETOV(dep), length);
		return deextend(dep, length, cred);
	}

	/*
	 * If the desired length is 0 then remember the starting cluster of
	 * the file and set the StartCluster field in the directory entry
	 * to 0.  If the desired length is not zero, then get the number of
	 * the last cluster in the shortened file.  Then get the number of
	 * the first cluster in the part of the file that is to be freed.
	 * Then set the next cluster pointer in the last cluster of the
	 * file to CLUST_EOFE.
	 */
	if (length == 0) {
		chaintofree = dep->de_StartCluster;
		dep->de_StartCluster = 0;
		eofentry = ~0;
	} else {
		error = pcbmap(dep, de_clcount(pmp, length) - 1, 0, 
			       &eofentry, 0);
		if (error) {
#ifdef MSDOSFS_DEBUG
			printf("detrunc(): pcbmap fails %d\n", error);
#endif
			return (error);
		}
	}

	fc_purge(dep, de_clcount(pmp, length));

	/*
	 * If the new length is not a multiple of the cluster size then we
	 * must zero the tail end of the new last cluster in case it
	 * becomes part of the file again because of a seek.
	 */
	if ((boff = length & pmp->pm_crbomask) != 0) {
		if (isadir) {
			bn = cntobn(pmp, eofentry);
			error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
			    NOCRED, &bp);
			if (error) {
				brelse(bp);
#ifdef MSDOSFS_DEBUG
				printf("detrunc(): bread fails %d\n", error);
#endif
				return (error);
			}
			bzero(bp->b_data + boff, pmp->pm_bpcluster - boff);
			if (flags & IO_SYNC)
				bwrite(bp);
			else
				bdwrite(bp);
		}
	}

	/*
	 * Write out the updated directory entry.  Even if the update fails
	 * we free the trailing clusters.
	 */
	dep->de_FileSize = length;
	if (!isadir)
		dep->de_flag |= DE_UPDATE | DE_MODIFIED;
	allerror = vtruncbuf(DETOV(dep), cred, length, pmp->pm_bpcluster);
#ifdef MSDOSFS_DEBUG
	if (allerror)
		printf("detrunc(): vtruncbuf error %d\n", allerror);
#endif
	error = deupdat(dep, !DOINGASYNC((DETOV(dep))));
	if (error != 0 && allerror == 0)
		allerror = error;
#ifdef MSDOSFS_DEBUG
	printf("detrunc(): allerror %d, eofentry %lu\n",
	       allerror, eofentry);
#endif

	/*
	 * If we need to break the cluster chain for the file then do it
	 * now.
	 */
	if (eofentry != ~0) {
		error = fatentry(FAT_GET_AND_SET, pmp, eofentry,
				 &chaintofree, CLUST_EOFE);
		if (error) {
#ifdef MSDOSFS_DEBUG
			printf("detrunc(): fatentry errors %d\n", error);
#endif
			return (error);
		}
		fc_setcache(dep, FC_LASTFC, de_cluster(pmp, length - 1),
			    eofentry);
	}

	/*
	 * Now free the clusters removed from the file because of the
	 * truncation.
	 */
	if (chaintofree != 0 && !MSDOSFSEOF(pmp, chaintofree))
		freeclusterchain(pmp, chaintofree);

	return (allerror);
}
コード例 #8
0
ファイル: ext2_inode.c プロジェクト: JasonFord53/freebsd
/*
 * Truncate the inode oip to at most length size, freeing the
 * disk blocks.
 */
int
ext2_truncate(struct vnode *vp, off_t length, int flags, struct ucred *cred,
    struct thread *td)
{
	struct vnode *ovp = vp;
	int32_t lastblock;
	struct inode *oip;
	int32_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR];
	uint32_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR];
	struct m_ext2fs *fs;
	struct buf *bp;
	int offset, size, level;
	e4fs_daddr_t count, nblocks, blocksreleased = 0;
	int error, i, allerror;
	off_t osize;
#ifdef INVARIANTS
	struct bufobj *bo;
#endif

	oip = VTOI(ovp);
#ifdef INVARIANTS
	bo = &ovp->v_bufobj;
#endif

	ASSERT_VOP_LOCKED(vp, "ext2_truncate");	

	if (length < 0)
	    return (EINVAL);

	if (ovp->v_type == VLNK &&
	    oip->i_size < ovp->v_mount->mnt_maxsymlinklen) {
#ifdef INVARIANTS
		if (length != 0)
			panic("ext2_truncate: partial truncate of symlink");
#endif
		bzero((char *)&oip->i_shortlink, (u_int)oip->i_size);
		oip->i_size = 0;
		oip->i_flag |= IN_CHANGE | IN_UPDATE;
		return (ext2_update(ovp, 1));
	}
	if (oip->i_size == length) {
		oip->i_flag |= IN_CHANGE | IN_UPDATE;
		return (ext2_update(ovp, 0));
	}
	fs = oip->i_e2fs;
	osize = oip->i_size;
	/*
	 * Lengthen the size of the file. We must ensure that the
	 * last byte of the file is allocated. Since the smallest
	 * value of osize is 0, length will be at least 1.
	 */
	if (osize < length) {
		if (length > oip->i_e2fs->e2fs_maxfilesize)
			return (EFBIG);
		vnode_pager_setsize(ovp, length);
		offset = blkoff(fs, length - 1);
		lbn = lblkno(fs, length - 1);
		flags |= BA_CLRBUF;
		error = ext2_balloc(oip, lbn, offset + 1, cred, &bp, flags);
		if (error) {
			vnode_pager_setsize(vp, osize);
			return (error);
		}
		oip->i_size = length;
		if (bp->b_bufsize == fs->e2fs_bsize)
			bp->b_flags |= B_CLUSTEROK;
		if (flags & IO_SYNC)
			bwrite(bp);
		else if (DOINGASYNC(ovp))
			bdwrite(bp);
		else
			bawrite(bp);
		oip->i_flag |= IN_CHANGE | IN_UPDATE;
		return (ext2_update(ovp, !DOINGASYNC(ovp)));
	}
	/*
	 * Shorten the size of the file. If the file is not being
	 * truncated to a block boundry, the contents of the
	 * partial block following the end of the file must be
	 * zero'ed in case it ever become accessible again because
	 * of subsequent file growth.
	 */
	/* I don't understand the comment above */
	offset = blkoff(fs, length);
	if (offset == 0) {
		oip->i_size = length;
	} else {
		lbn = lblkno(fs, length);
		flags |= BA_CLRBUF;
		error = ext2_balloc(oip, lbn, offset, cred, &bp, flags);
		if (error)
			return (error);
		oip->i_size = length;
		size = blksize(fs, oip, lbn);
		bzero((char *)bp->b_data + offset, (u_int)(size - offset));
		allocbuf(bp, size);
		if (bp->b_bufsize == fs->e2fs_bsize)
			bp->b_flags |= B_CLUSTEROK;
		if (flags & IO_SYNC)
			bwrite(bp);
		else if (DOINGASYNC(ovp))
			bdwrite(bp);
		else
			bawrite(bp);
	}
	/*
	 * Calculate index into inode's block list of
	 * last direct and indirect blocks (if any)
	 * which we want to keep.  Lastblock is -1 when
	 * the file is truncated to 0.
	 */
	lastblock = lblkno(fs, length + fs->e2fs_bsize - 1) - 1;
	lastiblock[SINGLE] = lastblock - NDADDR;
	lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
	lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
	nblocks = btodb(fs->e2fs_bsize);
	/*
	 * Update file and block pointers on disk before we start freeing
	 * blocks.  If we crash before free'ing blocks below, the blocks
	 * will be returned to the free list.  lastiblock values are also
	 * normalized to -1 for calls to ext2_indirtrunc below.
	 */
	for (level = TRIPLE; level >= SINGLE; level--) {
		oldblks[NDADDR + level] = oip->i_ib[level];
		if (lastiblock[level] < 0) {
			oip->i_ib[level] = 0;
			lastiblock[level] = -1;
		}
	}
	for (i = 0; i < NDADDR; i++) {
		oldblks[i] = oip->i_db[i];
		if (i > lastblock)
			oip->i_db[i] = 0;
	}
	oip->i_flag |= IN_CHANGE | IN_UPDATE;
	allerror = ext2_update(ovp, !DOINGASYNC(ovp));

	/*
	 * Having written the new inode to disk, save its new configuration
	 * and put back the old block pointers long enough to process them.
	 * Note that we save the new block configuration so we can check it
	 * when we are done.
	 */
	for (i = 0; i < NDADDR; i++) {
		newblks[i] = oip->i_db[i];
		oip->i_db[i] = oldblks[i];
	}
	for (i = 0; i < NIADDR; i++) {
		newblks[NDADDR + i] = oip->i_ib[i];
		oip->i_ib[i] = oldblks[NDADDR + i];
	}
	oip->i_size = osize;
	error = vtruncbuf(ovp, cred, length, (int)fs->e2fs_bsize);
	if (error && (allerror == 0))
		allerror = error;
	vnode_pager_setsize(ovp, length);

	/*
	 * Indirect blocks first.
	 */
	indir_lbn[SINGLE] = -NDADDR;
	indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1;
	indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1;
	for (level = TRIPLE; level >= SINGLE; level--) {
		bn = oip->i_ib[level];
		if (bn != 0) {
			error = ext2_indirtrunc(oip, indir_lbn[level],
			    fsbtodb(fs, bn), lastiblock[level], level, &count);
			if (error)
				allerror = error;
			blocksreleased += count;
			if (lastiblock[level] < 0) {
				oip->i_ib[level] = 0;
				ext2_blkfree(oip, bn, fs->e2fs_fsize);
				blocksreleased += nblocks;
			}
		}
		if (lastiblock[level] >= 0)
			goto done;
	}

	/*
	 * All whole direct blocks or frags.
	 */
	for (i = NDADDR - 1; i > lastblock; i--) {
		long bsize;

		bn = oip->i_db[i];
		if (bn == 0)
			continue;
		oip->i_db[i] = 0;
		bsize = blksize(fs, oip, i);
		ext2_blkfree(oip, bn, bsize);
		blocksreleased += btodb(bsize);
	}
	if (lastblock < 0)
		goto done;

	/*
	 * Finally, look for a change in size of the
	 * last direct block; release any frags.
	 */
	bn = oip->i_db[lastblock];
	if (bn != 0) {
		long oldspace, newspace;

		/*
		 * Calculate amount of space we're giving
		 * back as old block size minus new block size.
		 */
		oldspace = blksize(fs, oip, lastblock);
		oip->i_size = length;
		newspace = blksize(fs, oip, lastblock);
		if (newspace == 0)
			panic("ext2_truncate: newspace");
		if (oldspace - newspace > 0) {
			/*
			 * Block number of space to be free'd is
			 * the old block # plus the number of frags
			 * required for the storage we're keeping.
			 */
			bn += numfrags(fs, newspace);
			ext2_blkfree(oip, bn, oldspace - newspace);
			blocksreleased += btodb(oldspace - newspace);
		}
	}
done:
#ifdef INVARIANTS
	for (level = SINGLE; level <= TRIPLE; level++)
		if (newblks[NDADDR + level] != oip->i_ib[level])
			panic("itrunc1");
	for (i = 0; i < NDADDR; i++)
		if (newblks[i] != oip->i_db[i])
			panic("itrunc2");
	BO_LOCK(bo);
	if (length == 0 && (bo->bo_dirty.bv_cnt != 0 ||
	    bo->bo_clean.bv_cnt != 0))
		panic("itrunc3");
	BO_UNLOCK(bo);
#endif /* INVARIANTS */
	/*
	 * Put back the real size.
	 */
	oip->i_size = length;
	if (oip->i_blocks >= blocksreleased)
		oip->i_blocks -= blocksreleased;
	else				/* sanity */
		oip->i_blocks = 0;
	oip->i_flag |= IN_CHANGE;
	vnode_pager_setsize(ovp, length);
	return (allerror);
}
コード例 #9
0
ファイル: osi_vm.c プロジェクト: hwr/openafs
/* Purge pages beyond end-of-file, when truncating a file.
 *
 * Locking:  no lock is held, not even the global lock.
 * activeV is raised.  This is supposed to block pageins, but at present
 * it only works on Solaris.
 */
void
osi_VM_Truncate(struct vcache *avc, int alen, afs_ucred_t *acred)
{
    vnode_pager_setsize(AFSTOV(avc), alen);
}
コード例 #10
0
ファイル: ffs_inode.c プロジェクト: dancrossnyc/harvey
/*
 * Truncate the inode ip to at most length size, freeing the
 * disk blocks.
 */
int
ffs_truncate(vnode *vp, off_t length, int flags, Ucred *cred)
{
	print("HARVEY TODO: %s\n", __func__);
#if 0
	struct inode *ip;
	ufs2_daddr_t bn, lbn, lastblock, lastiblock[UFS_NIADDR];
	ufs2_daddr_t indir_lbn[UFS_NIADDR], oldblks[UFS_NDADDR + UFS_NIADDR];
	ufs2_daddr_t newblks[UFS_NDADDR + UFS_NIADDR];
	ufs2_daddr_t count, blocksreleased = 0, datablocks, blkno;
	struct bufobj *bo;
	struct fs *fs;
	struct buf *bp;
	struct ufsmount *ump;
	int softdeptrunc, journaltrunc;
	int needextclean, extblocks;
	int offset, size, level, nblocks;
	int i, error, allerror, indiroff, waitforupdate;
	off_t osize;

	ip = VTOI(vp);
	ump = VFSTOUFS(vp->v_mount);
	fs = ump->um_fs;
	bo = &vp->v_bufobj;

	ASSERT_VOP_LOCKED(vp, "ffs_truncate");

	if (length < 0)
		return (EINVAL);
	if (length > fs->fs_maxfilesize)
		return (EFBIG);
#ifdef QUOTA
	error = getinoquota(ip);
	if (error)
		return (error);
#endif
	/*
	 * Historically clients did not have to specify which data
	 * they were truncating. So, if not specified, we assume
	 * traditional behavior, e.g., just the normal data.
	 */
	if ((flags & (IO_EXT | IO_NORMAL)) == 0)
		flags |= IO_NORMAL;
	if (!DOINGSOFTDEP(vp) && !DOINGASYNC(vp))
		flags |= IO_SYNC;
	waitforupdate = (flags & IO_SYNC) != 0 || !DOINGASYNC(vp);
	/*
	 * If we are truncating the extended-attributes, and cannot
	 * do it with soft updates, then do it slowly here. If we are
	 * truncating both the extended attributes and the file contents
	 * (e.g., the file is being unlinked), then pick it off with
	 * soft updates below.
	 */
	allerror = 0;
	needextclean = 0;
	softdeptrunc = 0;
	journaltrunc = DOINGSUJ(vp);
	if (journaltrunc == 0 && DOINGSOFTDEP(vp) && length == 0)
		softdeptrunc = !softdep_slowdown(vp);
	extblocks = 0;
	datablocks = DIP(ip, i_blocks);
	if (fs->fs_magic == FS_UFS2_MAGIC && ip->i_din2->di_extsize > 0) {
		extblocks = btodb(fragroundup(fs, ip->i_din2->di_extsize));
		datablocks -= extblocks;
	}
	if ((flags & IO_EXT) && extblocks > 0) {
		if (length != 0)
			panic("ffs_truncate: partial trunc of extdata");
		if (softdeptrunc || journaltrunc) {
			if ((flags & IO_NORMAL) == 0)
				goto extclean;
			needextclean = 1;
		} else {
			if ((error = ffs_syncvnode(vp, MNT_WAIT, 0)) != 0)
				return (error);
#ifdef QUOTA
			(void) chkdq(ip, -extblocks, NOCRED, 0);
#endif
			vinvalbuf(vp, V_ALT, 0, 0);
			vn_pages_remove(vp,
			    OFF_TO_IDX(lblktosize(fs, -extblocks)), 0);
			osize = ip->i_din2->di_extsize;
			ip->i_din2->di_blocks -= extblocks;
			ip->i_din2->di_extsize = 0;
			for (i = 0; i < UFS_NXADDR; i++) {
				oldblks[i] = ip->i_din2->di_extb[i];
				ip->i_din2->di_extb[i] = 0;
			}
			ip->i_flag |= IN_CHANGE;
			if ((error = ffs_update(vp, waitforupdate)))
				return (error);
			for (i = 0; i < UFS_NXADDR; i++) {
				if (oldblks[i] == 0)
					continue;
				ffs_blkfree(ump, fs, ITODEVVP(ip), oldblks[i],
				    sblksize(fs, osize, i), ip->i_number,
				    vp->v_type, nil);
			}
		}
	}
	if ((flags & IO_NORMAL) == 0)
		return (0);
	if (vp->v_type == VLNK &&
	    (ip->i_size < vp->v_mount->mnt_maxsymlinklen ||
	     datablocks == 0)) {
#ifdef INVARIANTS
		if (length != 0)
			panic("ffs_truncate: partial truncate of symlink");
#endif
		bzero(SHORTLINK(ip), (uint)ip->i_size);
		ip->i_size = 0;
		DIP_SET(ip, i_size, 0);
		ip->i_flag |= IN_CHANGE | IN_UPDATE;
		if (needextclean)
			goto extclean;
		return (ffs_update(vp, waitforupdate));
	}
	if (ip->i_size == length) {
		ip->i_flag |= IN_CHANGE | IN_UPDATE;
		if (needextclean)
			goto extclean;
		return (ffs_update(vp, 0));
	}
	if (fs->fs_ronly)
		panic("ffs_truncate: read-only filesystem");
	if (IS_SNAPSHOT(ip))
		ffs_snapremove(vp);
	vp->v_lasta = vp->v_clen = vp->v_cstart = vp->v_lastw = 0;
	osize = ip->i_size;
	/*
	 * Lengthen the size of the file. We must ensure that the
	 * last byte of the file is allocated. Since the smallest
	 * value of osize is 0, length will be at least 1.
	 */
	if (osize < length) {
		vnode_pager_setsize(vp, length);
		flags |= BA_CLRBUF;
		error = UFS_BALLOC(vp, length - 1, 1, cred, flags, &bp);
		if (error) {
			vnode_pager_setsize(vp, osize);
			return (error);
		}
		ip->i_size = length;
		DIP_SET(ip, i_size, length);
		if (bp->b_bufsize == fs->fs_bsize)
			bp->b_flags |= B_CLUSTEROK;
		if (flags & IO_SYNC)
			bwrite(bp);
		else if (DOINGASYNC(vp))
			bdwrite(bp);
		else
			bawrite(bp);
		ip->i_flag |= IN_CHANGE | IN_UPDATE;
		return (ffs_update(vp, waitforupdate));
	}
	/*
	 * Lookup block number for a given offset. Zero length files
	 * have no blocks, so return a blkno of -1.
	 */
	lbn = lblkno(fs, length - 1);
	if (length == 0) {
		blkno = -1;
	} else if (lbn < UFS_NDADDR) {
		blkno = DIP(ip, i_db[lbn]);
	} else {
		error = UFS_BALLOC(vp, lblktosize(fs, (off_t)lbn), fs->fs_bsize,
		    cred, BA_METAONLY, &bp);
		if (error)
			return (error);
		indiroff = (lbn - UFS_NDADDR) % NINDIR(fs);
		if (I_IS_UFS1(ip))
			blkno = ((ufs1_daddr_t *)(bp->b_data))[indiroff];
		else
			blkno = ((ufs2_daddr_t *)(bp->b_data))[indiroff];
		/*
		 * If the block number is non-zero, then the indirect block
		 * must have been previously allocated and need not be written.
		 * If the block number is zero, then we may have allocated
		 * the indirect block and hence need to write it out.
		 */
		if (blkno != 0)
			brelse(bp);
		else if (flags & IO_SYNC)
			bwrite(bp);
		else
			bdwrite(bp);
	}
	/*
	 * If the block number at the new end of the file is zero,
	 * then we must allocate it to ensure that the last block of 
	 * the file is allocated. Soft updates does not handle this
	 * case, so here we have to clean up the soft updates data
	 * structures describing the allocation past the truncation
	 * point. Finding and deallocating those structures is a lot of
	 * work. Since partial truncation with a hole at the end occurs
	 * rarely, we solve the problem by syncing the file so that it
	 * will have no soft updates data structures left.
	 */
	if (blkno == 0 && (error = ffs_syncvnode(vp, MNT_WAIT, 0)) != 0)
		return (error);
	if (blkno != 0 && DOINGSOFTDEP(vp)) {
		if (softdeptrunc == 0 && journaltrunc == 0) {
			/*
			 * If soft updates cannot handle this truncation,
			 * clean up soft dependency data structures and
			 * fall through to the synchronous truncation.
			 */
			if ((error = ffs_syncvnode(vp, MNT_WAIT, 0)) != 0)
				return (error);
		} else {
			flags = IO_NORMAL | (needextclean ? IO_EXT: 0);
			if (journaltrunc)
				softdep_journal_freeblocks(ip, cred, length,
				    flags);
			else
				softdep_setup_freeblocks(ip, length, flags);
			ASSERT_VOP_LOCKED(vp, "ffs_truncate1");
			if (journaltrunc == 0) {
				ip->i_flag |= IN_CHANGE | IN_UPDATE;
				error = ffs_update(vp, 0);
			}
			return (error);
		}
	}
	/*
	 * Shorten the size of the file. If the last block of the
	 * shortened file is unallocated, we must allocate it.
	 * Additionally, if the file is not being truncated to a
	 * block boundary, the contents of the partial block
	 * following the end of the file must be zero'ed in
	 * case it ever becomes accessible again because of
	 * subsequent file growth. Directories however are not
	 * zero'ed as they should grow back initialized to empty.
	 */
	offset = blkoff(fs, length);
	if (blkno != 0 && offset == 0) {
		ip->i_size = length;
		DIP_SET(ip, i_size, length);
	} else {
		lbn = lblkno(fs, length);
		flags |= BA_CLRBUF;
		error = UFS_BALLOC(vp, length - 1, 1, cred, flags, &bp);
		if (error)
			return (error);
		/*
		 * When we are doing soft updates and the UFS_BALLOC
		 * above fills in a direct block hole with a full sized
		 * block that will be truncated down to a fragment below,
		 * we must flush out the block dependency with an FSYNC
		 * so that we do not get a soft updates inconsistency
		 * when we create the fragment below.
		 */
		if (DOINGSOFTDEP(vp) && lbn < UFS_NDADDR &&
		    fragroundup(fs, blkoff(fs, length)) < fs->fs_bsize &&
		    (error = ffs_syncvnode(vp, MNT_WAIT, 0)) != 0)
			return (error);
		ip->i_size = length;
		DIP_SET(ip, i_size, length);
		size = blksize(fs, ip, lbn);
		if (vp->v_type != VDIR && offset != 0)
			bzero((char *)bp->b_data + offset,
			    (uint)(size - offset));
		/* Kirk's code has reallocbuf(bp, size, 1) here */
		allocbuf(bp, size);
		if (bp->b_bufsize == fs->fs_bsize)
			bp->b_flags |= B_CLUSTEROK;
		if (flags & IO_SYNC)
			bwrite(bp);
		else if (DOINGASYNC(vp))
			bdwrite(bp);
		else
			bawrite(bp);
	}
	/*
	 * Calculate index into inode's block list of
	 * last direct and indirect blocks (if any)
	 * which we want to keep.  Lastblock is -1 when
	 * the file is truncated to 0.
	 */
	lastblock = lblkno(fs, length + fs->fs_bsize - 1) - 1;
	lastiblock[SINGLE] = lastblock - UFS_NDADDR;
	lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
	lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
	nblocks = btodb(fs->fs_bsize);
	/*
	 * Update file and block pointers on disk before we start freeing
	 * blocks.  If we crash before free'ing blocks below, the blocks
	 * will be returned to the free list.  lastiblock values are also
	 * normalized to -1 for calls to ffs_indirtrunc below.
	 */
	for (level = TRIPLE; level >= SINGLE; level--) {
		oldblks[UFS_NDADDR + level] = DIP(ip, i_ib[level]);
		if (lastiblock[level] < 0) {
			DIP_SET(ip, i_ib[level], 0);
			lastiblock[level] = -1;
		}
	}
	for (i = 0; i < UFS_NDADDR; i++) {
		oldblks[i] = DIP(ip, i_db[i]);
		if (i > lastblock)
			DIP_SET(ip, i_db[i], 0);
	}
	ip->i_flag |= IN_CHANGE | IN_UPDATE;
	allerror = ffs_update(vp, waitforupdate);
	
	/*
	 * Having written the new inode to disk, save its new configuration
	 * and put back the old block pointers long enough to process them.
	 * Note that we save the new block configuration so we can check it
	 * when we are done.
	 */
	for (i = 0; i < UFS_NDADDR; i++) {
		newblks[i] = DIP(ip, i_db[i]);
		DIP_SET(ip, i_db[i], oldblks[i]);
	}
	for (i = 0; i < UFS_NIADDR; i++) {
		newblks[UFS_NDADDR + i] = DIP(ip, i_ib[i]);
		DIP_SET(ip, i_ib[i], oldblks[UFS_NDADDR + i]);
	}
	ip->i_size = osize;
	DIP_SET(ip, i_size, osize);

	error = vtruncbuf(vp, cred, length, fs->fs_bsize);
	if (error && (allerror == 0))
		allerror = error;

	/*
	 * Indirect blocks first.
	 */
	indir_lbn[SINGLE] = -UFS_NDADDR;
	indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1;
	indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1;
	for (level = TRIPLE; level >= SINGLE; level--) {
		bn = DIP(ip, i_ib[level]);
		if (bn != 0) {
			error = ffs_indirtrunc(ip, indir_lbn[level],
			    fsbtodb(fs, bn), lastiblock[level], level, &count);
			if (error)
				allerror = error;
			blocksreleased += count;
			if (lastiblock[level] < 0) {
				DIP_SET(ip, i_ib[level], 0);
				ffs_blkfree(ump, fs, ump->um_devvp, bn,
				    fs->fs_bsize, ip->i_number,
				    vp->v_type, nil);
				blocksreleased += nblocks;
			}
		}
		if (lastiblock[level] >= 0)
			goto done;
	}

	/*
	 * All whole direct blocks or frags.
	 */
	for (i = UFS_NDADDR - 1; i > lastblock; i--) {
		long bsize;

		bn = DIP(ip, i_db[i]);
		if (bn == 0)
			continue;
		DIP_SET(ip, i_db[i], 0);
		bsize = blksize(fs, ip, i);
		ffs_blkfree(ump, fs, ump->um_devvp, bn, bsize, ip->i_number,
		    vp->v_type, nil);
		blocksreleased += btodb(bsize);
	}
	if (lastblock < 0)
		goto done;

	/*
	 * Finally, look for a change in size of the
	 * last direct block; release any frags.
	 */
	bn = DIP(ip, i_db[lastblock]);
	if (bn != 0) {
		long oldspace, newspace;

		/*
		 * Calculate amount of space we're giving
		 * back as old block size minus new block size.
		 */
		oldspace = blksize(fs, ip, lastblock);
		ip->i_size = length;
		DIP_SET(ip, i_size, length);
		newspace = blksize(fs, ip, lastblock);
		if (newspace == 0)
			panic("ffs_truncate: newspace");
		if (oldspace - newspace > 0) {
			/*
			 * Block number of space to be free'd is
			 * the old block # plus the number of frags
			 * required for the storage we're keeping.
			 */
			bn += numfrags(fs, newspace);
			ffs_blkfree(ump, fs, ump->um_devvp, bn,
			   oldspace - newspace, ip->i_number, vp->v_type, nil);
			blocksreleased += btodb(oldspace - newspace);
		}
	}
done:
#ifdef INVARIANTS
	for (level = SINGLE; level <= TRIPLE; level++)
		if (newblks[UFS_NDADDR + level] != DIP(ip, i_ib[level]))
			panic("ffs_truncate1");
	for (i = 0; i < UFS_NDADDR; i++)
		if (newblks[i] != DIP(ip, i_db[i]))
			panic("ffs_truncate2");
	BO_LOCK(bo);
	if (length == 0 &&
	    (fs->fs_magic != FS_UFS2_MAGIC || ip->i_din2->di_extsize == 0) &&
	    (bo->bo_dirty.bv_cnt > 0 || bo->bo_clean.bv_cnt > 0))
		panic("ffs_truncate3");
	BO_UNLOCK(bo);
#endif /* INVARIANTS */
	/*
	 * Put back the real size.
	 */
	ip->i_size = length;
	DIP_SET(ip, i_size, length);
	if (DIP(ip, i_blocks) >= blocksreleased)
		DIP_SET(ip, i_blocks, DIP(ip, i_blocks) - blocksreleased);
	else	/* sanity */
		DIP_SET(ip, i_blocks, 0);
	ip->i_flag |= IN_CHANGE;
#ifdef QUOTA
	(void) chkdq(ip, -blocksreleased, NOCRED, 0);
#endif
	return (allerror);

extclean:
	if (journaltrunc)
		softdep_journal_freeblocks(ip, cred, length, IO_EXT);
	else
		softdep_setup_freeblocks(ip, length, IO_EXT);
	return (ffs_update(vp, waitforupdate));

#endif // 0
	return 0;
}
コード例 #11
0
/*
 * Truncate the inode oip to at most length size, freeing the
 * disk blocks.
 */
int
ext2_truncate(struct vnode *vp, off_t length, int flags, struct ucred *cred)
{
    struct vnode *ovp = vp;
    daddr_t lastblock;
    struct inode *oip;
    daddr_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR];
    daddr_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR];
    struct ext2_sb_info *fs;
    struct buf *bp;
    int offset, size, level;
    long count, nblocks, blocksreleased = 0;
    int i;
    int aflags, error, allerror;
    off_t osize;
    /*
    kprintf("ext2_truncate called %d to %d\n", VTOI(ovp)->i_number, length);
    */	/*
	 * negative file sizes will totally break the code below and
	 * are not meaningful anyways.
	 */
    if (length < 0)
        return EFBIG;

    oip = VTOI(ovp);
    if (ovp->v_type == VLNK &&
            oip->i_size < ovp->v_mount->mnt_maxsymlinklen) {
#if DIAGNOSTIC
        if (length != 0)
            panic("ext2_truncate: partial truncate of symlink");
#endif
        bzero((char *)&oip->i_shortlink, (u_int)oip->i_size);
        oip->i_size = 0;
        oip->i_flag |= IN_CHANGE | IN_UPDATE;
        return (EXT2_UPDATE(ovp, 1));
    }
    if (oip->i_size == length) {
        oip->i_flag |= IN_CHANGE | IN_UPDATE;
        return (EXT2_UPDATE(ovp, 0));
    }
#if QUOTA
    if ((error = ext2_getinoquota(oip)) != 0)
        return (error);
#endif
    fs = oip->i_e2fs;
    osize = oip->i_size;
    ext2_discard_prealloc(oip);
    /*
     * Lengthen the size of the file. We must ensure that the
     * last byte of the file is allocated. Since the smallest
     * value of osize is 0, length will be at least 1.
     */
    if (osize < length) {
        offset = blkoff(fs, length - 1);
        lbn = lblkno(fs, length - 1);
        aflags = B_CLRBUF;
        if (flags & IO_SYNC)
            aflags |= B_SYNC;
        vnode_pager_setsize(ovp, length);
        error = ext2_balloc(oip, lbn, offset + 1, cred, &bp, aflags);
        if (error) {
            vnode_pager_setsize(ovp, osize);
            return (error);
        }
        oip->i_size = length;
        if (aflags & IO_SYNC)
            bwrite(bp);
        else
            bawrite(bp);
        oip->i_flag |= IN_CHANGE | IN_UPDATE;
        return (EXT2_UPDATE(ovp, 1));
    }
    /*
     * Shorten the size of the file. If the file is not being
     * truncated to a block boundry, the contents of the
     * partial block following the end of the file must be
     * zero'ed in case it ever become accessable again because
     * of subsequent file growth.
     */
    /* I don't understand the comment above */
    offset = blkoff(fs, length);
    if (offset == 0) {
        oip->i_size = length;
    } else {
        lbn = lblkno(fs, length);
        aflags = B_CLRBUF;
        if (flags & IO_SYNC)
            aflags |= B_SYNC;
        error = ext2_balloc(oip, lbn, offset, cred, &bp, aflags);
        if (error)
            return (error);
        oip->i_size = length;
        size = blksize(fs, oip, lbn);
        bzero((char *)bp->b_data + offset, (u_int)(size - offset));
        allocbuf(bp, size);
        if (aflags & IO_SYNC)
            bwrite(bp);
        else
            bawrite(bp);
    }
    /*
     * Calculate index into inode's block list of
     * last direct and indirect blocks (if any)
     * which we want to keep.  Lastblock is -1 when
     * the file is truncated to 0.
     */
    lastblock = lblkno(fs, length + fs->s_blocksize - 1) - 1;
    lastiblock[SINGLE] = lastblock - NDADDR;
    lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
    lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
    nblocks = btodb(fs->s_blocksize);
    /*
     * Update file and block pointers on disk before we start freeing
     * blocks.  If we crash before free'ing blocks below, the blocks
     * will be returned to the free list.  lastiblock values are also
     * normalized to -1 for calls to ext2_indirtrunc below.
     */
    bcopy((caddr_t)&oip->i_db[0], (caddr_t)oldblks, sizeof oldblks);
    for (level = TRIPLE; level >= SINGLE; level--)
        if (lastiblock[level] < 0) {
            oip->i_ib[level] = 0;
            lastiblock[level] = -1;
        }
    for (i = NDADDR - 1; i > lastblock; i--)
        oip->i_db[i] = 0;
    oip->i_flag |= IN_CHANGE | IN_UPDATE;
    allerror = EXT2_UPDATE(ovp, 1);

    /*
     * Having written the new inode to disk, save its new configuration
     * and put back the old block pointers long enough to process them.
     * Note that we save the new block configuration so we can check it
     * when we are done.
     */
    bcopy((caddr_t)&oip->i_db[0], (caddr_t)newblks, sizeof newblks);
    bcopy((caddr_t)oldblks, (caddr_t)&oip->i_db[0], sizeof oldblks);
    oip->i_size = osize;
    error = vtruncbuf(ovp, length, (int)fs->s_blocksize);
    if (error && (allerror == 0))
        allerror = error;

    /*
     * Indirect blocks first.
     */
    indir_lbn[SINGLE] = -NDADDR;
    indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1;
    indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1;
    for (level = TRIPLE; level >= SINGLE; level--) {
        bn = oip->i_ib[level];
        if (bn != 0) {
            error = ext2_indirtrunc(oip, indir_lbn[level],
                                    fsbtodoff(fs, bn), lastiblock[level], level, &count);
            if (error)
                allerror = error;
            blocksreleased += count;
            if (lastiblock[level] < 0) {
                oip->i_ib[level] = 0;
                ext2_blkfree(oip, bn, fs->s_frag_size);
                blocksreleased += nblocks;
            }
        }
        if (lastiblock[level] >= 0)
            goto done;
    }

    /*
     * All whole direct blocks or frags.
     */
    for (i = NDADDR - 1; i > lastblock; i--) {
        long bsize;

        bn = oip->i_db[i];
        if (bn == 0)
            continue;
        oip->i_db[i] = 0;
        bsize = blksize(fs, oip, i);
        ext2_blkfree(oip, bn, bsize);
        blocksreleased += btodb(bsize);
    }
    if (lastblock < 0)
        goto done;

    /*
     * Finally, look for a change in size of the
     * last direct block; release any frags.
     */
    bn = oip->i_db[lastblock];
    if (bn != 0) {
        long oldspace, newspace;

        /*
         * Calculate amount of space we're giving
         * back as old block size minus new block size.
         */
        oldspace = blksize(fs, oip, lastblock);
        oip->i_size = length;
        newspace = blksize(fs, oip, lastblock);
        if (newspace == 0)
            panic("itrunc: newspace");
        if (oldspace - newspace > 0) {
            /*
             * Block number of space to be free'd is
             * the old block # plus the number of frags
             * required for the storage we're keeping.
             */
            bn += numfrags(fs, newspace);
            ext2_blkfree(oip, bn, oldspace - newspace);
            blocksreleased += btodb(oldspace - newspace);
        }
    }
done:
#if DIAGNOSTIC
    for (level = SINGLE; level <= TRIPLE; level++)
        if (newblks[NDADDR + level] != oip->i_ib[level])
            panic("itrunc1");
    for (i = 0; i < NDADDR; i++)
        if (newblks[i] != oip->i_db[i])
            panic("itrunc2");
    if (length == 0 && (!RB_EMPTY(&ovp->v_rbdirty_tree) ||
                        !RB_EMPTY(&ovp->v_rbclean_tree)))
        panic("itrunc3");
#endif /* DIAGNOSTIC */
    /*
     * Put back the real size.
     */
    oip->i_size = length;
    oip->i_blocks -= blocksreleased;
    if (oip->i_blocks < 0)			/* sanity */
        oip->i_blocks = 0;
    oip->i_flag |= IN_CHANGE;
    vnode_pager_setsize(ovp, length);
#if QUOTA
    ext2_chkdq(oip, -blocksreleased, NOCRED, 0);
#endif
    return (allerror);
}
コード例 #12
0
int
xfs_write_file(xfs_inode_t *xip, struct uio *uio, int ioflag)
{
	struct buf	*bp;
	//struct thread	*td;
	daddr_t		lbn;
	off_t		osize = 0;
	off_t		offset= 0;
	int		blkoffset, error, resid, xfersize;
	int		fsblocksize;
	int		seqcount;
	xfs_iomap_t	iomap;
	int		maps = 1;

	xfs_vnode_t	*xvp = XFS_ITOV(xip);
	struct vnode	*vp = xvp->v_vnode;

	xfs_mount_t	*mp = (&xip->i_iocore)->io_mount;

	seqcount = ioflag >> IO_SEQSHIFT;

	memset(&iomap,0,sizeof(xfs_iomap_t));

	/*
	 * Maybe this should be above the vnode op call, but so long as
	 * file servers have no limits, I don't think it matters.
	 */
#if 0
	td = uio->uio_td;
	if (vp->v_type == VREG && td != NULL) {
		PROC_LOCK(td->td_proc);
		if (uio->uio_offset + uio->uio_resid >
		    lim_cur(td->td_proc, RLIMIT_FSIZE)) {
			psignal(td->td_proc, SIGXFSZ);
			PROC_UNLOCK(td->td_proc);
			return (EFBIG);
		}
		PROC_UNLOCK(td->td_proc);
	}
#endif

	resid = uio->uio_resid;
	offset = uio->uio_offset;
	osize = xip->i_d.di_size;

   /* xfs bmap wants bytes for both offset and size */
	XVOP_BMAP(xvp,
		  uio->uio_offset,
		  uio->uio_resid,
		  BMAPI_WRITE|BMAPI_DIRECT,
		  &iomap, &maps, error);
	if(error) {
		printf("XVOP_BMAP failed\n");
		goto error;
	}

	for (error = 0; uio->uio_resid > 0;) {

		lbn = XFS_B_TO_FSBT(mp, offset);
		blkoffset = XFS_B_FSB_OFFSET(mp, offset);
		xfersize = mp->m_sb.sb_blocksize - blkoffset;
		fsblocksize = mp->m_sb.sb_blocksize;

		if (uio->uio_resid < xfersize)
			xfersize = uio->uio_resid;

		/*
		 * getblk sets buf by  blkno *  bo->bo_bsize
		 * bo_bsize is set from the mnt point fsize
		 * so we call getblk in the case using fsblocks
		 * not basic blocks
		 */

		bp = getblk(vp, lbn, fsblocksize, 0, 0, 0);
		if(!bp) {
			printf("getblk failed\n");
			error = EINVAL;
			break;
		}

		if (!(bp->b_flags & B_CACHE)  && fsblocksize > xfersize)
			vfs_bio_clrbuf(bp);

		if (offset + xfersize >  xip->i_d.di_size) {
			xip->i_d.di_size = offset + xfersize;
			vnode_pager_setsize(vp, offset + fsblocksize);
		}

		/* move the offset for the next itteration of the loop */
		offset += xfersize;

		error = uiomove((char *)bp->b_data + blkoffset, xfersize, uio);

		if ((ioflag & IO_VMIO) &&
		   (LIST_FIRST(&bp->b_dep) == NULL)) /* in ext2fs? */
			bp->b_flags |= B_RELBUF;

		/* force to full direct for now */
		bp->b_flags |= B_DIRECT;
		/* and sync ... the delay path is not pushing data out */
		ioflag |= IO_SYNC;

		if (ioflag & IO_SYNC) {
			(void)bwrite(bp);
		} else if (0 /* RMC xfersize + blkoffset == fs->s_frag_size */) {
			if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERW) == 0) {
				bp->b_flags |= B_CLUSTEROK;
				cluster_write(vp, bp, osize, seqcount);
			} else {
				bawrite(bp);
			}
		} else {
			bp->b_flags |= B_CLUSTEROK;
			bdwrite(bp);
		}
		if (error || xfersize == 0)
			break;
	}
	/*
	 * If we successfully wrote any data, and we are not the superuser
	 * we clear the setuid and setgid bits as a precaution against
	 * tampering.
	 */
#if 0
	if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0)
		ip->i_mode &= ~(ISUID | ISGID);
#endif
	if (error) {
		if (ioflag & IO_UNIT) {
#if 0
			(void)ext2_truncate(vp, osize,
			    ioflag & IO_SYNC, ap->a_cred, uio->uio_td);
#endif
			uio->uio_offset -= resid - uio->uio_resid;
			uio->uio_resid = resid;
		}
	} else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) {
		/* Update the vnode here? */
	}

error:
	return error;
}
コード例 #13
0
ファイル: afs_vnop_attrs.c プロジェクト: bagdxk/openafs
/* copy out attributes from cache entry */
int
afs_CopyOutAttrs(struct vcache *avc, struct vattr *attrs)
{
    struct volume *tvp;
    struct cell *tcell;
#if defined(AFS_FBSD_ENV) || defined(AFS_DFBSD_ENV)
    struct vnode *vp = AFSTOV(avc);
#endif
    int fakedir = 0;

    AFS_STATCNT(afs_CopyOutAttrs);
    if (afs_fakestat_enable && avc->mvstat == AFS_MVSTAT_MTPT)
	fakedir = 1;
    attrs->va_type = fakedir ? VDIR : vType(avc);
#if defined(AFS_SGI_ENV) || defined(AFS_AIX32_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
    attrs->va_mode = fakedir ? S_IFDIR | 0755 : (mode_t) (avc->f.m.Mode & 0xffff);
#else
    attrs->va_mode = fakedir ? VDIR | 0755 : avc->f.m.Mode;
#endif

    if (avc->f.m.Mode & (VSUID | VSGID)) {
	/* setuid or setgid, make sure we're allowed to run them from this cell */
	tcell = afs_GetCell(avc->f.fid.Cell, 0);
	if (tcell && (tcell->states & CNoSUID))
	    attrs->va_mode &= ~(VSUID | VSGID);
    }
#if defined(AFS_DARWIN_ENV)
    {
	if (!afs_darwin_realmodes) {
	    /* Mac OS X uses the mode bits to determine whether a file or
	     * directory is accessible, and believes them, even though under
	     * AFS they're almost assuredly wrong, especially if the local uid
	     * does not match the AFS ID.  So we set the mode bits
	     * conservatively.
	     */
	    if (S_ISDIR(attrs->va_mode)) {
		/* all access bits need to be set for directories, since even
		 * a mode 0 directory can still be used normally.
		 */
		attrs->va_mode |= ACCESSPERMS;
	    } else {
		/* for other files, replicate the user bits to group and other */
		mode_t ubits = (attrs->va_mode & S_IRWXU) >> 6;
		attrs->va_mode |= ubits | (ubits << 3);
	    }
	}
    }
#endif /* AFS_DARWIN_ENV */
    attrs->va_uid = fakedir ? 0 : avc->f.m.Owner;
    attrs->va_gid = fakedir ? 0 : avc->f.m.Group;	/* yeah! */
#if defined(AFS_SUN5_ENV)
    attrs->va_fsid = avc->v.v_vfsp->vfs_fsid.val[0];
#elif defined(AFS_DARWIN80_ENV)
    VATTR_RETURN(attrs, va_fsid, vfs_statfs(vnode_mount(AFSTOV(avc)))->f_fsid.val[0]);
#elif defined(AFS_DARWIN_ENV)
    attrs->va_fsid = avc->v->v_mount->mnt_stat.f_fsid.val[0];
#else /* ! AFS_DARWIN_ENV */
    attrs->va_fsid = 1;
#endif 
    if (avc->mvstat == AFS_MVSTAT_ROOT) {
	tvp = afs_GetVolume(&avc->f.fid, 0, READ_LOCK);
	/* The mount point's vnode. */
	if (tvp) {
	    attrs->va_nodeid =
	      afs_calc_inum(tvp->mtpoint.Cell,
			    tvp->mtpoint.Fid.Volume,
			    tvp->mtpoint.Fid.Vnode);
	    if (FidCmp(&afs_rootFid, &avc->f.fid) && !attrs->va_nodeid)
		attrs->va_nodeid = 2;
	    afs_PutVolume(tvp, READ_LOCK);
	} else
	    attrs->va_nodeid = 2;
    } else
	attrs->va_nodeid = 
	      afs_calc_inum(avc->f.fid.Cell,
			    avc->f.fid.Fid.Volume,
			    avc->f.fid.Fid.Vnode);
    attrs->va_nodeid &= 0x7fffffff;	/* Saber C hates negative inode #s! */
    attrs->va_nlink = fakedir ? 100 : avc->f.m.LinkCount;
    attrs->va_size = fakedir ? 4096 : avc->f.m.Length;
#if defined(AFS_FBSD_ENV) || defined(AFS_DFBSD_ENV)
        vnode_pager_setsize(vp, (u_long) attrs->va_size);
#endif
    attrs->va_atime.tv_sec = attrs->va_mtime.tv_sec = attrs->va_ctime.tv_sec =
	fakedir ? 0 : (int)avc->f.m.Date;
    /* set microseconds to be dataversion # so that we approximate NFS-style
     * use of mtime as a dataversion #.  We take it mod 512K because
     * microseconds *must* be less than a million, and 512K is the biggest
     * power of 2 less than such.  DataVersions are typically pretty small
     * anyway, so the difference between 512K and 1000000 shouldn't matter
     * much, and "&" is a lot faster than "%".
     */
#if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
    /* nfs on these systems puts an 0 in nsec and stores the nfs usec (aka 
     * dataversion) in va_gen */

    attrs->va_atime.tv_nsec = attrs->va_mtime.tv_nsec =
	attrs->va_ctime.tv_nsec = 0;
    attrs->va_gen = hgetlo(avc->f.m.DataVersion);
#elif defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_AIX41_ENV) || defined(AFS_OBSD_ENV) || defined(AFS_NBSD_ENV)
    attrs->va_atime.tv_nsec = attrs->va_mtime.tv_nsec =
	attrs->va_ctime.tv_nsec =
	(hgetlo(avc->f.m.DataVersion) & 0x7ffff) * 1000;
#else
    attrs->va_atime.tv_usec = attrs->va_mtime.tv_usec =
	attrs->va_ctime.tv_usec = (hgetlo(avc->f.m.DataVersion) & 0x7ffff);
#endif
#if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
    attrs->va_flags = 0;
#endif
#if defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV)
    attrs->va_blksize = AFS_BLKSIZE;	/* XXX Was 8192 XXX */
#else
    attrs->va_blocksize = AFS_BLKSIZE;	/* XXX Was 8192 XXX */
#endif
    attrs->va_rdev = 1;
#if defined(AFS_HPUX110_ENV)
    if (afs_globalVFS)
	attrs->va_fstype = afs_globalVFS->vfs_mtype;
#endif

    /*
     * Below return 0 (and not 1) blocks if the file is zero length. This conforms
     * better with the other filesystems that do return 0.      
     */
#if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
    attrs->va_bytes = (attrs->va_size ? (attrs->va_size + 1023) : 1024);
#ifdef	va_bytes_rsv
    attrs->va_bytes_rsv = -1;
#endif
#elif defined(AFS_HPUX_ENV)
    attrs->va_blocks = (attrs->va_size ? ((attrs->va_size + 1023)>>10) : 0);
#elif defined(AFS_SGI_ENV)
    attrs->va_blocks = BTOBB(attrs->va_size);
#elif defined(AFS_SUN5_ENV)
    attrs->va_nblocks = (attrs->va_size ? ((attrs->va_size + 1023)>>10)<<1:0);
#else /* everything else */
    attrs->va_blocks = (attrs->va_size ? ((attrs->va_size + 1023)>>10)<<1:0);
#endif
    return 0;
}
コード例 #14
0
ファイル: nandfs_dir.c プロジェクト: JabirTech/Source
int
nandfs_add_dirent(struct vnode *dvp, uint64_t ino, char *nameptr, long namelen,
    uint8_t type)
{
	struct nandfs_node *dir_node = VTON(dvp);
	struct nandfs_dir_entry *dirent, *pdirent;
	uint32_t blocksize = dir_node->nn_nandfsdev->nd_blocksize;
	uint64_t filesize = dir_node->nn_inode.i_size;
	uint64_t inode_blks = dir_node->nn_inode.i_blocks;
	uint32_t off, rest;
	uint8_t *pos;
	struct buf *bp;
	int error;

	pdirent = NULL;
	bp = NULL;
	if (inode_blks) {
		error = nandfs_bread(dir_node, inode_blks - 1, NOCRED, 0, &bp);
		if (error) {
			brelse(bp);
			return (error);
		}

		pos = bp->b_data;
		off = 0;
		while (off < blocksize) {
			pdirent = (struct nandfs_dir_entry *) (pos + off);
			if (!pdirent->rec_len) {
				pdirent = NULL;
				break;
			}
			off += pdirent->rec_len;
		}

		if (pdirent)
			rest = pdirent->rec_len -
			    NANDFS_DIR_REC_LEN(pdirent->name_len);
		else
			rest = blocksize;

		if (rest < NANDFS_DIR_REC_LEN(namelen)) {
			/* Do not update pdirent as new block is created */
			pdirent = NULL;
			brelse(bp);
			/* Set to NULL to create new */
			bp = NULL;
			filesize += rest;
		}
	}

	/* If no bp found create new */
	if (!bp) {
		error = nandfs_bcreate(dir_node, inode_blks, NOCRED, 0, &bp);
		if (error)
			return (error);
		off = 0;
		pos = bp->b_data;
	}

	/* Modify pdirent if exists */
	if (pdirent) {
		DPRINTF(LOOKUP, ("modify pdirent %p\n", pdirent));
		/* modify last de */
		off -= pdirent->rec_len;
		pdirent->rec_len =
		    NANDFS_DIR_REC_LEN(pdirent->name_len);
		off += pdirent->rec_len;
	}

	/* Create new dirent */
	dirent = (struct nandfs_dir_entry *) (pos + off);
	dirent->rec_len = blocksize - off;
	dirent->inode = ino;
	dirent->name_len = namelen;
	memset(dirent->name, 0, NANDFS_DIR_NAME_LEN(namelen));
	memcpy(dirent->name, nameptr, namelen);
	dirent->file_type = type;

	filesize += NANDFS_DIR_REC_LEN(dirent->name_len);

	DPRINTF(LOOKUP, ("create dir_entry '%.*s' at %p with size %x "
	    "new filesize: %jx\n",
	    (int)namelen, dirent->name, dirent, dirent->rec_len,
	    (uintmax_t)filesize));

	error = nandfs_dirty_buf(bp, 0);
	if (error)
		return (error);

	dir_node->nn_inode.i_size = filesize;
	dir_node->nn_flags |= IN_CHANGE | IN_UPDATE;
	vnode_pager_setsize(dvp, filesize);

	return (0);
}
コード例 #15
0
ファイル: hpfs_vnops.c プロジェクト: juanfra684/DragonFlyBSD
/*
 * XXXXX do we need hpfsnode locking inside?
 *
 * hpfs_setattr(struct vnode *a_vp, struct vattr *a_vap, struct ucred *a_cred)
 */
static int
hpfs_setattr(struct vop_setattr_args *ap)
{
	struct vnode *vp = ap->a_vp;
	struct hpfsnode *hp = VTOHP(vp);
	struct vattr *vap = ap->a_vap;
	struct ucred *cred = ap->a_cred;
	int error;

	dprintf(("hpfs_setattr(0x%x):\n", hp->h_no));

	/*
	 * Check for unsettable attributes.
	 */
	if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
	    (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
	    (vap->va_blocksize != VNOVAL) || (vap->va_rmajor != VNOVAL) ||
	    (vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
		dprintf(("hpfs_setattr: changing nonsettable attr\n"));
		return (EINVAL);
	}

	/* Can't change flags XXX Could be implemented */
	if (vap->va_flags != VNOVAL) {
		kprintf("hpfs_setattr: FLAGS CANNOT BE SET\n");
		return (EINVAL);
	}

	/* Can't change uid/gid XXX Could be implemented */
	if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
		kprintf("hpfs_setattr: UID/GID CANNOT BE SET\n");
		return (EINVAL);
	}

	/* Can't change mode XXX Could be implemented */
	if (vap->va_mode != (mode_t)VNOVAL) {
		kprintf("hpfs_setattr: MODE CANNOT BE SET\n");
		return (EINVAL);
	}

	/* Update times */
	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
		if (vp->v_mount->mnt_flag & MNT_RDONLY)
			return (EROFS);
		if (cred->cr_uid != hp->h_uid &&
		    (error = priv_check_cred(cred, PRIV_VFS_SETATTR, 0)) &&
		    ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
		    (error = VOP_EACCESS(vp, VWRITE, cred))))
			return (error);
		if (vap->va_atime.tv_sec != VNOVAL)
			hp->h_atime = vap->va_atime.tv_sec;
		if (vap->va_mtime.tv_sec != VNOVAL)
			hp->h_mtime = vap->va_mtime.tv_sec;

		hp->h_flag |= H_PARCHANGE;
	}

	if (vap->va_size != VNOVAL) {
		switch (vp->v_type) {
		case VDIR:
			return (EISDIR);
		case VREG:
			if (vp->v_mount->mnt_flag & MNT_RDONLY)
				return (EROFS);
			break;
		default:
			kprintf("hpfs_setattr: WRONG v_type\n");
			return (EINVAL);
		}

		if (vap->va_size < hp->h_fn.fn_size) {
#if defined(__DragonFly__)
			error = vtruncbuf(vp, vap->va_size, DEV_BSIZE);
			if (error)
				return (error);
#else /* defined(__NetBSD__) */
#error Need alternation for vtruncbuf()
#endif
			error = hpfs_truncate(hp, vap->va_size);
			if (error)
				return (error);

		} else if (vap->va_size > hp->h_fn.fn_size) {
#if defined(__DragonFly__)
			vnode_pager_setsize(vp, vap->va_size);
#endif
			error = hpfs_extend(hp, vap->va_size);
			if (error)
				return (error);
		}
	}

	return (0);
}
コード例 #16
0
/*
 * Vnode op for writing.
 */
static int
ext2_write(struct vop_write_args *ap)
{
	struct vnode *vp;
	struct uio *uio;
	struct inode *ip;
	struct m_ext2fs *fs;
	struct buf *bp;
	daddr_t lbn;
	off_t osize;
	int blkoffset, error, flags, ioflag, resid, size, seqcount, xfersize;

	ioflag = ap->a_ioflag;
	uio = ap->a_uio;
	vp = ap->a_vp;

	seqcount = ioflag >> IO_SEQSHIFT;
	ip = VTOI(vp);

#ifdef INVARIANTS
	if (uio->uio_rw != UIO_WRITE)
		panic("%s: mode", "ext2_write");
#endif

	switch (vp->v_type) {
	case VREG:
		if (ioflag & IO_APPEND)
			uio->uio_offset = ip->i_size;
		if ((ip->i_flags & APPEND) && uio->uio_offset != ip->i_size)
			return (EPERM);
		/* FALLTHROUGH */
	case VLNK:
		break;
	case VDIR:
		/* XXX differs from ffs -- this is called from ext2_mkdir(). */
		if ((ioflag & IO_SYNC) == 0)
		panic("ext2_write: nonsync dir write");
		break;
	default:
		panic("ext2_write: type %p %d (%jd,%jd)", (void *)vp,
		    vp->v_type, (intmax_t)uio->uio_offset,
		    (intmax_t)uio->uio_resid);
	}

	KASSERT(uio->uio_resid >= 0, ("ext2_write: uio->uio_resid < 0"));
	KASSERT(uio->uio_offset >= 0, ("ext2_write: uio->uio_offset < 0"));
	fs = ip->i_e2fs;
	if ((uoff_t)uio->uio_offset + uio->uio_resid > fs->e2fs_maxfilesize)
		return (EFBIG);
	/*
	 * Maybe this should be above the vnode op call, but so long as
	 * file servers have no limits, I don't think it matters.
	 */
	if (vn_rlimit_fsize(vp, uio, uio->uio_td))
		return (EFBIG);

	resid = uio->uio_resid;
	osize = ip->i_size;
	if (seqcount > BA_SEQMAX)
		flags = BA_SEQMAX << BA_SEQSHIFT;
	else
		flags = seqcount << BA_SEQSHIFT;
	if ((ioflag & IO_SYNC) && !DOINGASYNC(vp))
		flags |= IO_SYNC;

	for (error = 0; uio->uio_resid > 0;) {
		lbn = lblkno(fs, uio->uio_offset);
		blkoffset = blkoff(fs, uio->uio_offset);
		xfersize = fs->e2fs_fsize - blkoffset;
		if (uio->uio_resid < xfersize)
			xfersize = uio->uio_resid;
		if (uio->uio_offset + xfersize > ip->i_size)
			vnode_pager_setsize(vp, uio->uio_offset + xfersize);

                /*
		 * We must perform a read-before-write if the transfer size
		 * does not cover the entire buffer.
                 */
		if (fs->e2fs_bsize > xfersize)
			flags |= BA_CLRBUF;
		else
			flags &= ~BA_CLRBUF;
		error = ext2_balloc(ip, lbn, blkoffset + xfersize,
		    ap->a_cred, &bp, flags);
		if (error != 0)
			break;

		/*
		 * If the buffer is not valid and we did not clear garbage
		 * out above, we have to do so here even though the write
		 * covers the entire buffer in order to avoid a mmap()/write
		 * race where another process may see the garbage prior to
		 * the uiomove() for a write replacing it.
		 */
		if ((bp->b_flags & B_CACHE) == 0 && fs->e2fs_bsize <= xfersize)
			vfs_bio_clrbuf(bp);
		if ((ioflag & (IO_SYNC|IO_INVAL)) == (IO_SYNC|IO_INVAL))
			bp->b_flags |= B_NOCACHE;
		if (uio->uio_offset + xfersize > ip->i_size)
			ip->i_size = uio->uio_offset + xfersize;
		size = blksize(fs, ip, lbn) - bp->b_resid;
		if (size < xfersize)
			xfersize = size;

		error =
		    uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio);
		if (ioflag & (IO_VMIO|IO_DIRECT)) {
			bp->b_flags |= B_RELBUF;
		}

		/*
		 * If IO_SYNC each buffer is written synchronously.  Otherwise
		 * if we have a severe page deficiency write the buffer
		 * asynchronously.  Otherwise try to cluster, and if that
		 * doesn't do it then either do an async write (if O_DIRECT),
		 * or a delayed write (if not).
		 */
		if (ioflag & IO_SYNC) {
			(void)bwrite(bp);
		} else if (vm_page_count_severe() ||
		    buf_dirty_count_severe() ||
		    (ioflag & IO_ASYNC)) {
			bp->b_flags |= B_CLUSTEROK;
			bawrite(bp);
		} else if (xfersize + blkoffset == fs->e2fs_fsize) {
			if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERW) == 0) {
				bp->b_flags |= B_CLUSTEROK;
				cluster_write(vp, bp, ip->i_size, seqcount, 0);
			} else {
				bawrite(bp);
			}
		} else if (ioflag & IO_DIRECT) {
			bp->b_flags |= B_CLUSTEROK;
			bawrite(bp);
		} else {
			bp->b_flags |= B_CLUSTEROK;
			bdwrite(bp);
		}
		if (error || xfersize == 0)
			break;
	}
	/*
	 * If we successfully wrote any data, and we are not the superuser
	 * we clear the setuid and setgid bits as a precaution against
	 * tampering.
	 */
	if ((ip->i_mode & (ISUID | ISGID)) && resid > uio->uio_resid &&
	    ap->a_cred) {
		if (priv_check_cred(ap->a_cred, PRIV_VFS_RETAINSUGID, 0))
			ip->i_mode &= ~(ISUID | ISGID);
	}
	if (error) {
		if (ioflag & IO_UNIT) {
			(void)ext2_truncate(vp, osize,
			    ioflag & IO_SYNC, ap->a_cred, uio->uio_td);
			uio->uio_offset -= resid - uio->uio_resid;
			uio->uio_resid = resid;
		}
	}
	if (uio->uio_resid != resid) {
               ip->i_flag |= IN_CHANGE | IN_UPDATE;
               if (ioflag & IO_SYNC)
                       error = ext2_update(vp, 1);
       }
	return (error);
}
コード例 #17
0
ファイル: nfs_clsubs.c プロジェクト: ryo/netbsd-src
/*
 * Check the time stamp
 * If the cache is valid, copy contents to *vap and return 0
 * otherwise return an error
 */
int
ncl_getattrcache(struct vnode *vp, struct vattr *vaper)
{
	struct nfsnode *np;
	struct vattr *vap;
	struct nfsmount *nmp;
	int timeo, mustflush;
	
	np = VTONFS(vp);
	vap = &np->n_vattr.na_vattr;
	nmp = VFSTONFS(vp->v_mount);
	mustflush = nfscl_mustflush(vp);	/* must be before mtx_lock() */
	mtx_lock(&np->n_mtx);
	/* XXX n_mtime doesn't seem to be updated on a miss-and-reload */
	timeo = (time_second - np->n_mtime.tv_sec) / 10;

#ifdef NFS_ACDEBUG
	if (nfs_acdebug>1)
		printf("ncl_getattrcache: initial timeo = %d\n", timeo);
#endif

	if (vap->va_type == VDIR) {
		if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin)
			timeo = nmp->nm_acdirmin;
		else if (timeo > nmp->nm_acdirmax)
			timeo = nmp->nm_acdirmax;
	} else {
		if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin)
			timeo = nmp->nm_acregmin;
		else if (timeo > nmp->nm_acregmax)
			timeo = nmp->nm_acregmax;
	}

#ifdef NFS_ACDEBUG
	if (nfs_acdebug > 2)
		printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n",
		    nmp->nm_acregmin, nmp->nm_acregmax,
		    nmp->nm_acdirmin, nmp->nm_acdirmax);

	if (nfs_acdebug)
		printf("ncl_getattrcache: age = %d; final timeo = %d\n",
		    (time_second - np->n_attrstamp), timeo);
#endif

	if ((time_second - np->n_attrstamp) >= timeo &&
	    (mustflush != 0 || np->n_attrstamp == 0)) {
		nfsstatsv1.attrcache_misses++;
		mtx_unlock(&np->n_mtx);
		KDTRACE_NFS_ATTRCACHE_GET_MISS(vp);
		return( ENOENT);
	}
	nfsstatsv1.attrcache_hits++;
	if (vap->va_size != np->n_size) {
		if (vap->va_type == VREG) {
			if (np->n_flag & NMODIFIED) {
				if (vap->va_size < np->n_size)
					vap->va_size = np->n_size;
				else
					np->n_size = vap->va_size;
			} else {
				np->n_size = vap->va_size;
			}
			vnode_pager_setsize(vp, np->n_size);
		} else {
			np->n_size = vap->va_size;
		}
	}
	bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
	if (np->n_flag & NCHG) {
		if (np->n_flag & NACC)
			vaper->va_atime = np->n_atim;
		if (np->n_flag & NUPD)
			vaper->va_mtime = np->n_mtim;
	}
	mtx_unlock(&np->n_mtx);
	KDTRACE_NFS_ATTRCACHE_GET_HIT(vp, vap);
	return (0);
}
コード例 #18
0
ファイル: nfs4_vn_subs.c プロジェクト: MarginC/kame
void
nfs4_vnop_loadattrcache(struct vnode *vp, struct nfsv4_fattr *fap,
    struct vattr *vaper)
{
        struct vattr *vap;
        struct nfsnode *np;
        int32_t rdev;
        enum vtype vtyp;
        u_short vmode;
        struct timespec mtime;
	struct timeval tv;

        microtime(&tv);

        vtyp = nv3tov_type[fap->fa4_type & 0x7];
        vmode = (fap->fa4_valid & FA4V_MODE) ? fap->fa4_mode : 0777;
        rdev = (fap->fa4_valid & FA4V_RDEV) ?
	    makeudev(fap->fa4_rdev_major, fap->fa4_rdev_minor) : 0;
        if (fap->fa4_valid & FA4V_MTIME)
                mtime = fap->fa4_mtime;
        else
                bzero(&mtime, sizeof mtime);

        /*
         * If v_type == VNON it is a new node, so fill in the v_type,
         * n_mtime fields. Check to see if it represents a special
         * device, and if so, check for a possible alias. Once the
         * correct vnode has been obtained, fill in the rest of the
         * information.
         */
        np = VTONFS(vp);
        vap = &np->n_vattr;
        if (vp->v_type != vtyp || np->n_mtime == 0) {
                bzero(vap, sizeof *vap);
                vp->v_type = vtyp;
                np->n_mtime = mtime.tv_sec;
        }
        vap->va_type = vtyp;
        vap->va_mode = (vmode & 07777);
        vap->va_rdev = rdev;
        vap->va_mtime = mtime;
        vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
        if (fap->fa4_valid & FA4V_NLINK)
                vap->va_nlink = fap->fa4_nlink;
        if (fap->fa4_valid & FA4V_UID)
                vap->va_uid = fap->fa4_uid;
        if (fap->fa4_valid & FA4V_GID)
                vap->va_gid = fap->fa4_gid;
        vap->va_size = fap->fa4_size;
        vap->va_blocksize = NFS_FABLKSIZE;
        vap->va_bytes = fap->fa4_size;
        if (fap->fa4_valid & FA4V_FILEID)
                vap->va_fileid = nfs_v4fileid4_to_fileid(fap->fa4_fileid);
        if (fap->fa4_valid & FA4V_ATIME)
                vap->va_atime = fap->fa4_atime;
        if (fap->fa4_valid & FA4V_CTIME)
                vap->va_ctime = fap->fa4_ctime;
        vap->va_flags = 0;
        vap->va_filerev = 0;
	/* XXX dontshrink flag? */
        if (vap->va_size != np->n_size) {
                if (vap->va_type == VREG) {
                        if (np->n_flag & NMODIFIED) {
                                if (vap->va_size < np->n_size)
                                        vap->va_size = np->n_size;
                                else
                                        np->n_size = vap->va_size;
                        } else
                                np->n_size = vap->va_size;
			vnode_pager_setsize(vp, np->n_size);
                } else
                        np->n_size = vap->va_size;
        }
        np->n_attrstamp = tv.tv_sec;
        if (vaper != NULL) {
                bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
                if (np->n_flag & NCHG) {
                        if (np->n_flag & NACC)
                                vaper->va_atime = np->n_atim;
                        if (np->n_flag & NUPD)
                                vaper->va_mtime = np->n_mtim;
                }
        }
}