Skip site navigation (1)Skip section navigation (2)
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
Message-ID:  <200111300626.fAU6QxZ22980@westhost36.westhost.net>

next in thread | raw e-mail | index | archive | help

>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 <mini@haikugeek.com>
 Reply-To: Jonathan Mini <mini@haikugeek.com>
 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




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200111300626.fAU6QxZ22980>