~ubuntu-branches/debian/sid/grub2/sid-200907171837

« back to all changes in this revision

Viewing changes to kern/disk.c

  • Committer: Bazaar Package Importer
  • Author(s): Robert Millan
  • Date: 2009-07-02 13:23:51 UTC
  • mfrom: (1.1.10 upstream)
  • Revision ID: james.westby@ubuntu.com-20090702132351-tanpn0ryyijp93gu
Tags: 1.96+20090702-1
* New SVN snapshot.
* rules: Remove duplicated files in sparc64-ieee1275 port.
* rules: Comment out -DGRUB_ASSUME_LINUX_HAS_FB_SUPPORT=1 setting.  We'll
  re-evaluate using it when it's more mature.  (Closes: #535026).

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
#include <grub/types.h>
23
23
#include <grub/partition.h>
24
24
#include <grub/misc.h>
25
 
#include <grub/machine/time.h>
 
25
#include <grub/time.h>
26
26
#include <grub/file.h>
27
27
 
28
28
#define GRUB_CACHE_TIMEOUT      2
29
29
 
30
30
/* The last time the disk was used.  */
31
 
static unsigned long grub_last_time = 0;
 
31
static grub_uint64_t grub_last_time = 0;
32
32
 
33
33
 
34
34
/* Disk cache.  */
46
46
void (*grub_disk_firmware_fini) (void);
47
47
int grub_disk_firmware_is_tainted;
48
48
 
 
49
grub_err_t (* grub_disk_ata_pass_through) (grub_disk_t,
 
50
            struct grub_disk_ata_pass_through_parms *);
 
51
 
 
52
 
49
53
#if 0
50
54
static unsigned long grub_disk_cache_hits;
51
55
static unsigned long grub_disk_cache_misses;
128
132
#if 0
129
133
  grub_disk_cache_misses++;
130
134
#endif
131
 
  
 
135
 
132
136
  return 0;
133
137
}
134
138
 
153
157
{
154
158
  unsigned index;
155
159
  struct grub_disk_cache *cache;
156
 
  
157
 
  grub_disk_cache_invalidate (dev_id, disk_id, sector);
158
 
  
 
160
 
159
161
  index = grub_disk_cache_get_index (dev_id, disk_id, sector);
160
162
  cache = grub_disk_cache_table + index;
161
 
  
 
163
 
 
164
  cache->lock = 1;
 
165
  grub_free (cache->data);
 
166
  cache->data = 0;
 
167
  cache->lock = 0;
 
168
 
162
169
  cache->data = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
163
170
  if (! cache->data)
164
171
    return grub_errno;
165
 
  
 
172
 
166
173
  grub_memcpy (cache->data, data,
167
174
               GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
168
175
  cache->dev_id = dev_id;
187
194
grub_disk_dev_unregister (grub_disk_dev_t dev)
188
195
{
189
196
  grub_disk_dev_t *p, q;
190
 
  
 
197
 
191
198
  for (p = &grub_disk_dev_list, q = *p; q; p = &(q->next), q = q->next)
192
199
    if (q == dev)
193
200
      {
202
209
  grub_disk_dev_t p;
203
210
 
204
211
  for (p = grub_disk_dev_list; p; p = p->next)
205
 
    if ((p->iterate) (hook))
 
212
    if (p->iterate && (p->iterate) (hook))
206
213
      return 1;
207
214
 
208
215
  return 0;
209
216
}
210
217
 
 
218
/* Return the location of the first ',', if any, which is not
 
219
   escaped by a '\'.  */
 
220
static const char *
 
221
find_part_sep (const char *name)
 
222
{
 
223
  const char *p = name;
 
224
  char c;
 
225
 
 
226
  while ((c = *p++) != '\0')
 
227
    {
 
228
      if (c == '\\' && *p == ',')
 
229
        p++;
 
230
      else if (c == ',')
 
231
        return p - 1;
 
232
    }
 
233
  return NULL;
 
234
}
 
235
 
211
236
grub_disk_t
212
237
grub_disk_open (const char *name)
213
238
{
214
 
  char *p;
 
239
  const char *p;
215
240
  grub_disk_t disk;
216
241
  grub_disk_dev_t dev;
217
242
  char *raw = (char *) name;
218
 
  unsigned long current_time;
 
243
  grub_uint64_t current_time;
219
244
 
220
245
  grub_dprintf ("disk", "Opening `%s'...\n", name);
221
246
 
230
255
  disk->name = grub_strdup (name);
231
256
  if (! disk->name)
232
257
    goto fail;
233
 
  
234
 
  p = grub_strchr (name, ',');
 
258
 
 
259
  p = find_part_sep (name);
235
260
  if (p)
236
261
    {
237
262
      grub_size_t len = p - name;
238
 
      
 
263
 
239
264
      raw = grub_malloc (len + 1);
240
265
      if (! raw)
241
266
        goto fail;
265
290
      grub_error (GRUB_ERR_BAD_DEVICE, "no partition on this disk");
266
291
      goto fail;
267
292
    }
268
 
  
 
293
 
269
294
  disk->dev = dev;
270
295
 
271
296
  if (p)
280
305
 
281
306
  /* The cache will be invalidated about 2 seconds after a device was
282
307
     closed.  */
283
 
  current_time = grub_get_rtc ();
 
308
  current_time = grub_get_time_ms ();
284
309
 
285
310
  if (current_time > (grub_last_time
286
 
                      + GRUB_CACHE_TIMEOUT * GRUB_TICKS_PER_SECOND))
 
311
                      + GRUB_CACHE_TIMEOUT * 1000))
287
312
    grub_disk_cache_invalidate_all ();
288
 
  
 
313
 
289
314
  grub_last_time = current_time;
290
 
  
 
315
 
291
316
 fail:
292
 
  
 
317
 
293
318
  if (raw && raw != name)
294
319
    grub_free (raw);
295
320
 
315
340
    (disk->dev->close) (disk);
316
341
 
317
342
  /* Reset the timer.  */
318
 
  grub_last_time = grub_get_rtc ();
 
343
  grub_last_time = grub_get_time_ms ();
319
344
 
320
345
  grub_free (disk->partition);
321
346
  grub_free ((void *) disk->name);
322
347
  grub_free (disk);
323
348
}
324
349
 
 
350
/* This function performs three tasks:
 
351
   - Make sectors disk relative from partition relative.
 
352
   - Normalize offset to be less than the sector size.
 
353
   - Verify that the range is inside the partition.  */
325
354
static grub_err_t
326
 
grub_disk_check_range (grub_disk_t disk, grub_disk_addr_t *sector,
 
355
grub_disk_adjust_range (grub_disk_t disk, grub_disk_addr_t *sector,
327
356
                       grub_off_t *offset, grub_size_t size)
328
357
{
329
358
  *sector += *offset >> GRUB_DISK_SECTOR_BITS;
330
359
  *offset &= GRUB_DISK_SECTOR_SIZE - 1;
331
 
  
 
360
 
332
361
  if (disk->partition)
333
362
    {
334
363
      grub_disk_addr_t start;
356
385
/* Read data from the disk.  */
357
386
grub_err_t
358
387
grub_disk_read (grub_disk_t disk, grub_disk_addr_t sector,
359
 
                grub_off_t offset, grub_size_t size, char *buf)
 
388
                grub_off_t offset, grub_size_t size, void *buf)
360
389
{
361
390
  char *tmp_buf;
362
391
  unsigned real_offset;
363
392
 
364
393
  grub_dprintf ("disk", "Reading `%s'...\n", disk->name);
365
 
  
 
394
 
366
395
  /* First of all, check if the region is within the disk.  */
367
 
  if (grub_disk_check_range (disk, &sector, &offset, size) != GRUB_ERR_NONE)
 
396
  if (grub_disk_adjust_range (disk, &sector, &offset, size) != GRUB_ERR_NONE)
368
397
    {
369
398
      grub_error_push ();
370
 
      grub_dprintf ("disk", "Read out of range: sector 0x%llx.\n",
371
 
                    (unsigned long long) sector);
 
399
      grub_dprintf ("disk", "Read out of range: sector 0x%llx (%s).\n",
 
400
                    (unsigned long long) sector, grub_errmsg);
372
401
      grub_error_pop ();
373
402
      return grub_errno;
374
403
    }
375
404
 
376
405
  real_offset = offset;
377
 
  
 
406
 
378
407
  /* Allocate a temporary buffer.  */
379
408
  tmp_buf = grub_malloc (GRUB_DISK_SECTOR_SIZE << GRUB_DISK_CACHE_BITS);
380
409
  if (! tmp_buf)
425
454
                goto finish;
426
455
 
427
456
              tmp_buf = p;
428
 
              
 
457
 
429
458
              if ((disk->dev->read) (disk, sector, num, tmp_buf))
430
459
                {
431
460
                  grub_error_push ();
464
493
        {
465
494
          grub_disk_addr_t s = sector;
466
495
          grub_size_t l = len;
467
 
          
 
496
 
468
497
          while (l)
469
498
            {
470
499
              (disk->read_hook) (s, real_offset,
471
500
                                 ((l > GRUB_DISK_SECTOR_SIZE)
472
501
                                  ? GRUB_DISK_SECTOR_SIZE
473
502
                                  : l));
474
 
              
 
503
 
475
504
              if (l < GRUB_DISK_SECTOR_SIZE - real_offset)
476
505
                break;
477
 
              
 
506
 
478
507
              s++;
479
508
              l -= GRUB_DISK_SECTOR_SIZE - real_offset;
480
509
              real_offset = 0;
481
510
            }
482
511
        }
483
 
      
 
512
 
484
513
      sector = start_sector + GRUB_DISK_CACHE_SIZE;
485
 
      buf += len;
 
514
      buf = (char *) buf + len;
486
515
      size -= len;
487
516
      real_offset = 0;
488
517
    }
489
 
  
 
518
 
490
519
 finish:
491
 
  
 
520
 
492
521
  grub_free (tmp_buf);
493
 
  
 
522
 
494
523
  return grub_errno;
495
524
}
496
525
 
497
526
grub_err_t
498
527
grub_disk_write (grub_disk_t disk, grub_disk_addr_t sector,
499
 
                 grub_off_t offset, grub_size_t size, const char *buf)
 
528
                 grub_off_t offset, grub_size_t size, const void *buf)
500
529
{
501
530
  unsigned real_offset;
502
 
  
 
531
 
503
532
  grub_dprintf ("disk", "Writing `%s'...\n", disk->name);
504
533
 
505
 
  if (grub_disk_check_range (disk, &sector, &offset, size) != GRUB_ERR_NONE)
 
534
  if (grub_disk_adjust_range (disk, &sector, &offset, size) != GRUB_ERR_NONE)
506
535
    return -1;
507
536
 
508
537
  real_offset = offset;
509
 
  
 
538
 
510
539
  while (size)
511
540
    {
512
541
      if (real_offset != 0 || (size < GRUB_DISK_SECTOR_SIZE && size != 0))
513
542
        {
514
543
          char tmp_buf[GRUB_DISK_SECTOR_SIZE];
515
544
          grub_size_t len;
516
 
          
 
545
          grub_partition_t part;
 
546
 
 
547
          part = disk->partition;
 
548
          disk->partition = 0;
517
549
          if (grub_disk_read (disk, sector, 0, GRUB_DISK_SECTOR_SIZE, tmp_buf)
518
550
              != GRUB_ERR_NONE)
519
 
            goto finish;
 
551
            {
 
552
              disk->partition = part;
 
553
              goto finish;
 
554
            }
 
555
          disk->partition = part;
520
556
 
521
557
          len = GRUB_DISK_SECTOR_SIZE - real_offset;
522
558
          if (len > size)
523
559
            len = size;
524
 
          
 
560
 
525
561
          grub_memcpy (tmp_buf + real_offset, buf, len);
526
562
 
527
563
          grub_disk_cache_invalidate (disk->dev->id, disk->id, sector);
530
566
            goto finish;
531
567
 
532
568
          sector++;
533
 
          buf += len;
 
569
          buf = (char *) buf + len;
534
570
          size -= len;
535
571
          real_offset = 0;
536
572
        }
541
577
 
542
578
          len = size & ~(GRUB_DISK_SECTOR_SIZE - 1);
543
579
          n = size >> GRUB_DISK_SECTOR_BITS;
544
 
          
 
580
 
545
581
          if ((disk->dev->write) (disk, sector, n, buf) != GRUB_ERR_NONE)
546
582
            goto finish;
547
583
 
548
584
          while (n--)
549
585
            grub_disk_cache_invalidate (disk->dev->id, disk->id, sector++);
550
586
 
551
 
          buf += len;
 
587
          buf = (char *) buf + len;
552
588
          size -= len;
553
589
        }
554
590
    }
558
594
  return grub_errno;
559
595
}
560
596
 
561
 
grub_uint64_t 
 
597
grub_uint64_t
562
598
grub_disk_get_size (grub_disk_t disk)
563
599
{
564
600
  if (disk->partition)