FreeBSD/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
/*
 * Get data to generate a TX_WRITE intent log record.
 */
Get data to generate a TX_WRITE intent log record.
Get data to generate a TX_WRITE intent log record .
int
zfs_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio)
{
	zfsvfs_t *zfsvfs = arg;
	objset_t *os = zfsvfs->z_os;
	znode_t *zp;
	uint64_t object = lr->lr_foid;
	uint64_t offset = lr->lr_offset;
	uint64_t size = lr->lr_length;
	blkptr_t *bp = &lr->lr_blkptr;
	dmu_buf_t *db;
	zgd_t *zgd;
	int error = 0;
	ASSERT(zio != NULL);
	ASSERT(size != 0);
	if (zfs_zget(zfsvfs, object, &zp) != 0)
		return (SET_ERROR(ENOENT));
	if (zp->z_unlinked) {
		VN_RELE_ASYNC(ZTOV(zp),
		    dsl_pool_vnrele_taskq(dmu_objset_pool(os)));
		return (SET_ERROR(ENOENT));
	}
	zgd = (zgd_t *)kmem_zalloc(sizeof (zgd_t), KM_SLEEP);
	zgd->zgd_zilog = zfsvfs->z_log;
	zgd->zgd_private = zp;
	if (buf != NULL) { 
		zgd->zgd_rl = zfs_range_lock(zp, offset, size, RL_READER);
		if (offset >= zp->z_size) {
			error = SET_ERROR(ENOENT);
		} else {
			error = dmu_read(os, object, offset, size, buf,
			    DMU_READ_NO_PREFETCH);
		}
		ASSERT(error == 0 || error == ENOENT);
	} else { 
		for (;;) {
			uint64_t blkoff;
			size = zp->z_blksz;
			blkoff = ISP2(size) ? P2PHASE(offset, size) : offset;
			offset -= blkoff;
			zgd->zgd_rl = zfs_range_lock(zp, offset, size,
			    RL_READER);
			if (zp->z_blksz == size)
				break;
			offset += blkoff;
			zfs_range_unlock(zgd->zgd_rl);
		}
		if (lr->lr_offset >= zp->z_size)
			error = SET_ERROR(ENOENT);
#ifdef DEBUG
		if (zil_fault_io) {
			error = SET_ERROR(EIO);
			zil_fault_io = 0;
		}
#endif
		if (error == 0)
			error = dmu_buf_hold(os, object, offset, zgd, &db,
			    DMU_READ_NO_PREFETCH);
		if (error == 0) {
			blkptr_t *obp = dmu_buf_get_blkptr(db);
			if (obp) {
				ASSERT(BP_IS_HOLE(bp));
				*bp = *obp;
			}
			zgd->zgd_db = db;
			zgd->zgd_bp = bp;
			ASSERT(db->db_offset == offset);
			ASSERT(db->db_size == size);
			error = dmu_sync(zio, lr->lr_common.lrc_txg,
			    zfs_get_done, zgd);
			ASSERT(error || lr->lr_length <= zp->z_blksz);
			if (error == 0)
				return (0);
			if (error == EALREADY) {
				lr->lr_common.lrc_txtype = TX_WRITE2;
				error = 0;
			}
		}
	}
	zfs_get_done(zgd, error);
	return (error);
}
int zfs_get_data ( void * arg , lr_write_t * lr , char * buf , zio_t * zio ) { zfsvfs_t * zfsvfs = arg ; objset_t * os = zfsvfs -> z_os ; znode_t * zp ; uint64_t object = lr -> lr_foid ; uint64_t offset = lr -> lr_offset ; uint64_t size = lr -> lr_length ; blkptr_t * bp = & lr -> lr_blkptr ; dmu_buf_t * db ; zgd_t * zgd ; int error = 0 ; ASSERT ( zio != NULL ) ; ASSERT ( size != 0 ) ; if ( zfs_zget ( zfsvfs , object , & zp ) != 0 ) return ( SET_ERROR ( ENOENT ) ) ; if ( zp -> z_unlinked ) { VN_RELE_ASYNC ( ZTOV ( zp ) , dsl_pool_vnrele_taskq ( dmu_objset_pool ( os ) ) ) ; return ( SET_ERROR ( ENOENT ) ) ; } zgd = ( zgd_t * ) kmem_zalloc ( sizeof ( zgd_t ) , KM_SLEEP ) ; zgd -> zgd_zilog = zfsvfs -> z_log ; zgd -> zgd_private = zp ; if ( buf != NULL ) { zgd -> zgd_rl = zfs_range_lock ( zp , offset , size , RL_READER ) ; if ( offset >= zp -> z_size ) { error = SET_ERROR ( ENOENT ) ; } else { error = dmu_read ( os , object , offset , size , buf , DMU_READ_NO_PREFETCH ) ; } ASSERT ( error == 0 || error == ENOENT ) ; } else { for ( ; ; ) { uint64_t blkoff ; size = zp -> z_blksz ; blkoff = ISP2 ( size ) ? P2PHASE ( offset , size ) : offset ; offset -= blkoff ; zgd -> zgd_rl = zfs_range_lock ( zp , offset , size , RL_READER ) ; if ( zp -> z_blksz == size ) break ; offset += blkoff ; zfs_range_unlock ( zgd -> zgd_rl ) ; } if ( lr -> lr_offset >= zp -> z_size ) error = SET_ERROR ( ENOENT ) ; #ifdef DEBUG if ( zil_fault_io ) { error = SET_ERROR ( EIO ) ; zil_fault_io = 0 ; } #endif if ( error == 0 ) error = dmu_buf_hold ( os , object , offset , zgd , & db , DMU_READ_NO_PREFETCH ) ; if ( error == 0 ) { blkptr_t * obp = dmu_buf_get_blkptr ( db ) ; if ( obp ) { ASSERT ( BP_IS_HOLE ( bp ) ) ; * bp = * obp ; } zgd -> zgd_db = db ; zgd -> zgd_bp = bp ; ASSERT ( db -> db_offset == offset ) ; ASSERT ( db -> db_size == size ) ; error = dmu_sync ( zio , lr -> lr_common . lrc_txg , zfs_get_done , zgd ) ; ASSERT ( error || lr -> lr_length <= zp -> z_blksz ) ; if ( error == 0 ) return ( 0 ) ; if ( error == EALREADY ) { lr -> lr_common . lrc_txtype = TX_WRITE2 ; error = 0 ; } } } zfs_get_done ( zgd , error ) ; return ( error ) ; }
Get data to generate a TX_WRITE intent log record.
Get data to generate a TX_WRITE intent log record .
/*
	 * Nothing to do if the file has been removed
	 */ /*
		 * Release the vnode asynchronously as we currently have the
		 * txg stopped from syncing.
		 */ /*
	 * Write records come in two flavors: immediate and indirect.
	 * For small writes it's cheaper to store the data with the
	 * log record (immediate); for large writes it's cheaper to
	 * sync the data and get a pointer to it (indirect) so that
	 * we don't have to write the data twice.
	 */ /* immediate write */ /* test for truncation needs to be done while range locked */ /* indirect write */ /*
		 * Have to lock the whole block to ensure when it's
		 * written out and it's checksum is being calculated
		 * that no one can change the data. We need to re-check
		 * blocksize after we get the lock in case it's changed!
		 */ /* test for truncation needs to be done while range locked */ /*
			 * On success, we need to wait for the write I/O
			 * initiated by dmu_sync() to complete before we can
			 * release this dbuf.  We will finish everything up
			 * in the zfs_get_done() callback.
			 */