Version 1.3.15
[yaboot.git] / second / fs_ext2.c
index 82db81a2e7bf1a9864c97f71d72ede81014773a0..67571f28fadda668e967cde6e263a2ce37dda0a8 100644 (file)
@@ -35,6 +35,7 @@
 #include "fs.h"
 #include "errors.h"
 #include "debug.h"
+#include "bootinfo.h"
 
 #define FAST_VERSION
 #define MAX_READ_RANGE 256
@@ -65,7 +66,7 @@ struct fs_t ext2_filesystem =
 };
 
 /* IO manager structure for the ext2 library */
+
 static errcode_t linux_open (const char *name, int flags, io_channel * channel);
 static errcode_t linux_close (io_channel channel);
 static errcode_t linux_set_blksize (io_channel channel, int blksize);
@@ -93,6 +94,7 @@ static io_manager linux_io_manager = &struct_linux_manager;
 static int opened = 0;         /* We can't open twice ! */
 static unsigned int bs;                /* Blocksize */
 static unsigned long long doff;        /* Byte offset where partition starts */
+static unsigned long long dend;        /* Byte offset where partition ends */
 static ino_t root,cwd;
 static ext2_filsys fs = 0;
 static struct boot_file_t* cur_file;
@@ -129,7 +131,7 @@ ext2_open(  struct boot_file_t*     file,
      int error = FILE_ERR_NOTFOUND;
      static char buffer[1024];
      int ofopened = 0;
-       
+
      DEBUG_ENTER;
      DEBUG_OPEN;
 
@@ -143,23 +145,34 @@ ext2_open(        struct boot_file_t*     file,
      }
 
      fs = NULL;
-       
+
      /* We don't care too much about the device block size since we run
       * thru the deblocker. We may have to change that is we plan to be
       * compatible with older versions of OF
       */
      bs = 1024;
-     doff = 0;
-     if (part)
+
+     /*
+      * On the other hand, we do care about the actual size of the
+      * partition, reads or seeks past the end may cause undefined
+      * behavior on some devices.  A netapp that tries to seek and
+      * read past the end of the lun takes ~30 secs to recover per
+      * attempt.
+      */
+     doff = dend = 0;
+     if (part) {
          doff = (unsigned long long)(part->part_start) * part->blocksize;
+         dend = doff + (unsigned long long)part->part_size * part->blocksize;
+     }
      cur_file = file;
 
 
-     DEBUG_F("partition offset: %Lu\n", doff);
+     DEBUG_F("partition offset: %Lx, end: %Lx\n", doff, dend);
 
      /* Open the OF device for the entire disk */
      strncpy(buffer, dev_name, 1020);
-     strcat(buffer, ":0");
+     if (_machine != _MACH_bplan)
+         strcat(buffer, ":0");
 
      DEBUG_F("<%s>\n", buffer);
 
@@ -174,7 +187,7 @@ ext2_open(  struct boot_file_t*     file,
          return FILE_IOERR;
      }
      ofopened = 1;
-       
+
      /* Open the ext2 filesystem */
      result = ext2fs_open (buffer, EXT2_FLAG_RW, 0, 0, linux_io_manager, &fs);
      if (result) {
@@ -201,7 +214,7 @@ ext2_open(  struct boot_file_t*     file,
          error = FILE_IOERR;
          goto bail;
      }
-       
+
      /* Lookup file by pathname */
      root = cwd = EXT2_ROOT_INO;
      result = ext2fs_namei_follow(fs, root, cwd, file_name, &file->inode);
@@ -225,7 +238,7 @@ ext2_open(  struct boot_file_t*     file,
          error = FILE_ERR_NOTFOUND;
          goto bail;
      }
-#endif 
+#endif
 
 #ifndef FAST_VERSION
      result = ext2fs_read_inode(fs, file->inode, &cur_inode);
@@ -244,7 +257,7 @@ ext2_open(  struct boot_file_t*     file,
      }
 #endif /* FAST_VERSION */
      file->pos = 0;
-       
+
      opened = 1;
 bail:
      if (!opened) {
@@ -257,7 +270,7 @@ bail:
               free(block_buffer);
          block_buffer = NULL;
          cur_file = NULL;
-           
+
          DEBUG_LEAVE_F(error);
          return error;
      }
@@ -282,7 +295,7 @@ read_dump_range(void)
      if ((count * bs) > read_max)
          count--;
      if (count) {
-         size = count * bs;    
+         size = count * bs;
          read_result = io_channel_read_blk(fs->io, read_range_start, count, read_buffer);
          if (read_result)
               return BLOCK_ABORT;
@@ -293,7 +306,7 @@ read_dump_range(void)
          read_range_count -= count;
          read_range_start += count;
          read_last_logical += count;
-     } 
+     }
      /* Handle remaining block */
      if (read_max && read_range_count) {
          read_result = io_channel_read_blk(fs->io, read_range_start, 1, block_buffer);
@@ -343,7 +356,7 @@ read_iterator(ext2_filsys fs, blk_t *blocknr, int lg_block, void *private)
          ++read_range_count;
          return ((read_range_count * bs) >= read_max) ? BLOCK_ABORT : 0;
      }
-    
+
      /* Range doesn't match. Dump existing range */
      if (read_range_start) {
 #ifdef VERBOSE_DEBUG
@@ -418,7 +431,7 @@ read_iterator(ext2_filsys fs, blk_t *blocknr, int lg_block, void *private)
          read_range_count = 1;
          return (bs >= read_max) ? BLOCK_ABORT : 0;
      }
-    
+
 #ifdef VERBOSE_DEBUG
      DEBUG_F("\n");
 #endif
@@ -450,7 +463,7 @@ ext2_read(  struct boot_file_t*     file,
      read_max = size;
      read_buffer = (unsigned char*)buffer;
      read_result = 0;
-    
+
      retval = ext2fs_block_iterate(fs, file->inode, 0, 0, read_iterator, 0);
      if (retval == BLOCK_ABORT)
          retval = read_result;
@@ -464,13 +477,13 @@ ext2_read(        struct boot_file_t*     file,
      }
      if (retval)
          prom_printf ("ext2: i/o error %ld in read\n", (long) retval);
-               
+
      return read_total;
 
 #else /* FAST_VERSION */
      int status;
      unsigned int read = 0;
-       
+
      if (!opened)
          return FILE_IOERR;
 
@@ -478,11 +491,11 @@ ext2_read(        struct boot_file_t*     file,
      DEBUG_F("ext_read() from pos 0x%x, size: 0x%x\n", file->pos, size);
 
 
-     while(size) {     
+     while(size) {
          blk_t fblock = file->pos / bs;
          blk_t pblock;
          unsigned int blkorig, s, b;
-       
+
          pblock = 0;
          status = ext2fs_bmap(fs, file->inode, &cur_inode,
                               block_buffer, 0, fblock, &pblock);
@@ -515,7 +528,7 @@ ext2_read(  struct boot_file_t*     file,
          file->pos += s;
      }
      return read;
-#endif /* FAST_VERSION */      
+#endif /* FAST_VERSION */
 }
 
 static int
@@ -542,12 +555,12 @@ ext2_close(       struct boot_file_t*     file)
      if (fs)
          ext2fs_close(fs);
      fs = NULL;
-       
+
      prom_close(file->of_device);
      DEBUG_F("ext2_close called\n");
 
      opened = 0;
-           
+
      return 0;
 }
 
@@ -582,11 +595,12 @@ static errcode_t linux_close (io_channel channel)
 
 static errcode_t linux_set_blksize (io_channel channel, int blksize)
 {
+     DEBUG_F("bs set to 0x%x\n", blksize);
      channel->block_size = bs = blksize;
      if (block_buffer) {
          free(block_buffer);
          block_buffer = malloc(bs * 2);
-     } 
+     }
      return 0;
 }
 
@@ -597,9 +611,18 @@ static errcode_t linux_read_blk (io_channel channel, unsigned long block, int co
 
      if (count == 0)
          return 0;
-    
+
      tempb = (((unsigned long long) block) *
              ((unsigned long long)bs)) + (unsigned long long)doff;
+     /*
+      * Only test tempb exceeding dend if dend is set to allow things
+      * like boot: hd:0,\xxxx
+      */
+     if (dend && tempb > dend) {
+         DEBUG_F("\nSeek error on block %lx, tempb=%Lx\n", block, tempb >> 9);
+         return EXT2_ET_LLSEEK_FAILED;
+     }
+
      size = (count < 0) ? -count : count * bs;
      prom_lseek(cur_file->of_device, tempb);
      if (prom_read(cur_file->of_device, data, size) != size) {
@@ -619,7 +642,7 @@ static errcode_t linux_flush (io_channel channel)
      return 0;
 }
 
-/* 
+/*
  * Local variables:
  * c-file-style: "k&r"
  * c-basic-offset: 5