17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*da6c28aaSamw * Common Development and Distribution License (the "License"). 6*da6c28aaSamw * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*da6c28aaSamw * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <sys/types.h> 297c478bd9Sstevel@tonic-gate #include <sys/param.h> 307c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 317c478bd9Sstevel@tonic-gate #include <sys/conf.h> 327c478bd9Sstevel@tonic-gate #include <sys/fssnap_if.h> 337c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_inode.h> 347c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_lockfs.h> 357c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_log.h> 367c478bd9Sstevel@tonic-gate #include <sys/fs/ufs_trans.h> 377c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 387c478bd9Sstevel@tonic-gate #include <vm/pvn.h> 397c478bd9Sstevel@tonic-gate #include <vm/seg_map.h> 407c478bd9Sstevel@tonic-gate #include <sys/fdbuffer.h> 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #ifdef DEBUG 437c478bd9Sstevel@tonic-gate int evn_ufs_debug = 0; 447c478bd9Sstevel@tonic-gate #define DEBUGF(args) { if (evn_ufs_debug) cmn_err args; } 457c478bd9Sstevel@tonic-gate #else 467c478bd9Sstevel@tonic-gate #define DEBUGF(args) 477c478bd9Sstevel@tonic-gate #endif 487c478bd9Sstevel@tonic-gate 497c478bd9Sstevel@tonic-gate /* 507c478bd9Sstevel@tonic-gate * ufs_rdwr_data - supports reading or writing data when 517c478bd9Sstevel@tonic-gate * no changes are permitted in file size or space allocation. 527c478bd9Sstevel@tonic-gate * 537c478bd9Sstevel@tonic-gate * Inputs: 547c478bd9Sstevel@tonic-gate * fdb - The mandatory fdbuffer supports 557c478bd9Sstevel@tonic-gate * the read or write operation. 567c478bd9Sstevel@tonic-gate * flags - defaults (zero value) to synchronous write 577c478bd9Sstevel@tonic-gate * B_READ - indicates read operation 587c478bd9Sstevel@tonic-gate * B_ASYNC - indicates perform operation asynchronously 597c478bd9Sstevel@tonic-gate */ 607c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 617c478bd9Sstevel@tonic-gate int 627c478bd9Sstevel@tonic-gate ufs_rdwr_data( 637c478bd9Sstevel@tonic-gate vnode_t *vnodep, 647c478bd9Sstevel@tonic-gate u_offset_t offset, 657c478bd9Sstevel@tonic-gate size_t len, 667c478bd9Sstevel@tonic-gate fdbuffer_t *fdbp, 677c478bd9Sstevel@tonic-gate int flags, 687c478bd9Sstevel@tonic-gate cred_t *credp) 697c478bd9Sstevel@tonic-gate { 707c478bd9Sstevel@tonic-gate struct inode *ip = VTOI(vnodep); 717c478bd9Sstevel@tonic-gate struct fs *fs; 727c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp = ip->i_ufsvfs; 737c478bd9Sstevel@tonic-gate struct buf *bp; 747c478bd9Sstevel@tonic-gate krw_t rwtype = RW_READER; 757c478bd9Sstevel@tonic-gate u_offset_t offset1 = offset; /* Initial offset */ 767c478bd9Sstevel@tonic-gate size_t iolen; 777c478bd9Sstevel@tonic-gate int curlen = 0; 787c478bd9Sstevel@tonic-gate int pplen; 797c478bd9Sstevel@tonic-gate daddr_t bn; 807c478bd9Sstevel@tonic-gate int contig = 0; 817c478bd9Sstevel@tonic-gate int error = 0; 827c478bd9Sstevel@tonic-gate int nbytes; /* Number bytes this IO */ 837c478bd9Sstevel@tonic-gate int offsetn; /* Start point this IO */ 847c478bd9Sstevel@tonic-gate int iswrite = flags & B_WRITE; 857c478bd9Sstevel@tonic-gate int io_started = 0; /* No IO started */ 867c478bd9Sstevel@tonic-gate struct ulockfs *ulp; 877c478bd9Sstevel@tonic-gate uint_t protp = PROT_ALL; 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate error = ufs_lockfs_begin_getpage(ufsvfsp, &ulp, segkmap, !iswrite, 907c478bd9Sstevel@tonic-gate &protp); 917c478bd9Sstevel@tonic-gate if (error) { 927c478bd9Sstevel@tonic-gate if (flags & B_ASYNC) { 937c478bd9Sstevel@tonic-gate fdb_ioerrdone(fdbp, error); 947c478bd9Sstevel@tonic-gate } 957c478bd9Sstevel@tonic-gate return (error); 967c478bd9Sstevel@tonic-gate } 977c478bd9Sstevel@tonic-gate fs = ufsvfsp->vfs_fs; 987c478bd9Sstevel@tonic-gate iolen = len; 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate DEBUGF((CE_CONT, "?ufs_rdwr: %s vp: %p pages:%p off %llx len %lx" 1017c478bd9Sstevel@tonic-gate " isize: %llx fdb: %p\n", 1027c478bd9Sstevel@tonic-gate flags & B_READ ? "READ" : "WRITE", (void *)vnodep, 1037c478bd9Sstevel@tonic-gate (void *)vnodep->v_pages, offset1, iolen, ip->i_size, (void *)fdbp)); 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate rw_enter(&ip->i_ufsvfs->vfs_dqrwlock, RW_READER); 1067c478bd9Sstevel@tonic-gate rw_enter(&ip->i_contents, rwtype); 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate ASSERT(offset1 < ip->i_size); 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate if ((offset1 + iolen) > ip->i_size) { 1117c478bd9Sstevel@tonic-gate iolen = ip->i_size - offset1; 1127c478bd9Sstevel@tonic-gate } 1137c478bd9Sstevel@tonic-gate while (!error && curlen < iolen) { 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate contig = 0; 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate if ((error = bmap_read(ip, offset1, &bn, &contig)) != 0) { 1187c478bd9Sstevel@tonic-gate break; 1197c478bd9Sstevel@tonic-gate } 1207c478bd9Sstevel@tonic-gate ASSERT(!(bn == UFS_HOLE && iswrite)); 1217c478bd9Sstevel@tonic-gate if (bn == UFS_HOLE) { 1227c478bd9Sstevel@tonic-gate /* 1237c478bd9Sstevel@tonic-gate * If the above assertion is true, 1247c478bd9Sstevel@tonic-gate * then the following if statement can never be true. 1257c478bd9Sstevel@tonic-gate */ 1267c478bd9Sstevel@tonic-gate if (iswrite && (rwtype == RW_READER)) { 1277c478bd9Sstevel@tonic-gate rwtype = RW_WRITER; 1287c478bd9Sstevel@tonic-gate if (!rw_tryupgrade(&ip->i_contents)) { 1297c478bd9Sstevel@tonic-gate rw_exit(&ip->i_contents); 1307c478bd9Sstevel@tonic-gate rw_enter(&ip->i_contents, rwtype); 1317c478bd9Sstevel@tonic-gate continue; 1327c478bd9Sstevel@tonic-gate } 1337c478bd9Sstevel@tonic-gate } 1347c478bd9Sstevel@tonic-gate offsetn = blkoff(fs, offset1); 1357c478bd9Sstevel@tonic-gate pplen = P2ROUNDUP(len, PAGESIZE); 1367c478bd9Sstevel@tonic-gate nbytes = MIN((pplen - curlen), 1377c478bd9Sstevel@tonic-gate (fs->fs_bsize - offsetn)); 1387c478bd9Sstevel@tonic-gate ASSERT(nbytes > 0); 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate /* 1417c478bd9Sstevel@tonic-gate * We may be reading or writing. 1427c478bd9Sstevel@tonic-gate */ 1437c478bd9Sstevel@tonic-gate DEBUGF((CE_CONT, "?ufs_rdwr_data: hole %llx - %lx\n", 1447c478bd9Sstevel@tonic-gate offset1, (iolen - curlen))); 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate if (iswrite) { 1477c478bd9Sstevel@tonic-gate printf("**WARNING: ignoring hole in write\n"); 1487c478bd9Sstevel@tonic-gate error = ENOSPC; 1497c478bd9Sstevel@tonic-gate } else { 1507c478bd9Sstevel@tonic-gate fdb_add_hole(fdbp, offset1 - offset, nbytes); 1517c478bd9Sstevel@tonic-gate } 1527c478bd9Sstevel@tonic-gate offset1 += nbytes; 1537c478bd9Sstevel@tonic-gate curlen += nbytes; 1547c478bd9Sstevel@tonic-gate continue; 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate ASSERT(contig > 0); 1587c478bd9Sstevel@tonic-gate pplen = P2ROUNDUP(len, PAGESIZE); 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate contig = MIN(contig, len - curlen); 1617c478bd9Sstevel@tonic-gate contig = P2ROUNDUP(contig, DEV_BSIZE); 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate bp = fdb_iosetup(fdbp, offset1 - offset, contig, vnodep, flags); 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate bp->b_edev = ip->i_dev; 1667c478bd9Sstevel@tonic-gate bp->b_dev = cmpdev(ip->i_dev); 1677c478bd9Sstevel@tonic-gate bp->b_blkno = bn; 1687c478bd9Sstevel@tonic-gate bp->b_file = ip->i_vnode; 1697c478bd9Sstevel@tonic-gate bp->b_offset = (offset_t)offset1; 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate if (ufsvfsp->vfs_snapshot) { 1727c478bd9Sstevel@tonic-gate fssnap_strategy(&ufsvfsp->vfs_snapshot, bp); 1737c478bd9Sstevel@tonic-gate } else { 1747c478bd9Sstevel@tonic-gate (void) bdev_strategy(bp); 1757c478bd9Sstevel@tonic-gate } 1767c478bd9Sstevel@tonic-gate io_started = 1; 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate offset1 += contig; 1797c478bd9Sstevel@tonic-gate curlen += contig; 1807c478bd9Sstevel@tonic-gate if (iswrite) 1817c478bd9Sstevel@tonic-gate lwp_stat_update(LWP_STAT_OUBLK, 1); 1827c478bd9Sstevel@tonic-gate else 1837c478bd9Sstevel@tonic-gate lwp_stat_update(LWP_STAT_INBLK, 1); 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate if ((flags & B_ASYNC) == 0) { 1867c478bd9Sstevel@tonic-gate error = biowait(bp); 1877c478bd9Sstevel@tonic-gate fdb_iodone(bp); 1887c478bd9Sstevel@tonic-gate } 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate DEBUGF((CE_CONT, "?loop ufs_rdwr_data.. off %llx len %lx\n", 1917c478bd9Sstevel@tonic-gate offset1, (iolen - curlen))); 1927c478bd9Sstevel@tonic-gate } 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate DEBUGF((CE_CONT, "?ufs_rdwr_data: off %llx len %lx pages: %p ------\n", 1957c478bd9Sstevel@tonic-gate offset1, (iolen - curlen), (void *)vnodep->v_pages)); 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate rw_exit(&ip->i_contents); 1987c478bd9Sstevel@tonic-gate rw_exit(&ip->i_ufsvfs->vfs_dqrwlock); 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate if (flags & B_ASYNC) { 2017c478bd9Sstevel@tonic-gate /* 2027c478bd9Sstevel@tonic-gate * Show that no more asynchronous IO will be added 2037c478bd9Sstevel@tonic-gate */ 2047c478bd9Sstevel@tonic-gate fdb_ioerrdone(fdbp, error); 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate if (ulp) { 2077c478bd9Sstevel@tonic-gate ufs_lockfs_end(ulp); 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate if (io_started && flags & B_ASYNC) { 2107c478bd9Sstevel@tonic-gate return (0); 2117c478bd9Sstevel@tonic-gate } else { 2127c478bd9Sstevel@tonic-gate return (error); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate } 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate /* 2177c478bd9Sstevel@tonic-gate * ufs_alloc_data - supports allocating space and reads or writes 2187c478bd9Sstevel@tonic-gate * that involve changes to file length or space allocation. 2197c478bd9Sstevel@tonic-gate * 2207c478bd9Sstevel@tonic-gate * This function is more expensive, because of the UFS log transaction, 2217c478bd9Sstevel@tonic-gate * so ufs_rdwr_data() should be used when space or file length changes 2227c478bd9Sstevel@tonic-gate * will not occur. 2237c478bd9Sstevel@tonic-gate * 2247c478bd9Sstevel@tonic-gate * Inputs: 2257c478bd9Sstevel@tonic-gate * fdb - A null pointer instructs this function to only allocate 2267c478bd9Sstevel@tonic-gate * space for the specified offset and length. 2277c478bd9Sstevel@tonic-gate * An actual fdbuffer instructs this function to perform 2287c478bd9Sstevel@tonic-gate * the read or write operation. 2297c478bd9Sstevel@tonic-gate * flags - defaults (zero value) to synchronous write 2307c478bd9Sstevel@tonic-gate * B_READ - indicates read operation 2317c478bd9Sstevel@tonic-gate * B_ASYNC - indicates perform operation asynchronously 2327c478bd9Sstevel@tonic-gate */ 2337c478bd9Sstevel@tonic-gate int 2347c478bd9Sstevel@tonic-gate ufs_alloc_data( 2357c478bd9Sstevel@tonic-gate vnode_t *vnodep, 2367c478bd9Sstevel@tonic-gate u_offset_t offset, 2377c478bd9Sstevel@tonic-gate size_t *len, 2387c478bd9Sstevel@tonic-gate fdbuffer_t *fdbp, 2397c478bd9Sstevel@tonic-gate int flags, 2407c478bd9Sstevel@tonic-gate cred_t *credp) 2417c478bd9Sstevel@tonic-gate { 2427c478bd9Sstevel@tonic-gate struct inode *ip = VTOI(vnodep); 2437c478bd9Sstevel@tonic-gate size_t done_len, io_len; 2447c478bd9Sstevel@tonic-gate int contig; 2457c478bd9Sstevel@tonic-gate u_offset_t uoff, io_off; 246*da6c28aaSamw int error = 0; /* No error occurred */ 2477c478bd9Sstevel@tonic-gate int offsetn; /* Start point this IO */ 2487c478bd9Sstevel@tonic-gate int nbytes; /* Number bytes in this IO */ 2497c478bd9Sstevel@tonic-gate daddr_t bn; 2507c478bd9Sstevel@tonic-gate struct fs *fs; 2517c478bd9Sstevel@tonic-gate struct ufsvfs *ufsvfsp = ip->i_ufsvfs; 2527c478bd9Sstevel@tonic-gate int i_size_changed = 0; 2537c478bd9Sstevel@tonic-gate u_offset_t old_i_size; 2547c478bd9Sstevel@tonic-gate struct ulockfs *ulp; 2557c478bd9Sstevel@tonic-gate int trans_size; 2567c478bd9Sstevel@tonic-gate int issync; /* UFS Log transaction */ 2577c478bd9Sstevel@tonic-gate /* synchronous when non-zero */ 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate int io_started = 0; /* No IO started */ 2607c478bd9Sstevel@tonic-gate uint_t protp = PROT_ALL; 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate ASSERT((flags & B_WRITE) == 0); 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate /* 2657c478bd9Sstevel@tonic-gate * Obey the lockfs protocol 2667c478bd9Sstevel@tonic-gate */ 2677c478bd9Sstevel@tonic-gate error = ufs_lockfs_begin_getpage(ufsvfsp, &ulp, segkmap, 0, &protp); 2687c478bd9Sstevel@tonic-gate if (error) { 2697c478bd9Sstevel@tonic-gate if ((fdbp != NULL) && (flags & B_ASYNC)) { 2707c478bd9Sstevel@tonic-gate fdb_ioerrdone(fdbp, error); 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate return (error); 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate if (ulp) { 2757c478bd9Sstevel@tonic-gate /* 2767c478bd9Sstevel@tonic-gate * Try to begin a UFS log transaction 2777c478bd9Sstevel@tonic-gate */ 2787c478bd9Sstevel@tonic-gate trans_size = TOP_GETPAGE_SIZE(ip); 2797c478bd9Sstevel@tonic-gate TRANS_TRY_BEGIN_CSYNC(ufsvfsp, issync, TOP_GETPAGE, 2807c478bd9Sstevel@tonic-gate trans_size, error); 2817c478bd9Sstevel@tonic-gate if (error == EWOULDBLOCK) { 2827c478bd9Sstevel@tonic-gate ufs_lockfs_end(ulp); 2837c478bd9Sstevel@tonic-gate if ((fdbp != NULL) && (flags & B_ASYNC)) { 2847c478bd9Sstevel@tonic-gate fdb_ioerrdone(fdbp, EDEADLK); 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate return (EDEADLK); 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate uoff = offset; 2917c478bd9Sstevel@tonic-gate io_off = offset; 2927c478bd9Sstevel@tonic-gate io_len = *len; 2937c478bd9Sstevel@tonic-gate done_len = 0; 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate DEBUGF((CE_CONT, "?ufs_alloc: off %llx len %lx size %llx fdb: %p\n", 2967c478bd9Sstevel@tonic-gate uoff, (io_len - done_len), ip->i_size, (void *)fdbp)); 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate rw_enter(&ip->i_ufsvfs->vfs_dqrwlock, RW_READER); 2997c478bd9Sstevel@tonic-gate rw_enter(&ip->i_contents, RW_WRITER); 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate ASSERT((ip->i_mode & IFMT) == IFREG); 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate fs = ip->i_fs; 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate while (error == 0 && done_len < io_len) { 3067c478bd9Sstevel@tonic-gate uoff = (u_offset_t)(io_off + done_len); 3077c478bd9Sstevel@tonic-gate offsetn = (int)blkoff(fs, uoff); 3087c478bd9Sstevel@tonic-gate nbytes = (int)MIN(fs->fs_bsize - offsetn, io_len - done_len); 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate DEBUGF((CE_CONT, "?ufs_alloc_data: offset: %llx len %x\n", 3117c478bd9Sstevel@tonic-gate uoff, nbytes)); 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate if (uoff + nbytes > ip->i_size) { 3147c478bd9Sstevel@tonic-gate /* 3157c478bd9Sstevel@tonic-gate * We are extending the length of the file. 3167c478bd9Sstevel@tonic-gate * bmap is used so that we are sure that 3177c478bd9Sstevel@tonic-gate * if we need to allocate new blocks, that it 3187c478bd9Sstevel@tonic-gate * is done here before we up the file size. 3197c478bd9Sstevel@tonic-gate */ 3207c478bd9Sstevel@tonic-gate DEBUGF((CE_CONT, "?ufs_alloc_data: grow %llx -> %llx\n", 3217c478bd9Sstevel@tonic-gate ip->i_size, uoff + nbytes)); 3227c478bd9Sstevel@tonic-gate 323303bf60bSsdebnath error = bmap_write(ip, uoff, (offsetn + nbytes), 324303bf60bSsdebnath BI_ALLOC_ONLY, NULL, credp); 3257c478bd9Sstevel@tonic-gate if (ip->i_flag & (ICHG|IUPD)) 3267c478bd9Sstevel@tonic-gate ip->i_seq++; 3277c478bd9Sstevel@tonic-gate if (error) { 3287c478bd9Sstevel@tonic-gate DEBUGF((CE_CONT, "?ufs_alloc_data: grow " 3297c478bd9Sstevel@tonic-gate "failed err: %d\n", error)); 3307c478bd9Sstevel@tonic-gate break; 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate if (fdbp != NULL) { 3337c478bd9Sstevel@tonic-gate if (uoff >= ip->i_size) { 3347c478bd9Sstevel@tonic-gate /* 3357c478bd9Sstevel@tonic-gate * Desired offset is past end of bytes 3367c478bd9Sstevel@tonic-gate * in file, so we have a hole. 3377c478bd9Sstevel@tonic-gate */ 3387c478bd9Sstevel@tonic-gate fdb_add_hole(fdbp, uoff - offset, 3397c478bd9Sstevel@tonic-gate nbytes); 3407c478bd9Sstevel@tonic-gate } else { 3417c478bd9Sstevel@tonic-gate int contig; 3427c478bd9Sstevel@tonic-gate buf_t *bp; 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate error = bmap_read(ip, uoff, &bn, 3457c478bd9Sstevel@tonic-gate &contig); 3467c478bd9Sstevel@tonic-gate if (error) { 3477c478bd9Sstevel@tonic-gate break; 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate contig = ip->i_size - uoff; 3517c478bd9Sstevel@tonic-gate contig = P2ROUNDUP(contig, DEV_BSIZE); 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate bp = fdb_iosetup(fdbp, uoff - offset, 3547c478bd9Sstevel@tonic-gate contig, vnodep, flags); 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate bp->b_edev = ip->i_dev; 3577c478bd9Sstevel@tonic-gate bp->b_dev = cmpdev(ip->i_dev); 3587c478bd9Sstevel@tonic-gate bp->b_blkno = bn; 3597c478bd9Sstevel@tonic-gate bp->b_file = ip->i_vnode; 3607c478bd9Sstevel@tonic-gate bp->b_offset = (offset_t)uoff; 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate if (ufsvfsp->vfs_snapshot) { 3637c478bd9Sstevel@tonic-gate fssnap_strategy( 3647c478bd9Sstevel@tonic-gate &ufsvfsp->vfs_snapshot, bp); 3657c478bd9Sstevel@tonic-gate } else { 3667c478bd9Sstevel@tonic-gate (void) bdev_strategy(bp); 3677c478bd9Sstevel@tonic-gate } 3687c478bd9Sstevel@tonic-gate io_started = 1; 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate lwp_stat_update(LWP_STAT_OUBLK, 1); 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate if ((flags & B_ASYNC) == 0) { 3737c478bd9Sstevel@tonic-gate error = biowait(bp); 3747c478bd9Sstevel@tonic-gate fdb_iodone(bp); 3757c478bd9Sstevel@tonic-gate if (error) { 3767c478bd9Sstevel@tonic-gate break; 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate if (contig > (ip->i_size - uoff)) { 3807c478bd9Sstevel@tonic-gate contig -= ip->i_size - uoff; 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate fdb_add_hole(fdbp, 3837c478bd9Sstevel@tonic-gate ip->i_size - offset, 3847c478bd9Sstevel@tonic-gate contig); 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate i_size_changed = 1; 3907c478bd9Sstevel@tonic-gate old_i_size = ip->i_size; 3917c478bd9Sstevel@tonic-gate UFS_SET_ISIZE(uoff + nbytes, ip); 3927c478bd9Sstevel@tonic-gate TRANS_INODE(ip->i_ufsvfs, ip); 3937c478bd9Sstevel@tonic-gate /* 3947c478bd9Sstevel@tonic-gate * file has grown larger than 2GB. Set flag 3957c478bd9Sstevel@tonic-gate * in superblock to indicate this, if it 3967c478bd9Sstevel@tonic-gate * is not already set. 3977c478bd9Sstevel@tonic-gate */ 3987c478bd9Sstevel@tonic-gate if ((ip->i_size > MAXOFF32_T) && 3997c478bd9Sstevel@tonic-gate !(fs->fs_flags & FSLARGEFILES)) { 4007c478bd9Sstevel@tonic-gate ASSERT(ufsvfsp->vfs_lfflags & UFS_LARGEFILES); 4017c478bd9Sstevel@tonic-gate mutex_enter(&ufsvfsp->vfs_lock); 4027c478bd9Sstevel@tonic-gate fs->fs_flags |= FSLARGEFILES; 4037c478bd9Sstevel@tonic-gate ufs_sbwrite(ufsvfsp); 4047c478bd9Sstevel@tonic-gate mutex_exit(&ufsvfsp->vfs_lock); 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate } else { 4077c478bd9Sstevel@tonic-gate /* 4087c478bd9Sstevel@tonic-gate * The file length is not being extended. 4097c478bd9Sstevel@tonic-gate */ 4107c478bd9Sstevel@tonic-gate error = bmap_read(ip, uoff, &bn, &contig); 4117c478bd9Sstevel@tonic-gate if (error) { 4127c478bd9Sstevel@tonic-gate DEBUGF((CE_CONT, "?ufs_alloc_data: " 4137c478bd9Sstevel@tonic-gate "bmap_read err: %d\n", error)); 4147c478bd9Sstevel@tonic-gate break; 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate if (bn != UFS_HOLE) { 4187c478bd9Sstevel@tonic-gate /* 4197c478bd9Sstevel@tonic-gate * Did not map a hole in the file 4207c478bd9Sstevel@tonic-gate */ 4217c478bd9Sstevel@tonic-gate int contig = P2ROUNDUP(nbytes, DEV_BSIZE); 4227c478bd9Sstevel@tonic-gate buf_t *bp; 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate if (fdbp != NULL) { 4257c478bd9Sstevel@tonic-gate bp = fdb_iosetup(fdbp, uoff - offset, 4267c478bd9Sstevel@tonic-gate contig, vnodep, flags); 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate bp->b_edev = ip->i_dev; 4297c478bd9Sstevel@tonic-gate bp->b_dev = cmpdev(ip->i_dev); 4307c478bd9Sstevel@tonic-gate bp->b_blkno = bn; 4317c478bd9Sstevel@tonic-gate bp->b_file = ip->i_vnode; 4327c478bd9Sstevel@tonic-gate bp->b_offset = (offset_t)uoff; 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate if (ufsvfsp->vfs_snapshot) { 4357c478bd9Sstevel@tonic-gate fssnap_strategy( 4367c478bd9Sstevel@tonic-gate &ufsvfsp->vfs_snapshot, bp); 4377c478bd9Sstevel@tonic-gate } else { 4387c478bd9Sstevel@tonic-gate (void) bdev_strategy(bp); 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate io_started = 1; 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate lwp_stat_update(LWP_STAT_OUBLK, 1); 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate if ((flags & B_ASYNC) == 0) { 4457c478bd9Sstevel@tonic-gate error = biowait(bp); 4467c478bd9Sstevel@tonic-gate fdb_iodone(bp); 4477c478bd9Sstevel@tonic-gate if (error) { 4487c478bd9Sstevel@tonic-gate break; 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate } 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate } else { 4537c478bd9Sstevel@tonic-gate /* 4547c478bd9Sstevel@tonic-gate * We read a hole in the file. 4557c478bd9Sstevel@tonic-gate * We have to allocate blocks for the hole. 4567c478bd9Sstevel@tonic-gate */ 4577c478bd9Sstevel@tonic-gate error = bmap_write(ip, uoff, (offsetn + nbytes), 458303bf60bSsdebnath BI_ALLOC_ONLY, NULL, credp); 4597c478bd9Sstevel@tonic-gate if (ip->i_flag & (ICHG|IUPD)) 4607c478bd9Sstevel@tonic-gate ip->i_seq++; 4617c478bd9Sstevel@tonic-gate if (error) { 4627c478bd9Sstevel@tonic-gate DEBUGF((CE_CONT, "?ufs_alloc_data: fill" 4637c478bd9Sstevel@tonic-gate " hole failed error: %d\n", error)); 4647c478bd9Sstevel@tonic-gate break; 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate if (fdbp != NULL) { 4677c478bd9Sstevel@tonic-gate fdb_add_hole(fdbp, uoff - offset, 4687c478bd9Sstevel@tonic-gate nbytes); 4697c478bd9Sstevel@tonic-gate } 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate done_len += nbytes; 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate if (error) { 4767c478bd9Sstevel@tonic-gate if (i_size_changed) { 4777c478bd9Sstevel@tonic-gate /* 4787c478bd9Sstevel@tonic-gate * Allocation of the blocks for the file failed. 4797c478bd9Sstevel@tonic-gate * So truncate the file size back to its original size. 4807c478bd9Sstevel@tonic-gate */ 4817c478bd9Sstevel@tonic-gate (void) ufs_itrunc(ip, old_i_size, 0, credp); 4827c478bd9Sstevel@tonic-gate } 4837c478bd9Sstevel@tonic-gate } 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate DEBUGF((CE_CONT, "?ufs_alloc: uoff %llx len %lx\n", 4867c478bd9Sstevel@tonic-gate uoff, (io_len - done_len))); 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate if ((offset + *len) < (NDADDR * fs->fs_bsize)) { 4897c478bd9Sstevel@tonic-gate *len = (size_t)(roundup(offset + *len, fs->fs_fsize) - offset); 4907c478bd9Sstevel@tonic-gate } else { 4917c478bd9Sstevel@tonic-gate *len = (size_t)(roundup(offset + *len, fs->fs_bsize) - offset); 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate /* 4957c478bd9Sstevel@tonic-gate * Flush cached pages. 4967c478bd9Sstevel@tonic-gate * 4977c478bd9Sstevel@tonic-gate * XXX - There should be no pages involved, since the I/O was performed 4987c478bd9Sstevel@tonic-gate * through the device strategy routine and the page cache was bypassed. 4997c478bd9Sstevel@tonic-gate * However, testing has demonstrated that this VOP_PUTPAGE is 5007c478bd9Sstevel@tonic-gate * necessary. Without this, data might not always be read back as it 5017c478bd9Sstevel@tonic-gate * was written. 5027c478bd9Sstevel@tonic-gate * 5037c478bd9Sstevel@tonic-gate */ 504*da6c28aaSamw (void) VOP_PUTPAGE(vnodep, 0, 0, B_INVAL, credp, NULL); 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate rw_exit(&ip->i_contents); 5077c478bd9Sstevel@tonic-gate rw_exit(&ip->i_ufsvfs->vfs_dqrwlock); 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate if ((fdbp != NULL) && (flags & B_ASYNC)) { 5107c478bd9Sstevel@tonic-gate /* 5117c478bd9Sstevel@tonic-gate * Show that no more asynchronous IO will be added 5127c478bd9Sstevel@tonic-gate */ 5137c478bd9Sstevel@tonic-gate fdb_ioerrdone(fdbp, error); 5147c478bd9Sstevel@tonic-gate } 5157c478bd9Sstevel@tonic-gate if (ulp) { 5167c478bd9Sstevel@tonic-gate /* 5177c478bd9Sstevel@tonic-gate * End the UFS Log transaction 5187c478bd9Sstevel@tonic-gate */ 5197c478bd9Sstevel@tonic-gate TRANS_END_CSYNC(ufsvfsp, error, issync, TOP_GETPAGE, 5207c478bd9Sstevel@tonic-gate trans_size); 5217c478bd9Sstevel@tonic-gate ufs_lockfs_end(ulp); 5227c478bd9Sstevel@tonic-gate } 5237c478bd9Sstevel@tonic-gate if (io_started && (flags & B_ASYNC)) { 5247c478bd9Sstevel@tonic-gate return (0); 5257c478bd9Sstevel@tonic-gate } else { 5267c478bd9Sstevel@tonic-gate return (error); 5277c478bd9Sstevel@tonic-gate } 5287c478bd9Sstevel@tonic-gate } 529