// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: disk.cc
// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
// The above named program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public
// License along with this work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
// ========== Copyright Header End ============================================
std::list
<Disk
*> * diskList
;
std::list
<Disk
*>::iterator diskListIter
;
bool Disk::UI_registered
= false;
// parser for disk configuration
extern int scsi_parse_config(const char * fname
, FILE *fp
, int target
);
int gdisk_ui_cmd(void*, int argc
, char * argv
[]){
for(diskListIter
= diskList
->begin(); diskListIter
!= diskList
->end(); diskListIter
++)
fprintf(stderr
," %s\n",(*diskListIter
)->get_name());
if(!strcmp("help",argv
[1])){
diskListIter
= diskList
->begin();
(*diskListIter
)->display_help();
fprintf(stderr
,"gdisk: unknown command %s\n",argv
[1]);
fprintf(stderr
,"gdisk: Try \"gdisk help\"\n");
for(diskListIter
= diskList
->begin(); diskListIter
!= diskList
->end(); diskListIter
++)
if(!strcmp((*diskListIter
)->get_name(),argv
[1])){
(*diskListIter
)->handle_ui(argc
,argv
);
if (!strcmp(argv
[1], "all")) {
for(diskListIter
= diskList
->begin(); diskListIter
!= diskList
->end(); diskListIter
++)
(*diskListIter
)->handle_ui(argc
,argv
);
fprintf(stderr
,"gdisk: No disk %s configured\n",argv
[1]);
Disk::Disk(const char * name
){
disk_name
= name
? strdup(name
) : strdup("Disk");
for(int i
= 0; i
< MAX_PARTITIONS
; i
++)
strcpy(debug_file_name
,"stderr");
read_delay
= READ_DELAY_DEFAULT
;
write_delay
= WRITE_DELAY_DEFAULT
;
bzero((void*)&disk_label
, sizeof(disk_label
));
if(stat(overlaydir
, &statbuf
) == 0){
if (!S_ISDIR(statbuf
.st_mode
) ) {
fprintf(debug_file
,"%s: overlay dir %s does not exist\n",disk_name
,overlaydir
);
// default values, in case vtoc needs to be faked
tracks_per_cylinder
= 16;
bytes_per_sector
= BYTES_PER_SECTOR
; // constant
UI_register_cmd_2 ("gdisk", "", gdisk_ui_cmd
, NULL
);
diskList
= new std::list
<Disk
*>;
SCSIDisk::SCSIDisk():Disk(0){
revisionid
= sid
.revision
;
serialno
= sid
.serialnum
;
prodserialno
= usn
.productSerialNumber
;
brdserialno
= usn
.boardSerialNumber
;
sizeof_vendorid
= sizeof(sid
.vendor
);
sizeof_productid
= sizeof(sid
.product
);
sizeof_revisionid
= sizeof(sid
.revision
);
sizeof_serialno
= sizeof(sid
.serialnum
);
sizeof_prodserialno
= sizeof(usn
.productSerialNumber
);
sizeof_brdserialno
= sizeof(usn
.boardSerialNumber
);
sizeof_portwwn
= sizeof(fdi
.id0
);
sizeof_nodewwn
= sizeof(fdi
.id1
);
Supported_VPD_size
= 0x8;
sv
.pageLength
= 0x4; // support the first 4 VPD only
bool SCSIDisk::parse_config(const char * filename
, FILE * fp
, int target
){
int ret
= scsi_parse_config(filename
, fp
, target
);
fprintf(stderr
,"Error parsing disk config file %s\n",filename
);
if(!fake_vtoc
&& user_geometry
){
fprintf(stderr
,"%s Error:Can't specify VTOC geometry for real disk labels\n",get_name());
for(diskListIter
= diskList
->begin(); diskListIter
!= diskList
->end(); diskListIter
++){
if(!strcmp(get_name(),(*diskListIter
)->get_name())){
fprintf(stderr
,"Error: Disk %s already configured,\n Provide unique names to disks.\n",get_name());
diskList
->push_front(this);
disk_read_lblk(0,(uint8_t*)&disk_label
,1);
label_endian_convert(&disk_label
);
bool Disk::add_partition_fini(){
// all paritions have been read. Now create the vtoc if needed, adjust the
char buf
[BYTES_PER_SECTOR
];
// Do not need to fake a vtoc
// 1. Read the vtoc and initialize partition start/end/number blocks according to
lseek(partitions
[vtoc_partition
]->primary_fd
,0,SEEK_SET
);
if(read(partitions
[vtoc_partition
]->primary_fd
,(void*)(buf
),BYTES_PER_SECTOR
) != BYTES_PER_SECTOR
){
fprintf(debug_file
,"%s: Cannot read sector 0 on %s\n",disk_name
,partitions
[vtoc_partition
]->part_filename
);
struct vtoc8_dk_label
* dkl
= (vtoc8_dk_label
*) buf
;
// 1. See if this is s2 partition
assert(vtoc_partition
== 2);
partitions
[2]->nblks
= dkl
->dkl_map
[2].dkl_nblk
;
partitions
[2]->start_lblk
= dkl
->dkl_map
[2].dkl_cylno
* dkl
->dkl_nsect
* dkl
->dkl_nhead
;
partitions
[2]->end_lblk
= partitions
[2]->start_lblk
+ partitions
[2]->nblks
- 1;
num_blks
= partitions
[2]->nblks
;
if(partitions
[2]->nblks
* BYTES_PER_SECTOR
!= partitions
[2]->size
){
fprintf(debug_file
,"%s Warning: %s size (%lld) not same as size in vtoc (%lld)\n",\
disk_name
,partitions
[2]->part_filename
,partitions
[2]->size
,partitions
[2]->nblks
* BYTES_PER_SECTOR
);
// initialize other partitions from the vtoc
partitions
[vtoc_partition
]->nblks
= dkl
->dkl_map
[vtoc_partition
].dkl_nblk
;
partitions
[vtoc_partition
]->start_lblk
= dkl
->dkl_map
[vtoc_partition
].dkl_cylno
* dkl
->dkl_nsect
* dkl
->dkl_nhead
;
partitions
[vtoc_partition
]->end_lblk
= partitions
[vtoc_partition
]->start_lblk
+ partitions
[vtoc_partition
]->nblks
- 1;
for(int i
= 0; i
< MAX_PARTITIONS
; i
++){
partitions
[i
]->nblks
= dkl
->dkl_map
[i
].dkl_nblk
;
if(partitions
[i
]->nblks
== 0){
// nblk == 0 means undefined partition.
// The user has added a partition which
// is not present in the real
// vtoc in the disk. Treat as fatal error.
fprintf(debug_file
,"%s: configuring parition %d(%s) not present in disk vtoc.\n",\
disk_name
,i
,partitions
[i
]->part_filename
);
assert(partitions
[i
]->nblks
);
partitions
[i
]->start_lblk
= dkl
->dkl_map
[i
].dkl_cylno
* dkl
->dkl_nsect
* dkl
->dkl_nhead
;
partitions
[i
]->end_lblk
= partitions
[i
]->start_lblk
+ partitions
[i
]->nblks
- 1;
num_blks
+= partitions
[i
]->nblks
;
if(partitions
[i
]->nblks
* BYTES_PER_SECTOR
!= partitions
[i
]->size
)
fprintf(debug_file
,"%s: Warning: %s size (%lld) not same as size in vtoc (%lld)\n",\
disk_name
,partitions
[i
]->part_filename
,partitions
[i
]->size
,partitions
[i
]->nblks
* BYTES_PER_SECTOR
);
for(int i
= 0; i
< VTOC8_NDKMAP
; i
++)
if(i
!= 2 && dkl
->dkl_map
[i
].dkl_nblk
!= 0){
// some partitions present in VTOV are not bein added.
// Reads/writes will be ignored.
fprintf(debug_file
,"%s: Warning - partition %d present in VTOC not configured\n",disk_name
,i
);
fprintf(debug_file
,"%s: Warning - some reads/writes MAY not succeed \n",disk_name
);
sectors_per_track
= dkl
->dkl_nsect
; // default 32
tracks_per_cylinder
= dkl
->dkl_nhead
; // default 16
num_cylinder
= ceil(1.0 * num_blks
/sectors_per_track
/tracks_per_cylinder
);// total number of cyinders in disk
// start init'ing the disk label
strcpy(disk_label
.dkl_ascii_label
,"SUN");
disk_label
.dkl_rpm
= DKLABEL_RPM
;
disk_label
.dkl_intrlv
= DKLABEL_INTRLV
;
disk_label
.dkl_acyl
= DKLABEL_ACYL
;
disk_label
.dkl_magic
= DKLABEL_MAGIC
;
disk_label
.dkl_write_reinstruct
= 0;
disk_label
.dkl_read_reinstruct
= 0;
disk_label
.dkl_nsect
= sectors_per_track
;
disk_label
.dkl_nhead
= tracks_per_cylinder
;
disk_label
.dkl_vtoc
.v_nparts
= MAX_PARTITIONS
;
disk_label
.dkl_vtoc
.v_version
= 0x1;
disk_label
.dkl_vtoc
.v_sanity
= VTOC_SANITY
;
strcpy(disk_label
.dkl_vtoc
.v_volume
,"SAM_VOL");
// start the lowest specified partition from cylinder 0 or 1.
for( int i
= 0; i
< MAX_PARTITIONS
; i
++){
if( (partitions
[i
] == 0) )
// we are creating a fake vtoc. check to see if the partition
// itself does not contain a vtoc. If it does, the access will fail
// as sector 0 will be duplicated. We bail out on such cases. The
// user needs to use the vtoc on partition here. This does not apply
// to s2 since the OS knows there is a label at sector 0, whether
// faked or real. Treat as fatal.
struct vtoc8_dk_label
* dkl
= (vtoc8_dk_label
*) buf
;
lseek(partitions
[i
]->primary_fd
,0,SEEK_SET
);
read(partitions
[i
]->primary_fd
,buf
,BYTES_PER_SECTOR
);
if(dkl
->dkl_magic
== DKLABEL_MAGIC
){
fprintf(stderr
,"%s.%s: Disk Label found on sector 0 of %s\n",\
disk_name
,partitions
[i
]->part_name
,partitions
[i
]->part_filename
);
fprintf(stderr
," : Use the label on image or clip sector 0\n.");
disk_label
.dkl_vtoc
.v_part
[i
].p_tag
= 0x04; // User
disk_label
.dkl_vtoc
.v_part
[2].p_tag
= 0x02; // Root
disk_label
.dkl_vtoc
.v_part
[i
].p_flag
= 0x00; // Mountable, rw
disk_label
.dkl_map
[i
].dkl_cylno
= num_cylinder
;
disk_label
.dkl_map
[i
].dkl_nblk
= ceil(1.0 * partitions
[i
]->size
/ bytes_per_sector
);
int64_t cylinders_in_partition
= ceil ( 1.0 * disk_label
.dkl_map
[i
].dkl_nblk
/ sectors_per_track
/ tracks_per_cylinder
);
if( num_cylinder
+ cylinders_in_partition
> 0x7fffffffLL
){
fprintf(debug_file
,"%s: number of cylinders exceed 0x7fffffff. Modify VTOC\n",disk_name
);
num_cylinder
+= cylinders_in_partition
;
num_blks
+= disk_label
.dkl_map
[i
].dkl_nblk
;
disk_label
.dkl_pcyl
= num_cylinder
;
disk_label
.dkl_ncyl
= num_cylinder
;
// fill in the start/end/num blocks in partitions
for( int i
= 0; i
< MAX_PARTITIONS
; i
++){
partitions
[i
]->nblks
= disk_label
.dkl_map
[i
].dkl_nblk
;
partitions
[i
]->start_lblk
= disk_label
.dkl_map
[i
].dkl_cylno
* disk_label
.dkl_nsect
* disk_label
.dkl_nhead
;
partitions
[i
]->end_lblk
= partitions
[i
]->start_lblk
+ partitions
[i
]->nblks
- 1;
// SCSI CAPACITY command reads the numberof nblocks in the disk. It is a 32 bit
// unsigned number. That gives a limit on size of disk as 2^32 * 512 = 2^41
// bytes or 2 TB. Put a check here for this limit. Note that this would not
// work in case of real VTOC, where partitions can overlap. SAM does not
// create disks from partitions that overlap, hence this check works.
if(num_blks
> 0xffffffffULL
){
fprintf(debug_file
,"%s: Fatal - Total disk size exceeds 2 TB!! LBLKS = %lld\n",disk_name
,num_blks
);
// return true on success, else false
bool Disk::add_partition(int partition
, const char * filename
, bool rw
, bool has_vtoc
){
// only one partition is allowed. It may or may not have a vtoc
fprintf(stderr
,"Cannot have more than 1 partitions with s2\n");
assert(num_partitions
== 0);
// this disk is being configured with an s2 along with other
// partition. Not allowed
fprintf(stderr
,"Can't have another partition with s2\n");
assert(vtoc_partition
== -1);
vtoc_partition
= partition
;
int oflag
= O_RDONLY
|O_LARGEFILE
; // XXX choose based upon 'rw' mode
if( (fd
= open(filename
, oflag
)) == -1){
fprintf(debug_file
,"%s: open() file %s errno: %d , %s \n", disk_name
, filename
, errno
, strerror(errno
));
if(stat(filename
, &statbuf
) == -1){
fprintf(debug_file
,"%s: Could not stat() file %s \n",disk_name
, filename
);
assert(partitions
[partition
] == 0);
Partition
* P
= partitions
[partition
] = new Partition();
P
->part_filename
= strdup(filename
);
sprintf(buf
,"s%d",partition
);
P
->part_name
= strdup(buf
);
P
->is_device_file
= statbuf
.st_rdev
;
P
->size
= statbuf
.st_size
;
P
->size
= lseek(fd
,0,SEEK_END
);
if(P
->size
% BYTES_PER_SECTOR
){
fprintf(debug_file
,"partition %d(%s) size not multiple of %d bytes\n",partition
,filename
,BYTES_PER_SECTOR
);
// return number of bytes written, -1 on error
uint32_t Disk::disk_write_lblk( uint64_t lblkno
, uint8_t *buf
, uint32_t nblks
){
uint32_t blocks_to_write
= nblks
;
if(lblkno
== 0 && fake_vtoc
){
bcopy(buf
,&disk_label
,BYTES_PER_SECTOR
);
label_endian_convert(&disk_label
);
for(int i
= 0; i
< MAX_PARTITIONS
&& blocks_to_write
; i
++){
if(partitions
[i
] && partitions
[i
]->lblk_inrange(lblkno
)){
// handle case of overlapping partitions. The lowest numbered
// partition having the block is read/written to
uint32_t retp
= partitions
[i
]->Write(lblkno
, buf
, blocks_to_write
);
fprintf(debug_file
,"%s:Warning. Write request at lblk %lld of size %ld wrote %ld lblks\n",disk_name
,lblkno
,nblks
,ret
);
// return number of bytes written
uint32_t Disk::disk_read_lblk( uint64_t lblkno
, uint8_t *buf
, uint32_t nblks
){
bzero(buf
,nblks
* BYTES_PER_SECTOR
);
uint32_t blocks_to_read
= nblks
;
if(lblkno
== 0 && fake_vtoc
){
struct vtoc8_dk_label tmp
;
bcopy(&disk_label
,&tmp
,sizeof(disk_label
));
label_endian_convert(&tmp
);
bcopy(&tmp
,buf
,BYTES_PER_SECTOR
);
bcopy(&disk_label
,buf
,BYTES_PER_SECTOR
);
for(int i
= 0; i
< MAX_PARTITIONS
&& blocks_to_read
; i
++){
if(partitions
[i
] && partitions
[i
]->lblk_inrange(lblkno
)){
// handle case of overlapping partitions. The lowest numbered
// partition having the block is read/written to
uint32_t retp
= partitions
[i
]->Read(lblkno
, buf
, blocks_to_read
);
fprintf(debug_file
,"%s:Warning. Read request at lblk %lld of size %ld read %ld lblks\n",disk_name
,lblkno
,nblks
,ret
);
bool Disk::dump(const char * dir
){
for(int i
= 0; i
< MAX_PARTITIONS
; i
++){
ret
&= partitions
[i
]->dump(dir
,disk_name
);
bool Disk::restore(const char * dir
){
for(int i
= 0; i
< MAX_PARTITIONS
; i
++){
ret
&= partitions
[i
]->restore(dir
,disk_name
);
ret
&= restore_misc(dir
);
bool Partition::dump(const char * dir
, const char * disk_name
){
bitset
* b
= new bitset (bitmap_size
);
if(ckpt_bitmap
) b
->Or(ckpt_bitmap
);
sprintf(buf
, "%s/%s.%s.dmp",dir
,disk_name
,part_name
);
FILE * fp
= fopen(buf
,"w");
sprintf(buf
, "%s/%s.%s.shadow",dir
,disk_name
,part_name
);
int to_fd
= open(buf
,O_WRONLY
|O_CREAT
|O_LARGEFILE
,0777);
lseek(to_fd
,nblks
*BYTES_PER_SECTOR
- 1,SEEK_SET
);
assert(write(to_fd
,"",1) == 1);
const char * src_file
= 0;
for(uint64_t i
= 0; i
< bitmap_size
; i
++){
char tmpbuf
[DISK_PAGE_SIZE
];
if(overlay_bitmap
->get(i
)){
src_file
= overlay_filename
;
}else if(ckpt_bitmap
&& ckpt_bitmap
->get(i
)){
src_file
= ckpt_filename
;
lseek(src_fd
,i
* DISK_PAGE_SIZE
, SEEK_SET
);
read(src_fd
,tmpbuf
,DISK_PAGE_SIZE
);
lseek(to_fd
,i
* DISK_PAGE_SIZE
, SEEK_SET
);
if(write(to_fd
,tmpbuf
,DISK_PAGE_SIZE
) != DISK_PAGE_SIZE
){
fprintf(debug_file
,"%s:Error writing checkpoint file %s offset %llx\n",part_name
,buf
,i
*DISK_PAGE_SIZE
);
bool Partition::restore(const char * dir
, const char * disk_name
){
sprintf(buf
, "%s/%s.%s.dmp",dir
,disk_name
,part_name
);
FILE * fp
= fopen(buf
,"r");
ckpt_bitmap
= new bitset(bitmap_size
,part_name
);
ckpt_bitmap
->restore(fp
);
sprintf(buf
,"%s/%s.%s.shadow",dir
,disk_name
,part_name
);
ckpt_filename
= strdup(buf
);
if( (ckpt_fd
= open(ckpt_filename
, O_RDONLY
|O_LARGEFILE
)) == -1){
fprintf(debug_file
,"%s: open() file %s errno: %d , %s \n", disk_name
, ckpt_filename
, errno
, strerror(errno
));
uint32_t Partition::Read(uint64_t lblkno
, uint8_t *buf
, uint32_t numblks
){
uint64_t relative_lblk
= lblkno
- start_lblk
; // lblk from start of backup file
const char * src_file
= 0;
uint32_t blocks_read
= 0;
char tmpbuf
[DISK_PAGE_SIZE
];
bzero(tmpbuf
,DISK_PAGE_SIZE
);
while(numblks
!= blocks_read
){
uint32_t blks_in_cur_page
= (BLOCKS_PER_PAGE
- relative_lblk
% BLOCKS_PER_PAGE
)\
< (numblks
- blocks_read
) ? (BLOCKS_PER_PAGE
- relative_lblk
% BLOCKS_PER_PAGE
):numblks
- blocks_read
;
bitmap_pos
= relative_lblk
/BLOCKS_PER_PAGE
; // 1 bit for every BLOCKS_PER_PAGE lblks
if(overlay_bitmap
->get(bitmap_pos
)){
src_fd
= overlay_fd
; // page has been modified earlier
src_file
= overlay_filename
;
lblk_reads_overlay
+= blks_in_cur_page
;
}else if(ckpt_bitmap
&& ckpt_bitmap
->get(bitmap_pos
)){
src_fd
= ckpt_fd
; // page has been modified and is present in the chpt
src_file
= ckpt_filename
;
lblk_reads_ckpt
+= blks_in_cur_page
;
src_fd
= primary_fd
; // page has not been written to yet. read from
src_file
= part_filename
;
lblk_reads_primary
+= blks_in_cur_page
;
if(lseek(src_fd
,bitmap_pos
* DISK_PAGE_SIZE
,SEEK_SET
) != bitmap_pos
* DISK_PAGE_SIZE
){
// the partition file does not have requested lblk. This may happen if
// vtoc specified a different parition size than the actual file size,
// or there may be partially filled lblk. In this case we can't
// write(barring certain cases). We print an error message and
// continue. The user needs to decide if this is fatal or not.
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
);
if(read(src_fd
, tmpbuf
, DISK_PAGE_SIZE
) != DISK_PAGE_SIZE
){
// src_fd is smaller than we thought. Flag an error, leave it to
// user to decide if its fatal. XXX cannot happen if DISK_PAGE_SIZE
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
);
bcopy(tmpbuf
+ (relative_lblk
% BLOCKS_PER_PAGE
) *BYTES_PER_SECTOR
,\
buf
, blks_in_cur_page
*BYTES_PER_SECTOR
);
blocks_read
+= blks_in_cur_page
;
buf
+= blks_in_cur_page
* BYTES_PER_SECTOR
;
relative_lblk
+= blks_in_cur_page
;
lblk_reads
+= blocks_read
;
// return the number of lblks written
uint32_t Partition::Write(uint64_t lblkno
, uint8_t *buf
, uint32_t numblks
){
const uint32_t blocks_to_write
= numblks
;
uint64_t relative_lblk
= lblkno
- start_lblk
; // lblk from start of backup file
int to_fd
= rw
? primary_fd
:overlay_fd
; // file to which data would be written
char tmpbuf
[DISK_PAGE_SIZE
]; // read/write DISK_PAGE_SIZE at a time
const char * src_file
= 0;
const char * to_file
= rw
?part_filename
: overlay_filename
;
bzero(tmpbuf
,DISK_PAGE_SIZE
);
uint32_t blocks_written
= 0;
while(numblks
!= blocks_written
){
uint32_t blks_in_cur_page
= (BLOCKS_PER_PAGE
- relative_lblk
% BLOCKS_PER_PAGE
)\
< (numblks
- blocks_written
) ? (BLOCKS_PER_PAGE
- relative_lblk
% BLOCKS_PER_PAGE
):numblks
- blocks_written
;
bitmap_pos
= relative_lblk
/BLOCKS_PER_PAGE
; // 1 bit for every BLOCKS_PER_PAGE lblks
if(overlay_bitmap
->get(bitmap_pos
)){
src_fd
= overlay_fd
; // page has been modified earlier
src_file
= overlay_filename
;
}else if(ckpt_bitmap
&& ckpt_bitmap
->get(bitmap_pos
)){
src_fd
= ckpt_fd
; // page has been modified and is present in the chpt
src_file
= ckpt_filename
;
src_fd
= primary_fd
; // page has not been written to yet. Next
// writes will have src_fd = overlay_fd if this
src_file
= part_filename
;
if(!rw
) overlay_bitmap
->set(bitmap_pos
);
if(lseek(src_fd
,bitmap_pos
* DISK_PAGE_SIZE
,SEEK_SET
) != bitmap_pos
* DISK_PAGE_SIZE
){
// the parition file does not have requested lblk. This may happen if
// vtoc specified a different parition size than the actual file size,
// or there may be partially filled lblk. In this case we can't
// write(barring certain cases). We print an error message and
// continue. The user needs to decide if this is fatal or not.
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
);
if(read(src_fd
, tmpbuf
, DISK_PAGE_SIZE
) != DISK_PAGE_SIZE
){
// src_fd is smaller than we thought. Flag an error, leave it to
// user to decide if its fatal
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
);
bcopy(buf
,tmpbuf
+ (relative_lblk
% BLOCKS_PER_PAGE
)*BYTES_PER_SECTOR
,\
blks_in_cur_page
*BYTES_PER_SECTOR
);
if(lseek(to_fd
,bitmap_pos
* DISK_PAGE_SIZE
,SEEK_SET
) != bitmap_pos
* DISK_PAGE_SIZE
){
// should not happen, since this is atleast the vtoc specified size,
// or the real file(rw=true), in which case the lseek would fail above
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
);
if(write(to_fd
, tmpbuf
, DISK_PAGE_SIZE
) != DISK_PAGE_SIZE
){
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
);
buf
+= blks_in_cur_page
* BYTES_PER_SECTOR
;
blocks_written
+= blks_in_cur_page
;
relative_lblk
+= blks_in_cur_page
;
lblk_writes_primary
+= blks_in_cur_page
;
lblk_writes_overlay
+= blks_in_cur_page
;
lblk_writes
+= blocks_written
;