From owner-freebsd-bugs Thu Nov 29 22:30:46 2001 Delivered-To: freebsd-bugs@hub.freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.org [216.136.204.21]) by hub.freebsd.org (Postfix) with ESMTP id DD48C37B41E for ; Thu, 29 Nov 2001 22:30:00 -0800 (PST) Received: (from gnats@localhost) by freefall.freebsd.org (8.11.6/8.11.6) id fAU6U0q75661; Thu, 29 Nov 2001 22:30:00 -0800 (PST) (envelope-from gnats) Received: from westhost36.westhost.net (westhost36.westhost.net [216.71.84.209]) by hub.freebsd.org (Postfix) with ESMTP id D9E4F37B41C for ; Thu, 29 Nov 2001 22:27:52 -0800 (PST) Received: (from haikugeek@localhost) by westhost36.westhost.net (8.11.6/8.11.6) id fAU6QxZ22980 for FreeBSD-gnats-submit@freebsd.org; Fri, 30 Nov 2001 00:26:59 -0600 Message-Id: <200111300626.fAU6QxZ22980@westhost36.westhost.net> Date: Fri, 30 Nov 2001 00:26:59 -0600 From: haikugeek@westhost36.westhost.net To: FreeBSD-gnats-submit@freebsd.org Subject: kern/32389: add ufs write support to /boot/loader and associated changes Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.org >Number: 32389 >Category: kern >Synopsis: add ufs write support to /boot/loader and associated changes >Confidential: no >Severity: non-critical >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Thu Nov 29 22:30:00 PST 2001 >Closed-Date: >Last-Modified: >Originator: Jonathan Mini >Release: FreeBSD 5.0-CURRENT i386 >Organization: Array Networks, Inc. >Environment: System: FreeBSD stylus.arraynetworks.net 4.3-CLICKARRAY FreeBSD 4.3-CLICKARRAY #0: Fri May 4 07:05:08 GMT 2001 terry@classix.clickarray.com:/usr/src/sys/compile/CA1000 i386 >Description: The third stage boot loader (/boot/loader) can currently only read to files on a UFS partition. This does not allow functionality of things like nextboot(8), or scripts that update configuration information before booting. >How-To-Repeat: Start /boot/loader, interrupt the autoboot sequence, and just try to write a script that writes to the disk. Ha! You can't can you? >Fix: Apply this patch : (also at http://www.haikugeek.com/freebsd/5.0-boot-libstand.diff) Index: sys/boot/common/bcache.c =================================================================== RCS file: /usr/FreeBSD/src/sys/boot/common/bcache.c,v retrieving revision 1.8 diff -c -r1.8 bcache.c *** sys/boot/common/bcache.c 2000/08/03 09:13:53 1.8 --- sys/boot/common/bcache.c 2001/11/22 00:26:58 *************** *** 63,68 **** --- 63,69 ---- static u_int bcache_flushes; static u_int bcache_bcount; + static void bcache_invalidate(daddr_t blkno); static void bcache_insert(caddr_t buf, daddr_t blkno); static int bcache_lookup(caddr_t buf, daddr_t blkno); *************** *** 116,131 **** } } ! /* ! * Handle a transfer request; fill in parts of the request that can * be satisfied by the cache, use the supplied strategy routine to do * device I/O and then use the I/O results to populate the cache. - * - * Requests larger than 1/2 the cache size will be bypassed and go - * directly to the disk. XXX tune this. */ ! int ! bcache_strategy(void *devdata, int unit, int rw, daddr_t blk, size_t size, char *buf, size_t *rsize) { static int bcache_unit = -1; --- 117,161 ---- } } ! /* ! * Handle a write request; write directly to the disk, and populate the ! * cache with the new values. ! */ ! static int ! write_strategy(void *devdata, int unit, int rw, daddr_t blk, size_t size, ! char *buf, size_t *rsize) ! { ! struct bcache_devdata *dd = (struct bcache_devdata *)devdata; ! daddr_t i, nblk; ! int err; ! ! nblk = size / bcache_blksize; ! ! /* Invalidate the blocks being written */ ! for (i = 0; i < nblk; i++) { ! bcache_invalidate(blk + i); ! } ! ! /* Write the blocks */ ! err = dd->dv_strategy(dd->dv_devdata, rw, blk, size, buf, rsize); ! ! /* Populate the block cache with the new data */ ! if (err == 0) { ! for (i = 0; i < nblk; i++) { ! bcache_insert(buf + (i * bcache_blksize),blk + i); ! } ! } ! ! return err; ! } ! ! /* ! * Handle a read request; fill in parts of the request that can * be satisfied by the cache, use the supplied strategy routine to do * device I/O and then use the I/O results to populate the cache. */ ! static int ! read_strategy(void *devdata, int unit, int rw, daddr_t blk, size_t size, char *buf, size_t *rsize) { static int bcache_unit = -1; *************** *** 134,153 **** daddr_t p_blk, i, j, nblk; caddr_t p_buf; - bcache_ops++; - - if(bcache_unit != unit) { - bcache_flush(); - bcache_unit = unit; - } - - /* bypass large requests, or when the cache is inactive */ - if ((bcache_data == NULL) || ((size * 2 / bcache_blksize) > bcache_nblks)) { - DEBUG("bypass %d from %d", size / bcache_blksize, blk); - bcache_bypasses++; - return(dd->dv_strategy(dd->dv_devdata, rw, blk, size, buf, rsize)); - } - nblk = size / bcache_blksize; result = 0; --- 164,169 ---- *************** *** 201,207 **** --- 217,260 ---- return(result); } + /* + * Requests larger than 1/2 the cache size will be bypassed and go + * directly to the disk. XXX tune this. + */ + int + bcache_strategy(void *devdata, int unit, int rw, daddr_t blk, size_t size, + char *buf, size_t *rsize) + { + static int bcache_unit = -1; + struct bcache_devdata *dd = (struct bcache_devdata *)devdata; + int p_size, result; + daddr_t p_blk, i, j, nblk; + caddr_t p_buf; + bcache_ops++; + + if(bcache_unit != unit) { + bcache_flush(); + bcache_unit = unit; + } + + /* bypass large requests, or when the cache is inactive */ + if ((bcache_data == NULL) || ((size * 2 / bcache_blksize) > bcache_nblks)) { + DEBUG("bypass %d from %d", size / bcache_blksize, blk); + bcache_bypasses++; + return(dd->dv_strategy(dd->dv_devdata, rw, blk, size, buf, rsize)); + } + + switch (rw) { + case F_READ: + return read_strategy(devdata, unit, rw, blk, size, buf, rsize); + case F_WRITE: + return write_strategy(devdata, unit, rw, blk, size, buf, rsize); + } + return -1; + } + + /* * Insert a block into the cache. Retire the oldest block to do so, if required. * *************** *** 259,264 **** --- 312,335 ---- return(0); } return(ENOENT); + } + + /* + * Invalidate a block from the cache. + */ + static void + bcache_invalidate(daddr_t blkno) + { + u_int i; + + for (i = 0; i < bcache_nblks; i++) { + if (bcache_ctl[i].bc_blkno == blkno) { + bcache_ctl[i].bc_count = -1; + bcache_ctl[i].bc_blkno = -1; + DEBUG("invalidate blk %d", blkno); + break; + } + } } COMMAND_SET(bcachestat, "bcachestat", "get disk block cache stats", command_bcache); Index: sys/boot/ficl/loader.c =================================================================== RCS file: /usr/FreeBSD/src/sys/boot/ficl/loader.c,v retrieving revision 1.5 diff -c -r1.5 loader.c *** sys/boot/ficl/loader.c 2001/09/04 08:51:15 1.5 --- sys/boot/ficl/loader.c 2001/11/16 06:31:45 *************** *** 371,392 **** /* fopen - open a file and return new fd on stack. * ! * fopen ( count ptr -- fd ) */ static void pfopen(FICL_VM *pVM) { ! int fd; ! char *p; #if FICL_ROBUST > 1 ! vmCheckStack(pVM, 2, 1); #endif ! (void)stackPopINT(pVM->pStack); /* don't need count value */ ! p = stackPopPtr(pVM->pStack); ! fd = open(p, O_RDONLY); stackPushINT(pVM->pStack, fd); return; ! } /* fclose - close a file who's fd is on stack. * --- 371,407 ---- /* fopen - open a file and return new fd on stack. * ! * fopen ( ptr count mode -- fd ) */ static void pfopen(FICL_VM *pVM) { ! int mode, fd, count; ! char *ptr, *name; #if FICL_ROBUST > 1 ! vmCheckStack(pVM, 3, 1); #endif ! ! mode = stackPopINT(pVM->pStack); /* get mode */ ! count = stackPopINT(pVM->pStack); /* get count */ ! ptr = stackPopPtr(pVM->pStack); /* get ptr */ ! ! if ((count < 0) || (ptr == NULL)) { ! stackPushINT(pVM->pStack, -1); ! return; ! } ! ! /* ensure that the string is null terminated */ ! name = (char *)malloc(count+1); ! bcopy(ptr,name,count); ! name[count] = 0; ! ! /* open the file */ ! fd = open(name, mode); ! free(name); stackPushINT(pVM->pStack, fd); return; ! } /* fclose - close a file who's fd is on stack. * *************** *** 444,449 **** --- 459,504 ---- return; } + /* fwrite - write file contents + * + * fwrite ( fd buf nbytes -- nwritten ) + */ + static void pfwrite(FICL_VM *pVM) + { + int fd, len; + char *buf; + + #if FICL_ROBUST > 1 + vmCheckStack(pVM, 3, 1); + #endif + len = stackPopINT(pVM->pStack); /* get number of bytes to read */ + buf = stackPopPtr(pVM->pStack); /* get buffer */ + fd = stackPopINT(pVM->pStack); /* get fd */ + if (len > 0 && buf && fd != -1) + stackPushINT(pVM->pStack, write(fd, buf, len)); + else + stackPushINT(pVM->pStack, -1); + return; + } + + /* fseek - seek to a new position in a file + * + * fseek ( fd ofs whence -- pos ) + */ + static void pfseek(FICL_VM *pVM) + { + int fd, pos, whence; + + #if FICL_ROBUST > 1 + vmCheckStack(pVM, 3, 1); + #endif + whence = stackPopINT(pVM->pStack); + pos = stackPopINT(pVM->pStack); + fd = stackPopINT(pVM->pStack); + stackPushINT(pVM->pStack, lseek(fd, pos, whence)); + return; + } + /* key - get a character from stdin * * key ( -- char ) *************** *** 568,573 **** --- 623,630 ---- dictAppendWord(dp, "fread", pfread, FW_DEFAULT); dictAppendWord(dp, "fload", pfload, FW_DEFAULT); dictAppendWord(dp, "fkey", fkey, FW_DEFAULT); + dictAppendWord(dp, "fseek", pfseek, FW_DEFAULT); + dictAppendWord(dp, "fwrite", pfwrite, FW_DEFAULT); dictAppendWord(dp, "key", key, FW_DEFAULT); dictAppendWord(dp, "key?", keyQuestion, FW_DEFAULT); dictAppendWord(dp, "ms", ms, FW_DEFAULT); Index: sys/boot/forth/pnp.4th =================================================================== RCS file: /usr/FreeBSD/src/sys/boot/forth/pnp.4th,v retrieving revision 1.1 diff -c -r1.1 pnp.4th *** sys/boot/forth/pnp.4th 2000/09/08 17:13:24 1.1 --- sys/boot/forth/pnp.4th 2001/11/15 20:26:57 *************** *** 158,164 **** : load-pnp 0 to end_of_file? reset_line_reading ! s" /boot/pnpid.conf" fopen fd ! fd @ -1 <> if begin end_of_file? 0= --- 158,164 ---- : load-pnp 0 to end_of_file? reset_line_reading ! s" /boot/pnpid.conf" O_RDONLY fopen fd ! fd @ -1 <> if begin end_of_file? 0= Index: sys/boot/forth/support.4th =================================================================== RCS file: /usr/FreeBSD/src/sys/boot/forth/support.4th,v retrieving revision 1.13 diff -c -r1.13 support.4th *** sys/boot/forth/support.4th 2000/09/25 11:36:55 1.13 --- sys/boot/forth/support.4th 2001/11/15 20:43:41 *************** *** 80,85 **** --- 80,95 ---- 8 constant before_load_error 9 constant after_load_error + \ I/O constants + + 0 constant SEEK_SET + 1 constant SEEK_CUR + 2 constant SEEK_END + + 0 constant O_RDONLY + 1 constant O_WRONLY + 2 constant O_RDWR + \ Crude structure support : structure: *************** *** 931,952 **** only forth also support-functions definitions - : create_null_terminated_string { addr len -- addr' len } - len char+ allocate if out_of_memory throw then - >r - addr r@ len move - 0 r@ len + c! - r> len - ; - \ Interface to loading conf files : load_conf ( addr len -- ) 0 to end_of_file? reset_line_reading - create_null_terminated_string over >r ! fopen fd ! r> free-memory fd @ -1 = if open_error throw then ['] process_conf catch --- 941,954 ---- only forth also support-functions definitions \ Interface to loading conf files : load_conf ( addr len -- ) + ." load_conf" cr 0 to end_of_file? reset_line_reading over >r ! O_RDONLY fopen fd ! r> free-memory fd @ -1 = if open_error throw then ['] process_conf catch Index: sys/boot/i386/libi386/biosdisk.c =================================================================== RCS file: /usr/FreeBSD/src/sys/boot/i386/libi386/biosdisk.c,v retrieving revision 1.33 diff -c -r1.33 biosdisk.c *** sys/boot/i386/libi386/biosdisk.c 2000/11/02 23:28:12 1.33 --- sys/boot/i386/libi386/biosdisk.c 2001/11/22 00:33:45 *************** *** 100,105 **** --- 100,107 ---- static int bd_getgeom(struct open_disk *od); static int bd_read(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest); + static int bd_write(struct open_disk *od, daddr_t dblk, int blks, + caddr_t dest); static int bd_int13probe(struct bdinfo *bd); *************** *** 779,788 **** DEBUG("open_disk %p", od); - if (rw != F_READ) - return(EROFS); ! blks = size / BIOSDISK_SECSIZE; DEBUG("read %d from %d to %p", blks, dblk, buf); --- 781,789 ---- DEBUG("open_disk %p", od); ! switch(rw){ ! case F_READ: blks = size / BIOSDISK_SECSIZE; DEBUG("read %d from %d to %p", blks, dblk, buf); *************** *** 804,809 **** --- 805,837 ---- if (rsize) *rsize = size; return (0); + break; + + case F_WRITE : + blks = size / BIOSDISK_SECSIZE; + DEBUG("write %d from %d to %p", blks, dblk, buf); + + if (rsize) + *rsize = 0; + if (blks && bd_write(od, dblk, blks, buf)) { + DEBUG("write error"); + return (EIO); + } + #ifdef BD_SUPPORT_FRAGS + if(fragsize) { + DEBUG("Attempted to write a frag"); + return (EIO); + } + #endif + + if (rsize) + *rsize = size; + return (0); + default: + /* DO NOTHING */ + } + + return EROFS; } /* Max number of sectors to bounce-buffer if the request crosses a 64k boundary */ *************** *** 940,945 **** --- 968,1111 ---- return(0); } + + static int + bd_write(struct open_disk *od, daddr_t dblk, int blks, caddr_t dest) + { + u_int x, bpc, cyl, hd, sec, result, resid, retry, maxfer; + caddr_t p, xp, bbuf, breg; + + /* Just in case some idiot actually tries to read -1 blocks... */ + if (blks < 0) + return (-1); + + bpc = (od->od_sec * od->od_hds); /* blocks per cylinder */ + resid = blks; + p = dest; + + /* Decide whether we have to bounce */ + if ((od->od_unit < 0x80) && + ((VTOP(dest) >> 16) != (VTOP(dest + blks * BIOSDISK_SECSIZE) >> 16))) { + + /* + * There is a 64k physical boundary somewhere in the destination buffer, so we have + * to arrange a suitable bounce buffer. Allocate a buffer twice as large as we + * need to. Use the bottom half unless there is a break there, in which case we + * use the top half. + */ + + x = min(FLOPPY_BOUNCEBUF, (unsigned)blks); + bbuf = malloc(x * 2 * BIOSDISK_SECSIZE); + if (((u_int32_t)VTOP(bbuf) & 0xffff0000) == ((u_int32_t)VTOP(dest + x * BIOSDISK_SECSIZE) & 0xffff0000)) { + breg = bbuf; + } else { + breg = bbuf + x * BIOSDISK_SECSIZE; + } + maxfer = x; /* limit transfers to bounce region size */ + } else { + breg = bbuf = NULL; + maxfer = 0; + } + + while (resid > 0) { + x = dblk; + cyl = x / bpc; /* block # / blocks per cylinder */ + x %= bpc; /* block offset into cylinder */ + hd = x / od->od_sec; /* offset / blocks per track */ + sec = x % od->od_sec; /* offset into track */ + + /* play it safe and don't cross track boundaries (XXX this is probably unnecessary) */ + x = min(od->od_sec - sec, resid); + if (maxfer > 0) + x = min(x, maxfer); /* fit bounce buffer */ + + /* where do we transfer to? */ + xp = bbuf == NULL ? p : breg; + + /* correct sector number for 1-based BIOS numbering */ + sec++; + + + /* Put your Data In, Put your Data out, + Put your Data In, and shake it all about + */ + if (bbuf != NULL) + bcopy(p, breg, x * BIOSDISK_SECSIZE); + p += (x * BIOSDISK_SECSIZE); + dblk += x; + resid -= x; + + /* Loop retrying the operation a couple of times. The BIOS may also retry. */ + for (retry = 0; retry < 3; retry++) { + /* if retrying, reset the drive */ + if (retry > 0) { + v86.ctl = V86_FLAGS; + v86.addr = 0x13; + v86.eax = 0; + v86.edx = od->od_unit; + v86int(); + } + + if(cyl > 1023) { + /* use EDD if the disk supports it, otherwise, return error */ + if(od->od_flags & BD_MODEEDD1) { + static unsigned short packet[8]; + + packet[0] = 0x10; + packet[1] = x; + packet[2] = VTOPOFF(xp); + packet[3] = VTOPSEG(xp); + packet[4] = dblk & 0xffff; + packet[5] = dblk >> 16; + packet[6] = 0; + packet[7] = 0; + v86.ctl = V86_FLAGS; + v86.addr = 0x13; + /* Should we Write with verify ?? 0x4302 ? */ + v86.eax = 0x4300; + v86.edx = od->od_unit; + v86.ds = VTOPSEG(packet); + v86.esi = VTOPOFF(packet); + v86int(); + result = (v86.efl & 0x1); + if(result == 0) + break; + } else { + result = 1; + break; + } + } else { + /* Use normal CHS addressing */ + v86.ctl = V86_FLAGS; + v86.addr = 0x13; + v86.eax = 0x300 | x; + v86.ecx = ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec; + v86.edx = (hd << 8) | od->od_unit; + v86.es = VTOPSEG(xp); + v86.ebx = VTOPOFF(xp); + v86int(); + result = (v86.efl & 0x1); + if (result == 0) + break; + } + } + + DEBUG("%d sectors from %d/%d/%d to %p (0x%x) %s", x, cyl, hd, sec - 1, p, VTOP(p), result ? "failed" : "ok"); + /* BUG here, cannot use v86 in printf because putchar uses it too */ + DEBUG("ax = 0x%04x cx = 0x%04x dx = 0x%04x status 0x%x", + 0x200 | x, ((cyl & 0xff) << 8) | ((cyl & 0x300) >> 2) | sec, (hd << 8) | od->od_unit, (v86.eax >> 8) & 0xff); + if (result) { + if (bbuf != NULL) + free(bbuf); + return(-1); + } + } + + /* hexdump(dest, (blks * BIOSDISK_SECSIZE)); */ + if (bbuf != NULL) + free(bbuf); + return(0); + } static int bd_getgeom(struct open_disk *od) { Index: lib/libstand/stand.h =================================================================== RCS file: /usr/FreeBSD/src/lib/libstand/stand.h,v retrieving revision 1.26 diff -c -r1.26 stand.h *** lib/libstand/stand.h 2001/09/18 13:01:12 1.26 --- lib/libstand/stand.h 2001/11/16 01:43:52 *************** *** 256,262 **** extern int open(const char *, int); #define O_RDONLY 0x0 ! #define O_WRONLY 0x1 /* writing not (yet?) supported */ #define O_RDWR 0x2 extern int close(int); extern void closeall(void); --- 257,263 ---- extern int open(const char *, int); #define O_RDONLY 0x0 ! #define O_WRONLY 0x1 #define O_RDWR 0x2 extern int close(int); extern void closeall(void); Index: lib/libstand/ufs.c =================================================================== RCS file: /usr/FreeBSD/src/lib/libstand/ufs.c,v retrieving revision 1.7 diff -c -r1.7 ufs.c *** lib/libstand/ufs.c 2001/09/30 22:28:01 1.7 --- lib/libstand/ufs.c 2001/11/16 01:43:52 *************** *** 82,87 **** --- 82,88 ---- #endif static int ufs_open(const char *path, struct open_file *f); + static int ufs_write(struct open_file *f, void *buf, size_t size, size_t *resid); static int ufs_close(struct open_file *f); static int ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid); static off_t ufs_seek(struct open_file *f, off_t offset, int where); *************** *** 93,99 **** ufs_open, ufs_close, ufs_read, ! null_write, ufs_seek, ufs_stat, ufs_readdir --- 94,100 ---- ufs_open, ufs_close, ufs_read, ! ufs_write, ufs_seek, ufs_stat, ufs_readdir *************** *** 122,127 **** --- 123,129 ---- static int read_inode(ino_t, struct open_file *); static int block_map(struct open_file *, daddr_t, daddr_t *); static int buf_read_file(struct open_file *, char **, size_t *); + static int buf_write_file(struct open_file *, char *, size_t *); static int search_directory(char *, struct open_file *, ino_t *); #ifdef COMPAT_UFS static void ffs_oldfscompat(struct fs *); *************** *** 288,293 **** --- 290,371 ---- } /* + * Write a portion of a file from an internal buffer. + */ + static int + buf_write_file(f, buf_p, size_p) + struct open_file *f; + char *buf_p; + size_t *size_p; /* out */ + { + register struct file *fp = (struct file *)f->f_fsdata; + register struct fs *fs = fp->f_fs; + long off; + register daddr_t file_block; + daddr_t disk_block; + size_t block_size; + int rc; + + /* + * Calculate the starting block address and offset. + */ + off = blkoff(fs, fp->f_seekp); + file_block = lblkno(fs, fp->f_seekp); + block_size = dblksize(fs, &fp->f_di, file_block); + + rc = block_map(f, file_block, &disk_block); + if (rc) + return (rc); + + if (disk_block == 0) + return (EFBIG); /* Because we can't allocate space on the drive */ + + /* + * Truncate buffer at end of file, and at the end of + * this block. + */ + if (*size_p > fp->f_di.di_size - fp->f_seekp) + *size_p = fp->f_di.di_size - fp->f_seekp; + if (*size_p > block_size - off) + *size_p = block_size - off; + + /* + * If we don't entirely occlude the block and it's not + * in memory already, read it in first. + */ + if (((off > 0) || (*size_p + off < block_size)) && + (file_block != fp->f_buf_blkno)) { + + if (fp->f_buf == (char *)0) + fp->f_buf = malloc(fs->fs_bsize); + + twiddle(); + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, + fsbtodb(fs, disk_block), + block_size, fp->f_buf, &fp->f_buf_size); + if (rc) + return (rc); + + fp->f_buf_blkno = file_block; + } + + /* + * Copy the user data into the cached block. + */ + bcopy(buf_p,fp->f_buf + off,*size_p); + + /* + * Write the block out to storage. + */ + + twiddle(); + rc = (f->f_dev->dv_strategy)(f->f_devdata, F_WRITE, + fsbtodb(fs, disk_block), + block_size, fp->f_buf, &fp->f_buf_size); + return (rc); + } + + /* * Read a portion of a file into an internal buffer. Return * the location in the buffer and the amount in the buffer. */ *************** *** 310,322 **** block_size = dblksize(fs, &fp->f_di, file_block); if (file_block != fp->f_buf_blkno) { rc = block_map(f, file_block, &disk_block); if (rc) return (rc); - if (fp->f_buf == (char *)0) - fp->f_buf = malloc(fs->fs_bsize); - if (disk_block == 0) { bzero(fp->f_buf, block_size); fp->f_buf_size = block_size; --- 388,400 ---- block_size = dblksize(fs, &fp->f_di, file_block); if (file_block != fp->f_buf_blkno) { + if (fp->f_buf == (char *)0) + fp->f_buf = malloc(fs->fs_bsize); + rc = block_map(f, file_block, &disk_block); if (rc) return (rc); if (disk_block == 0) { bzero(fp->f_buf, block_size); fp->f_buf_size = block_size; *************** *** 648,653 **** --- 726,768 ---- csize = buf_size; bcopy(buf, addr, csize); + + fp->f_seekp += csize; + addr += csize; + size -= csize; + } + if (resid) + *resid = size; + return (rc); + } + + /* + * Write to a portion of an already allocated file. + * Cross block boundaries when necessary. Can not + * extend the file. + */ + static int + ufs_write(f, start, size, resid) + struct open_file *f; + void *start; + size_t size; + size_t *resid; /* out */ + { + register struct file *fp = (struct file *)f->f_fsdata; + size_t csize; + int rc = 0; + register char *addr = start; + + csize = size; + while ((size != 0) && (csize != 0)) { + if (fp->f_seekp >= fp->f_di.di_size) + break; + + if (csize >= 512) csize = 512; /* XXX */ + + rc = buf_write_file(f, addr, &csize); + if (rc) + break; fp->f_seekp += csize; addr += csize; >Release-Note: >Audit-Trail: >Unformatted: To: FreeBSD-gnats-submit@freebsd.org Subject: add ufs write support to /boot/loader and associated changes From: Jonathan Mini Reply-To: Jonathan Mini Cc: X-send-pr-version: 3.113 X-GNATS-Notify: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message