Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / devices / common / disk.cc
CommitLineData
920dae64
AT
1// ========== Copyright Header Begin ==========================================
2//
3// OpenSPARC T2 Processor File: disk.cc
4// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
5// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
6//
7// The above named program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public
9// License version 2 as published by the Free Software Foundation.
10//
11// The above named program is distributed in the hope that it will be
12// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14// General Public License for more details.
15//
16// You should have received a copy of the GNU General Public
17// License along with this work; if not, write to the Free Software
18// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19//
20// ========== Copyright Header End ============================================
21#include "disk.h"
22
23
24SCSIDisk * parser_disk;
25
26std::list<Disk *> * diskList;
27std::list<Disk *>::iterator diskListIter;
28
29bool Disk::UI_registered = false;
30
31// parser for disk configuration
32extern int scsi_parse_config(const char * fname, FILE *fp, int target);
33
34
35int gdisk_ui_cmd(void*, int argc, char * argv[]){
36
37 if(argc == 1){
38 for(diskListIter = diskList->begin(); diskListIter != diskList->end(); diskListIter++)
39 fprintf(stderr," %s\n",(*diskListIter)->get_name());
40 return 0;
41 }else if(argc == 2){
42 if(!strcmp("help",argv[1])){
43 diskListIter = diskList->begin();
44 (*diskListIter)->display_help();
45 return 0;
46 }else{
47 fprintf(stderr,"gdisk: unknown command %s\n",argv[1]);
48 fprintf(stderr,"gdisk: Try \"gdisk help\"\n");
49 return 0;
50 }
51 }
52
53
54 for(diskListIter = diskList->begin(); diskListIter != diskList->end(); diskListIter++)
55 if(!strcmp((*diskListIter)->get_name(),argv[1])){
56 (*diskListIter)->handle_ui(argc,argv);
57 return 0;
58 }
59
60 if (!strcmp(argv[1], "all")) {
61 for(diskListIter = diskList->begin(); diskListIter != diskList->end(); diskListIter++)
62 (*diskListIter)->handle_ui(argc,argv);
63 return 0;
64 }
65
66 fprintf(stderr,"gdisk: No disk %s configured\n",argv[1]);
67 return 0;
68}
69
70
71Partition::Partition(){
72
73 debug_level = 0;
74 debug_file = stderr;
75
76 part_filename = 0;
77 part_name = 0;
78
79 overlay_filename = 0;
80 ckpt_filename = 0;
81
82 rw = false;
83 has_vtoc = false;
84
85 size = 0;
86 nblks = 0;
87 start_lblk = 0;
88 end_lblk = 0;
89
90 index = -1;
91 primary_fd = -1;
92 overlay_fd = -1;
93 ckpt_fd = -1;
94
95 bitmap_size = 0;
96 overlay_bitmap = 0;
97 ckpt_bitmap = 0;
98
99 lblk_reads = 0;
100 lblk_writes = 0;
101 lblk_reads_primary = 0;
102 lblk_writes_primary = 0;
103 lblk_reads_overlay = 0;
104 lblk_writes_overlay = 0;
105 lblk_reads_ckpt = 0;
106}
107
108
109Disk::Disk(const char * name){
110 disk_name = name ? strdup(name) : strdup("Disk");
111 for(int i = 0; i < MAX_PARTITIONS; i++)
112 partitions[i] = 0;
113
114 target_id = -1;
115 is_s2 = false;
116 debug_level = 0;
117 debug_file = stderr;
118 strcpy(debug_file_name,"stderr");
119 num_partitions = 0;
120 vtoc_partition = -1;
121 fake_vtoc = false;
122 num_cylinder = 0;
123 num_blks = 0;
124 user_geometry = false;
125 read_delay = READ_DELAY_DEFAULT;
126 write_delay = WRITE_DELAY_DEFAULT;
127
128 bzero((void*)&disk_label, sizeof(disk_label));
129
130 struct stat statbuf;
131 if(stat(overlaydir, &statbuf) == 0){
132 if (!S_ISDIR(statbuf.st_mode) ) {
133 fprintf(debug_file,"%s: overlay dir %s does not exist\n",disk_name,overlaydir);
134 exit(1);
135 }
136 }
137
138 // default values, in case vtoc needs to be faked
139 sectors_per_track = 32;
140 tracks_per_cylinder = 16;
141 bytes_per_sector = BYTES_PER_SECTOR; // constant
142
143
144 if(!UI_registered){
145 UI_registered = true;
146 UI_register_cmd_2 ("gdisk", "", gdisk_ui_cmd, NULL);
147 diskList = new std::list<Disk *>;
148 }
149}
150
151
152SCSIDisk::SCSIDisk():Disk(0){
153 vendorid = sid.vendor;
154 productid = sid.product;
155 revisionid = sid.revision;
156 serialno = sid.serialnum;
157 prodserialno = usn.productSerialNumber;
158 brdserialno = usn.boardSerialNumber;
159 portwwn = fdi.id0;
160 nodewwn = fdi.id1;
161
162 sizeof_vendorid = sizeof(sid.vendor);
163 sizeof_productid = sizeof(sid.product);
164 sizeof_revisionid = sizeof(sid.revision);
165 sizeof_serialno = sizeof(sid.serialnum);
166 sizeof_prodserialno = sizeof(usn.productSerialNumber);
167 sizeof_brdserialno= sizeof(usn.boardSerialNumber);
168 sizeof_portwwn = sizeof(fdi.id0);
169 sizeof_nodewwn = sizeof(fdi.id1);
170
171
172 Supported_VPD_size = 0x8;
173 sv.pageLength = 0x4; // support the first 4 VPD only
174}
175
176SCSIDisk::~SCSIDisk(){}
177
178
179bool SCSIDisk::parse_config(const char * filename, FILE * fp, int target){
180 assert(fp);
181 parser_disk = this;
182 num_partitions = 0;
183
184 int ret = scsi_parse_config(filename, fp, target);
185
186 if(ret){
187 fprintf(stderr,"Error parsing disk config file %s\n",filename);
188 exit(1);
189 }
190
191 if (num_partitions == 0)
192 return true;
193
194 add_partition_fini();
195
196 if(!fake_vtoc && user_geometry){
197 fprintf(stderr,"%s Error:Can't specify VTOC geometry for real disk labels\n",get_name());
198 assert(0);
199 }
200
201 if(!create_overlays())
202 exit(1);
203
204 for(diskListIter = diskList->begin(); diskListIter != diskList->end(); diskListIter++){
205 if(!strcmp(get_name(),(*diskListIter)->get_name())){
206 fprintf(stderr,"Error: Disk %s already configured,\n Provide unique names to disks.\n",get_name());
207 exit(1);
208 }
209 }
210
211 diskList->push_front(this);
212
213 if(!fake_vtoc) {
214 disk_read_lblk(0,(uint8_t*)&disk_label,1);
215#if defined(ARCH_X64)
216 label_endian_convert(&disk_label);
217#endif
218 }
219
220 return true;
221}
222
223
224
225bool Disk::add_partition_fini(){
226 // assumes _SUNOS_VTOC_8
227
228 // all paritions have been read. Now create the vtoc if needed, adjust the
229 // start, end lblks etc.
230
231 char buf[BYTES_PER_SECTOR];
232
233 if(vtoc_partition == -1)
234 // need to fake the vtoc
235 fake_vtoc = true;
236
237 if(!fake_vtoc){
238 // Do not need to fake a vtoc
239 // 1. Read the vtoc and initialize partition start/end/number blocks according to
240 // the vtoc
241 lseek(partitions[vtoc_partition]->primary_fd,0,SEEK_SET);
242 if(read(partitions[vtoc_partition]->primary_fd,(void*)(buf),BYTES_PER_SECTOR) != BYTES_PER_SECTOR){
243 fprintf(debug_file,"%s: Cannot read sector 0 on %s\n",disk_name,partitions[vtoc_partition]->part_filename);
244 perror("");
245 exit(1);
246 }
247 struct vtoc8_dk_label * dkl = (vtoc8_dk_label*) buf;
248
249 if(is_s2){
250 // 1. See if this is s2 partition
251 assert(vtoc_partition == 2);
252 partitions[2]->nblks = dkl->dkl_map[2].dkl_nblk;
253 partitions[2]->start_lblk = dkl->dkl_map[2].dkl_cylno * dkl->dkl_nsect * dkl->dkl_nhead;
254 partitions[2]->end_lblk = partitions[2]->start_lblk + partitions[2]->nblks - 1;
255 num_blks = partitions[2]->nblks;
256 if(partitions[2]->nblks * BYTES_PER_SECTOR != partitions[2]->size){
257 fprintf(debug_file,"%s Warning: %s size (%lld) not same as size in vtoc (%lld)\n",\
258 disk_name,partitions[2]->part_filename,partitions[2]->size,partitions[2]->nblks * BYTES_PER_SECTOR);
259 }
260 }else{
261 // initialize other partitions from the vtoc
262 partitions[vtoc_partition]->nblks = dkl->dkl_map[vtoc_partition].dkl_nblk;
263 partitions[vtoc_partition]->start_lblk = dkl->dkl_map[vtoc_partition].dkl_cylno * dkl->dkl_nsect * dkl->dkl_nhead;
264 partitions[vtoc_partition]->end_lblk = partitions[vtoc_partition]->start_lblk + partitions[vtoc_partition]->nblks - 1;
265
266 for(int i = 0; i < MAX_PARTITIONS; i++){
267 if(i == vtoc_partition)
268 continue;
269 if(partitions[i] == 0)
270 continue;
271 partitions[i]->nblks = dkl->dkl_map[i].dkl_nblk;
272 if(partitions[i]->nblks == 0){
273 // nblk == 0 means undefined partition.
274 // The user has added a partition which
275 // is not present in the real
276 // vtoc in the disk. Treat as fatal error.
277 fprintf(debug_file,"%s: configuring parition %d(%s) not present in disk vtoc.\n",\
278 disk_name,i,partitions[i]->part_filename);
279 assert(partitions[i]->nblks);
280 }
281 partitions[i]->start_lblk = dkl->dkl_map[i].dkl_cylno * dkl->dkl_nsect * dkl->dkl_nhead;
282 partitions[i]->end_lblk = partitions[i]->start_lblk + partitions[i]->nblks - 1;
283 num_blks += partitions[i]->nblks;
284 if(partitions[i]->nblks * BYTES_PER_SECTOR != partitions[i]->size)
285 fprintf(debug_file,"%s: Warning: %s size (%lld) not same as size in vtoc (%lld)\n",\
286 disk_name,partitions[i]->part_filename,partitions[i]->size,partitions[i]->nblks * BYTES_PER_SECTOR);
287 }
288 for(int i = 0; i < VTOC8_NDKMAP; i++)
289 if(i != 2 && dkl->dkl_map[i].dkl_nblk != 0){
290 if(partitions[i] == 0){
291 // some partitions present in VTOV are not bein added.
292 // Reads/writes will be ignored.
293 fprintf(debug_file,"%s: Warning - partition %d present in VTOC not configured\n",disk_name,i);
294 fprintf(debug_file,"%s: Warning - some reads/writes MAY not succeed \n",disk_name);
295 }
296 }
297 }
298
299 sectors_per_track = dkl->dkl_nsect; // default 32
300 tracks_per_cylinder = dkl->dkl_nhead; // default 16
301 num_cylinder = ceil(1.0 * num_blks/sectors_per_track/tracks_per_cylinder);// total number of cyinders in disk
302
303 return true;
304 }
305
306 // create the fake vtoc.
307
308 // start init'ing the disk label
309 strcpy(disk_label.dkl_ascii_label,"SUN");
310 disk_label.dkl_rpm = DKLABEL_RPM;
311 disk_label.dkl_intrlv = DKLABEL_INTRLV;
312 disk_label.dkl_acyl = DKLABEL_ACYL;
313 disk_label.dkl_magic = DKLABEL_MAGIC;
314 disk_label.dkl_write_reinstruct = 0;
315 disk_label.dkl_read_reinstruct = 0;
316 disk_label.dkl_nsect = sectors_per_track;
317 disk_label.dkl_nhead = tracks_per_cylinder;
318
319 disk_label.dkl_vtoc.v_nparts = MAX_PARTITIONS;
320 disk_label.dkl_vtoc.v_version = 0x1;
321 disk_label.dkl_vtoc.v_sanity = VTOC_SANITY;
322 strcpy(disk_label.dkl_vtoc.v_volume,"SAM_VOL");
323
324 // start the lowest specified partition from cylinder 0 or 1.
325 if(is_s2)
326 num_cylinder = 0;
327 else
328 num_cylinder = 1;
329
330 for( int i = 0; i < MAX_PARTITIONS; i++){
331 if( (partitions[i] == 0) )
332 continue;
333 if(!is_s2){
334 // we are creating a fake vtoc. check to see if the partition
335 // itself does not contain a vtoc. If it does, the access will fail
336 // as sector 0 will be duplicated. We bail out on such cases. The
337 // user needs to use the vtoc on partition here. This does not apply
338 // to s2 since the OS knows there is a label at sector 0, whether
339 // faked or real. Treat as fatal.
340 struct vtoc8_dk_label * dkl = (vtoc8_dk_label*) buf;
341 lseek(partitions[i]->primary_fd,0,SEEK_SET);
342 read(partitions[i]->primary_fd,buf,BYTES_PER_SECTOR);
343 if(dkl->dkl_magic == DKLABEL_MAGIC){
344 fprintf(stderr,"%s.%s: Disk Label found on sector 0 of %s\n",\
345 disk_name,partitions[i]->part_name,partitions[i]->part_filename);
346 fprintf(stderr," : Use the label on image or clip sector 0\n.");
347 assert(0);
348 }
349 }
350 if(!is_s2)
351 disk_label.dkl_vtoc.v_part[i].p_tag = 0x04; // User
352 else
353 disk_label.dkl_vtoc.v_part[2].p_tag = 0x02; // Root
354 disk_label.dkl_vtoc.v_part[i].p_flag = 0x00; // Mountable, rw
355 disk_label.dkl_map[i].dkl_cylno = num_cylinder;
356 disk_label.dkl_map[i].dkl_nblk = ceil(1.0 * partitions[i]->size / bytes_per_sector);
357 int64_t cylinders_in_partition = ceil ( 1.0 * disk_label.dkl_map[i].dkl_nblk / sectors_per_track / tracks_per_cylinder );
358 if( num_cylinder + cylinders_in_partition > 0x7fffffffLL){
359 fprintf(debug_file,"%s: number of cylinders exceed 0x7fffffff. Modify VTOC\n",disk_name);
360 exit(1);
361 }else
362 num_cylinder += cylinders_in_partition;
363 num_blks += disk_label.dkl_map[i].dkl_nblk;
364 }
365
366 disk_label.dkl_pcyl = num_cylinder;
367 disk_label.dkl_ncyl = num_cylinder;
368
369 set_dkl_cksum();
370
371 // fill in the start/end/num blocks in partitions
372
373 for( int i = 0; i < MAX_PARTITIONS; i++){
374 if( partitions[i] == 0 )
375 continue;
376 partitions[i]->nblks = disk_label.dkl_map[i].dkl_nblk;
377 partitions[i]->start_lblk = disk_label.dkl_map[i].dkl_cylno * disk_label.dkl_nsect * disk_label.dkl_nhead;
378 partitions[i]->end_lblk = partitions[i]->start_lblk + partitions[i]->nblks - 1;
379 }
380
381 // SCSI CAPACITY command reads the numberof nblocks in the disk. It is a 32 bit
382 // unsigned number. That gives a limit on size of disk as 2^32 * 512 = 2^41
383 // bytes or 2 TB. Put a check here for this limit. Note that this would not
384 // work in case of real VTOC, where partitions can overlap. SAM does not
385 // create disks from partitions that overlap, hence this check works.
386 if(num_blks > 0xffffffffULL ){
387 fprintf(debug_file,"%s: Fatal - Total disk size exceeds 2 TB!! LBLKS = %lld\n",disk_name,num_blks);
388 assert(0);
389 }
390
391
392 return true;
393}
394
395
396// return true on success, else false
397bool Disk::add_partition(int partition, const char * filename, bool rw, bool has_vtoc){
398
399 assert(partition <= 7);
400 if(partition == 2){
401 // only one partition is allowed. It may or may not have a vtoc
402 if(num_partitions != 0){
403 fprintf(stderr,"Cannot have more than 1 partitions with s2\n");
404 assert(num_partitions == 0);
405 }
406 is_s2 = true;
407 }else{
408 if(is_s2){
409 // this disk is being configured with an s2 along with other
410 // partition. Not allowed
411 fprintf(stderr,"Can't have another partition with s2\n");
412 assert(!is_s2);
413 }
414 }
415
416 if(has_vtoc){
417 assert(vtoc_partition == -1);
418 vtoc_partition = partition;
419 }
420
421 char buf[128];
422 struct stat statbuf;
423 int fd = -1;
424
425 int oflag = O_RDONLY|O_LARGEFILE; // XXX choose based upon 'rw' mode
426
427 if( (fd = open(filename, oflag)) == -1){
428 fprintf(debug_file,"%s: open() file %s errno: %d , %s \n", disk_name, filename, errno, strerror(errno));
429 return false;
430 }
431
432
433 if(stat(filename, &statbuf) == -1){
434 fprintf(debug_file,"%s: Could not stat() file %s \n",disk_name, filename);
435 return false;
436 }
437
438 assert(partitions[partition] == 0);
439 Partition * P = partitions[partition] = new Partition();
440 P->index = partition;
441 P->has_vtoc = has_vtoc;
442 P->part_filename = strdup(filename);
443 P->primary_fd = fd;
444 sprintf(buf,"s%d",partition);
445 P->part_name = strdup(buf);
446 P->rw = rw;
447
448
449 P->is_device_file = statbuf.st_rdev;
450 if(!P->is_device_file)
451 P->size = statbuf.st_size;
452 else{
453 P->size = lseek(fd,0,SEEK_END);
454 lseek(fd,0,SEEK_SET);
455 }
456
457 if(P->size % BYTES_PER_SECTOR){
458 fprintf(debug_file,"partition %d(%s) size not multiple of %d bytes\n",partition,filename,BYTES_PER_SECTOR);
459 assert(0);
460 }
461
462 num_partitions++;
463 return true;
464
465}
466
467// return number of bytes written, -1 on error
468uint32_t Disk::disk_write_lblk( uint64_t lblkno, uint8_t *buf, uint32_t nblks ){
469 uint32_t ret = 0;
470 uint32_t blocks_to_write = nblks;
471 if(lblkno == 0 && fake_vtoc){
472 bcopy(buf,&disk_label,BYTES_PER_SECTOR);
473#if defined(ARCH_X64)
474 label_endian_convert(&disk_label);
475#endif
476 buf += BYTES_PER_SECTOR;
477 lblkno++;
478 blocks_to_write--;
479 ret++;
480 }
481 for(int i = 0; i < MAX_PARTITIONS && blocks_to_write; i++){
482 if(partitions[i] && partitions[i]->lblk_inrange(lblkno)){
483 // handle case of overlapping partitions. The lowest numbered
484 // partition having the block is read/written to
485 uint32_t retp = partitions[i]->Write(lblkno, buf, blocks_to_write);
486 blocks_to_write -= retp;
487 lblkno += retp;
488 ret += retp;
489 }
490 }
491 if(ret != nblks)
492 fprintf(debug_file,"%s:Warning. Write request at lblk %lld of size %ld wrote %ld lblks\n",disk_name,lblkno,nblks,ret);
493
494 return ret;
495}
496
497// return number of bytes written
498uint32_t Disk::disk_read_lblk( uint64_t lblkno, uint8_t *buf, uint32_t nblks ){
499
500 bzero(buf,nblks * BYTES_PER_SECTOR);
501 uint32_t ret = 0;
502 uint32_t blocks_to_read = nblks;
503
504 if(lblkno == 0 && fake_vtoc){
505#if defined(ARCH_X64)
506 struct vtoc8_dk_label tmp;
507 bcopy(&disk_label,&tmp,sizeof(disk_label));
508 label_endian_convert(&tmp);
509 bcopy(&tmp,buf,BYTES_PER_SECTOR);
510#else
511 bcopy(&disk_label,buf,BYTES_PER_SECTOR);
512#endif
513 buf += BYTES_PER_SECTOR;
514 lblkno++;
515 blocks_to_read--;
516 ret++;
517 }
518
519 for(int i = 0; i < MAX_PARTITIONS && blocks_to_read; i++){
520 if(partitions[i] && partitions[i]->lblk_inrange(lblkno)){
521 // handle case of overlapping partitions. The lowest numbered
522 // partition having the block is read/written to
523 uint32_t retp = partitions[i]->Read(lblkno, buf, blocks_to_read);
524 blocks_to_read -= retp;
525 lblkno += retp;
526 ret += retp;
527 }
528 }
529
530 if(ret != nblks)
531 fprintf(debug_file,"%s:Warning. Read request at lblk %lld of size %ld read %ld lblks\n",disk_name,lblkno,nblks,ret);
532
533 return ret;
534}
535
536bool Disk::dump(const char * dir){
537
538 bool ret = true;
539 for(int i = 0; i < MAX_PARTITIONS; i++){
540 if(partitions[i] ){
541 ret &= partitions[i]->dump(dir,disk_name);
542 }
543 }
544
545 ret &= dump_misc(dir);
546
547 return ret;
548}
549
550bool Disk::restore(const char * dir){
551 bool ret = true;
552 for(int i = 0; i < MAX_PARTITIONS; i++){
553 if(partitions[i] ){
554 ret &= partitions[i]->restore(dir,disk_name);
555 }
556 }
557
558 ret &= restore_misc(dir);
559
560 return ret;
561}
562
563
564bool Partition::dump(const char * dir, const char * disk_name){
565 bool ret = true;
566
567 bitset * b = new bitset (bitmap_size);
568 b->Or(overlay_bitmap);
569 if(ckpt_bitmap) b->Or(ckpt_bitmap);
570
571 char buf[1024];
572 sprintf(buf, "%s/%s.%s.dmp",dir,disk_name,part_name);
573
574 FILE * fp = fopen(buf,"w");
575 ret &= b->dump(fp);
576 fclose(fp);
577
578 sprintf(buf, "%s/%s.%s.shadow",dir,disk_name,part_name);
579 int to_fd = open(buf,O_WRONLY|O_CREAT|O_LARGEFILE,0777);
580 assert(to_fd != -1);
581 lseek(to_fd,nblks*BYTES_PER_SECTOR - 1,SEEK_SET);
582 assert(write(to_fd,"",1) == 1);
583
584 int src_fd = -1;
585 const char * src_file= 0;
586 for(uint64_t i = 0; i < bitmap_size; i++){
587 char tmpbuf[DISK_PAGE_SIZE];
588 if(overlay_bitmap->get(i)){
589 src_fd = overlay_fd;
590 src_file = overlay_filename;
591 }else if(ckpt_bitmap && ckpt_bitmap->get(i)){
592 src_fd = ckpt_fd;
593 src_file = ckpt_filename;
594 }else
595 continue;
596 lseek(src_fd,i * DISK_PAGE_SIZE, SEEK_SET);
597 read(src_fd,tmpbuf,DISK_PAGE_SIZE);
598 lseek(to_fd,i * DISK_PAGE_SIZE, SEEK_SET);
599 if(write(to_fd,tmpbuf,DISK_PAGE_SIZE) != DISK_PAGE_SIZE){
600 fprintf(debug_file,"%s:Error writing checkpoint file %s offset %llx\n",part_name,buf,i*DISK_PAGE_SIZE);
601 perror("");
602 return false;
603 }
604 }
605 close(to_fd);
606 return ret;
607}
608bool Partition::restore(const char * dir, const char * disk_name){
609
610 bool ret = true;
611 char buf[1024];
612 sprintf(buf, "%s/%s.%s.dmp",dir,disk_name,part_name);
613 FILE * fp = fopen(buf,"r");
614 assert(fp);
615
616 ckpt_bitmap = new bitset(bitmap_size,part_name);
617 ckpt_bitmap->restore(fp);
618 fclose(fp);
619
620 sprintf(buf,"%s/%s.%s.shadow",dir,disk_name,part_name);
621 ckpt_filename = strdup(buf);
622
623 if( (ckpt_fd = open(ckpt_filename, O_RDONLY|O_LARGEFILE)) == -1){
624 fprintf(debug_file,"%s: open() file %s errno: %d , %s \n", disk_name, ckpt_filename, errno, strerror(errno));
625 ret &= false;
626 }
627
628 return ret;
629}
630
631uint32_t Partition::Read(uint64_t lblkno, uint8_t *buf, uint32_t numblks){
632
633 uint64_t relative_lblk = lblkno - start_lblk; // lblk from start of backup file
634 uint64_t bitmap_pos;
635 int src_fd = -1;
636 const char * src_file = 0;
637
638 uint32_t blocks_read = 0;
639
640 char tmpbuf[DISK_PAGE_SIZE];
641 bzero(tmpbuf,DISK_PAGE_SIZE);
642
643 while(numblks != blocks_read){
644 uint32_t blks_in_cur_page = (BLOCKS_PER_PAGE - relative_lblk % BLOCKS_PER_PAGE)\
645 < (numblks - blocks_read) ? (BLOCKS_PER_PAGE - relative_lblk % BLOCKS_PER_PAGE):numblks - blocks_read;
646
647 bitmap_pos = relative_lblk/BLOCKS_PER_PAGE; // 1 bit for every BLOCKS_PER_PAGE lblks
648
649 if(overlay_bitmap->get(bitmap_pos)){
650 src_fd = overlay_fd; // page has been modified earlier
651 src_file = overlay_filename;
652 lblk_reads_overlay += blks_in_cur_page;
653 }else if(ckpt_bitmap && ckpt_bitmap->get(bitmap_pos)){
654 src_fd = ckpt_fd; // page has been modified and is present in the chpt
655 src_file = ckpt_filename;
656 lblk_reads_ckpt += blks_in_cur_page;
657 }else{
658 src_fd = primary_fd; // page has not been written to yet. read from
659 // actual partition
660 src_file = part_filename;
661 lblk_reads_primary += blks_in_cur_page;
662 }
663
664 if(lseek(src_fd,bitmap_pos * DISK_PAGE_SIZE ,SEEK_SET) != bitmap_pos * DISK_PAGE_SIZE){
665 // the partition file does not have requested lblk. This may happen if
666 // vtoc specified a different parition size than the actual file size,
667 // or there may be partially filled lblk. In this case we can't
668 // write(barring certain cases). We print an error message and
669 // continue. The user needs to decide if this is fatal or not.
670 fprintf(debug_file,"%s: Request to seek at lblk %llx, backup file %s map<%llx,%llx> failed.\n",part_name,relative_lblk+start_lblk,src_file,start_lblk,end_lblk);
671 perror("");
672 return blocks_read;
673 }
674
675 if(read(src_fd, tmpbuf, DISK_PAGE_SIZE) != DISK_PAGE_SIZE){
676 // src_fd is smaller than we thought. Flag an error, leave it to
677 // user to decide if its fatal. XXX cannot happen if DISK_PAGE_SIZE
678 // == BYTES_PER_SECTOR
679 fprintf(debug_file,"%s: Request to read at lblk %llx, backup file %s map<%llx,%llx> failed.\n Data could be partial content\n",part_name,relative_lblk+start_lblk,src_file,start_lblk,end_lblk);
680 perror("");
681 }
682
683 bcopy(tmpbuf + (relative_lblk % BLOCKS_PER_PAGE) *BYTES_PER_SECTOR,\
684 buf, blks_in_cur_page*BYTES_PER_SECTOR);
685
686 blocks_read += blks_in_cur_page;
687 buf += blks_in_cur_page * BYTES_PER_SECTOR;
688 relative_lblk += blks_in_cur_page;
689 }
690
691 lblk_reads += blocks_read;
692 return blocks_read;
693}
694
695// return the number of lblks written
696uint32_t Partition::Write(uint64_t lblkno, uint8_t *buf, uint32_t numblks){
697
698 const uint32_t blocks_to_write = numblks;
699 uint64_t relative_lblk = lblkno - start_lblk; // lblk from start of backup file
700 uint64_t bitmap_pos;
701 int src_fd = -1;
702 int to_fd = rw ? primary_fd:overlay_fd; // file to which data would be written
703 assert(to_fd != -1);
704 char tmpbuf[DISK_PAGE_SIZE]; // read/write DISK_PAGE_SIZE at a time
705 const char * src_file = 0;
706 const char * to_file = rw?part_filename: overlay_filename;
707
708 bzero(tmpbuf,DISK_PAGE_SIZE);
709 uint32_t blocks_written = 0;
710
711 while(numblks != blocks_written){
712
713 uint32_t blks_in_cur_page = (BLOCKS_PER_PAGE - relative_lblk % BLOCKS_PER_PAGE)\
714 < (numblks - blocks_written) ? (BLOCKS_PER_PAGE - relative_lblk % BLOCKS_PER_PAGE):numblks - blocks_written;
715
716
717 bitmap_pos = relative_lblk/BLOCKS_PER_PAGE; // 1 bit for every BLOCKS_PER_PAGE lblks
718
719 if(overlay_bitmap->get(bitmap_pos)){
720 src_fd = overlay_fd; // page has been modified earlier
721 src_file = overlay_filename;
722 }else if(ckpt_bitmap && ckpt_bitmap->get(bitmap_pos)){
723 src_fd = ckpt_fd; // page has been modified and is present in the chpt
724 src_file = ckpt_filename;
725 }else{
726 src_fd = primary_fd; // page has not been written to yet. Next
727 // writes will have src_fd = overlay_fd if this
728 // is ro option
729 src_file = part_filename;
730 if(!rw) overlay_bitmap->set(bitmap_pos);
731 }
732
733 if(lseek(src_fd,bitmap_pos * DISK_PAGE_SIZE ,SEEK_SET) != bitmap_pos * DISK_PAGE_SIZE){
734 // the parition file does not have requested lblk. This may happen if
735 // vtoc specified a different parition size than the actual file size,
736 // or there may be partially filled lblk. In this case we can't
737 // write(barring certain cases). We print an error message and
738 // continue. The user needs to decide if this is fatal or not.
739 fprintf(debug_file,"%s: Request to seek at lblk %llx, file %s map<%llx,%llx> failed\n",part_name,relative_lblk+start_lblk,src_file,start_lblk,end_lblk);
740 perror("");
741 return blocks_written;
742 }
743
744 if(read(src_fd, tmpbuf, DISK_PAGE_SIZE) != DISK_PAGE_SIZE){
745 // src_fd is smaller than we thought. Flag an error, leave it to
746 // user to decide if its fatal
747 fprintf(debug_file,"%s: Request to read at lblk %llx, file %s map<%llx,%llx> failed.\n Data write could be partial.\n",part_name,relative_lblk+start_lblk,src_file,start_lblk,end_lblk);
748 perror("");
749 }
750
751 bcopy(buf,tmpbuf + (relative_lblk % BLOCKS_PER_PAGE)*BYTES_PER_SECTOR,\
752 blks_in_cur_page*BYTES_PER_SECTOR);
753
754 if(lseek(to_fd,bitmap_pos * DISK_PAGE_SIZE ,SEEK_SET) != bitmap_pos * DISK_PAGE_SIZE ){
755 // should not happen, since this is atleast the vtoc specified size,
756 // or the real file(rw=true), in which case the lseek would fail above
757 fprintf(debug_file,"%s: Request to seek at lblk %llx, file %s map<%llx,%llx>. Failed\n",part_name,relative_lblk+start_lblk,to_file,start_lblk,end_lblk);
758 perror("");
759 return blocks_written;
760 }
761
762 if(write(to_fd, tmpbuf, DISK_PAGE_SIZE) != DISK_PAGE_SIZE){
763 // should not happen
764 fprintf(debug_file,"%s: Request to write at lblk %llx, file %s map<%llx,%llx>. Failed\n",part_name,relative_lblk+start_lblk,to_file,start_lblk,end_lblk);
765 perror("");
766 }
767
768 buf += blks_in_cur_page * BYTES_PER_SECTOR;
769 blocks_written += blks_in_cur_page;
770 relative_lblk += blks_in_cur_page;
771
772 if(rw)
773 lblk_writes_primary += blks_in_cur_page;
774 else
775 lblk_writes_overlay += blks_in_cur_page;
776
777 }
778
779 lblk_writes += blocks_written;
780 return blocks_written;
781
782}