Mercurial > illumos > illumos-gate
changeset 6717:931e23d3d667
6669199 fcntl(F_ALLOCSP) causes solaris_nevada to panic: ufs_putapage: bn == UFS_HOLE
author | jr26306 |
---|---|
date | Tue, 27 May 2008 01:57:11 -0700 |
parents | 6af79b23c84d |
children | 549bc0892138 |
files | usr/src/uts/common/fs/ufs/ufs_alloc.c |
diffstat | 1 files changed, 48 insertions(+), 23 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/fs/ufs/ufs_alloc.c Tue May 27 01:07:00 2008 -0700 +++ b/usr/src/uts/common/fs/ufs/ufs_alloc.c Tue May 27 01:57:11 2008 -0700 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -1527,22 +1527,25 @@ /* * ufs_allocsp() can be used to pre-allocate blocks for a file on a given - * file system. The blocks are not initialized and are only marked as allocated. - * These addresses are then stored as negative block numbers in the inode to - * imply special handling. UFS has been modified where necessary to understand - * this new notion. Successfully fallocated files will have IFALLOCATE cflag - * set in the inode. + * file system. For direct blocks, the blocks are allocated from the offset + * requested to the block boundary, then any full blocks are allocated, + * and finally any remainder. + * For indirect blocks the blocks are not initialized and are + * only marked as allocated. These addresses are then stored as negative + * block numbers in the inode to imply special handling. UFS has been modified + * where necessary to understand this new notion. + * Successfully fallocated files will have IFALLOCATE cflag set in the inode. */ int ufs_allocsp(struct vnode *vp, struct flock64 *lp, cred_t *cr) { struct lockfs lf; int berr, err, resv, issync; - off_t start, istart, len; /* istart, special for idb */ + off_t istart, len; /* istart, special for idb */ struct inode *ip; struct fs *fs; struct ufsvfs *ufsvfsp; - u_offset_t resid, i; + u_offset_t resid, i, uoff; daddr32_t db_undo[NDADDR]; /* old direct blocks */ struct allocsp_undo *ib_undo = NULL; /* ib undo */ struct allocsp_undo *undo = NULL; @@ -1552,6 +1555,9 @@ daddr_t allocblk; daddr_t totblks = 0; struct ulockfs *ulp; + size_t done_len; + int nbytes, offsetn; + ASSERT(vp->v_type == VREG); @@ -1562,7 +1568,7 @@ goto out_allocsp; } - istart = start = blkroundup(fs, (lp->l_start)); + istart = blkroundup(fs, (lp->l_start)); len = blkroundup(fs, (lp->l_len)); chunkblks = blkroundup(fs, ufsvfsp->vfs_iotransz) / fs->fs_bsize; ulp = &ufsvfsp->vfs_ulockfs; @@ -1594,8 +1600,17 @@ osz = ip->i_size; rw_exit(&ip->i_contents); - /* Allocate any direct blocks now before we write lock the fs */ - if (lblkno(fs, start) < NDADDR) { + /* Write lock the file system */ + if (err = allocsp_wlockfs(vp, &lf)) + goto exit; + + /* + * Allocate any direct blocks now. + * Blocks are allocated from the offset requested to the block + * boundary, then any full blocks are allocated, and finally any + * remainder. + */ + if (lblkno(fs, lp->l_start) < NDADDR) { ufs_trans_trunc_resv(ip, ip->i_size + (NDADDR * fs->fs_bsize), &resv, &resid); TRANS_BEGIN_CSYNC(ufsvfsp, issync, TOP_ALLOCSP, resv); @@ -1603,10 +1618,16 @@ rw_enter(&ufsvfsp->vfs_dqrwlock, RW_READER); rw_enter(&ip->i_contents, RW_WRITER); - for (i = start; (i < (start + len)) && (lblkno(fs, i) < NDADDR); - i += fs->fs_bsize) { - berr = bmap_write(ip, i, fs->fs_bsize, BI_FALLOCATE, - &allocblk, cr); + done_len = 0; + while ((done_len < lp->l_len) && + (lblkno(fs, lp->l_start + done_len) < NDADDR)) { + uoff = (offset_t)(lp->l_start + done_len); + offsetn = (int)blkoff(fs, uoff); + nbytes = (int)MIN(fs->fs_bsize - offsetn, + lp->l_len - done_len); + + berr = bmap_write(ip, uoff, offsetn + nbytes, + BI_FALLOCATE, &allocblk, cr); /* Yikes error, quit */ if (berr) { TRANS_INODE(ufsvfsp, ip); @@ -1614,14 +1635,16 @@ rw_exit(&ufsvfsp->vfs_dqrwlock); TRANS_END_CSYNC(ufsvfsp, err, issync, TOP_ALLOCSP, resv); + err = allocsp_unlockfs(vp, &lf); goto exit; } if (allocblk) { totblks++; - if (i >= ip->i_size) - ip->i_size += fs->fs_bsize; + if ((uoff + nbytes) > ip->i_size) + ip->i_size = (uoff + nbytes); } + done_len += nbytes; } TRANS_INODE(ufsvfsp, ip); @@ -1629,13 +1652,10 @@ rw_exit(&ufsvfsp->vfs_dqrwlock); TRANS_END_CSYNC(ufsvfsp, err, issync, TOP_ALLOCSP, resv); - istart = i; /* start offset for indirect allocation */ + /* start offset for indirect allocation */ + istart = (uoff + nbytes); } - /* Write lock the file system */ - if (err = allocsp_wlockfs(vp, &lf)) - goto exit; - /* Break the transactions into vfs_iotransz units */ ufs_trans_trunc_resv(ip, ip->i_size + blkroundup(fs, ufsvfsp->vfs_iotransz), &resv, &resid); @@ -1645,7 +1665,7 @@ rw_enter(&ip->i_contents, RW_WRITER); /* Now go about fallocating necessary indirect blocks */ - for (i = istart; i < (start + len); i += fs->fs_bsize) { + for (i = istart; i < (lp->l_start + lp->l_len); i += fs->fs_bsize) { berr = bmap_write(ip, i, fs->fs_bsize, BI_FALLOCATE, &allocblk, cr); if (berr) { @@ -1691,6 +1711,7 @@ TRANS_END_CSYNC(ufsvfsp, err, issync, TOP_ALLOCSP, resv); rw_exit(&ip->i_rwlock); + (void) allocsp_unlockfs(vp, &lf); return (EIO); } @@ -1733,6 +1754,10 @@ if (!err && !berr) ip->i_cflags |= IFALLOCATE; + /* If the file has grown then correct the file size */ + if (osz < (lp->l_start + lp->l_len)) + ip->i_size = (lp->l_start + lp->l_len); + /* Release locks, end log transaction and unlock fs */ TRANS_INODE(ufsvfsp, ip); rw_exit(&ip->i_contents);