File s390-tools-sles11sp2-cmsfs-fuse-fba.patch of Package s390-tools
Description: cmsfs-fuse: Add support for FBA-512 disks
Symptom: FBA-512 disks can not be mounted with cmsfs-fuse.
Problem: For FBA-512 disks the label information is at a different
position. Also the formatted block size may differ from the
disk block size.
Solution: Extend the label detection to work with FBA-512 disks and
read the formatted block size always from the label.
Problem-ID: 75986
---
cmsfs-fuse/cmsfs-fuse.c | 9 +----
cmsfs-fuse/cmsfs-fuse.h | 4 +-
cmsfs-fuse/dasd.c | 84 ++++++++++++++++++++++++++++++------------------
3 files changed, 58 insertions(+), 39 deletions(-)
--- a/cmsfs-fuse/cmsfs-fuse.c
+++ b/cmsfs-fuse/cmsfs-fuse.c
@@ -92,8 +92,6 @@ static void usage(const char *progname)
static char CODEPAGE_EDF[] = "CP1047";
static char CODEPAGE_LINUX[] = "ISO-8859-1";
-#define USED_BLOCK_ADDR (cmsfs.blksize * 2 + 32)
-
#define READDIR_FILE_ENTRY -1
#define READDIR_END_OF_DIR -2
#define READDIR_DIR_ENTRY -3
@@ -318,7 +316,7 @@ int _read(void *buf, size_t size, off_t
(addr & ~DATA_BLOCK_MASK))
DIE("read: crossing blocks addr: %lx size: %ld\n",
addr, size);
- if (addr < cmsfs.fdir || addr > cmsfs.size)
+ if (addr < cmsfs.label || addr > cmsfs.size)
return -EIO;
memcpy(buf, cmsfs.map + addr, size);
@@ -331,8 +329,7 @@ int _write(const void *buf, size_t size,
(addr & ~DATA_BLOCK_MASK))
DIE("write: crossing blocks addr: %x size: %d\n",
(int)addr, (int)size);
-
- if ((addr < (2 * cmsfs.blksize)) || (addr > cmsfs.size))
+ if (addr < cmsfs.label || addr > cmsfs.size)
return -EIO;
if (buf == NULL)
@@ -2024,7 +2021,7 @@ static void update_block_count(void)
{
int rc;
- rc = _write(&cmsfs.used_blocks, sizeof(unsigned int), USED_BLOCK_ADDR);
+ rc = _write(&cmsfs.used_blocks, sizeof(unsigned int), cmsfs.label + 32);
BUG(rc < 0);
}
--- a/cmsfs-fuse/cmsfs-fuse.h
+++ b/cmsfs-fuse/cmsfs-fuse.h
@@ -50,12 +50,12 @@ struct cmsfs {
int blksize;
/* number of 512 byte blocks per block */
int nr_blocks_512;
- /* disk info */
- unsigned int format;
/* device is read only */
int readonly;
/* access permission for other users */
int allow_other;
+ /* offset to label */
+ off_t label;
/* offset to file directory root FST */
off_t fdir;
/* offset to allocation map */
--- a/cmsfs-fuse/dasd.c
+++ b/cmsfs-fuse/dasd.c
@@ -79,18 +79,9 @@ static int disk_supported(int fd, struct
{
unsigned int cms_id = VOL_LABEL_EBCDIC;
struct cms_label label;
- int offset, rc;
-
- /* check that this is a ldl disk */
- if (cmsfs->format != DASD_FORMAT_LDL) {
- fprintf(stderr, COMP "Disk not LDL formatted\n");
- return 0;
- }
-
- /* label is on block number 3 */
- offset = 2 * cmsfs->blksize;
+ int rc;
- rc = lseek(fd, offset, SEEK_SET);
+ rc = lseek(fd, cmsfs->label, SEEK_SET);
if (rc < 0) {
perror(COMP "lseek failed");
return 0;
@@ -103,11 +94,35 @@ static int disk_supported(int fd, struct
}
/* check that the label contains the CMS1 string */
- if (memcmp(label.id, &cms_id, sizeof(cms_id)) != 0) {
- fprintf(stderr, COMP "Disk is not a CMS disk\n");
+ if (memcmp(label.id, &cms_id, sizeof(cms_id)) != 0)
+ return 0;
+
+ /* label sanity checks */
+ if (label.blocksize != 4096 &&
+ label.blocksize != 2048 &&
+ label.blocksize != 1024 &&
+ label.blocksize != 512) {
+ fprintf(stderr, COMP "Invalid disk block size!\n");
+ return 0;
+ }
+
+ if (label.dop != 4 && label.dop != 5) {
+ fprintf(stderr, COMP "Invalid disk origin pointer!\n");
return 0;
}
+ if (label.fst_entry_size != sizeof(struct fst_entry)) {
+ fprintf(stderr, COMP "Invalid FST entry size!\n");
+ return 0;
+ }
+
+ if (label.fst_per_block != label.blocksize / label.fst_entry_size) {
+ fprintf(stderr, COMP "Invalid FST per block value!\n");
+ return 0;
+ }
+
+ /* set the blocksize to the formatted one */
+ cmsfs->blksize = label.blocksize;
DEBUG(" DOP: %d", label.dop);
/* block number 5 means 0x4000... */
cmsfs->fdir = (label.dop - 1) * cmsfs->blksize;
@@ -117,10 +132,11 @@ static int disk_supported(int fd, struct
cmsfs->used_blocks = label.used_blocks;
DEBUG(" Total blocks: %d Used blocks: %d",
cmsfs->total_blocks, cmsfs->used_blocks);
+
return 1;
}
-static void get_device_info_bdev(int fd, struct cmsfs *cmsfs)
+static void get_device_info_ioctl(int fd, struct cmsfs *cmsfs)
{
struct dasd_info2 *info = NULL;
@@ -137,11 +153,15 @@ static void get_device_info_bdev(int fd,
if (ioctl(fd, BIODASDINFO, info) != 0)
DIE("ioctl dasd info failed\n");
}
- cmsfs->format = info->format;
+
+ /* check that this is a ldl disk */
+ if (info->format != DASD_FORMAT_LDL)
+ DIE("Disk not LDL formatted\n");
+
free(info);
}
-static int blocksizes[] = { 4096, 512, 2048, 1024 };
+static int label_offsets[] = { 4096, 512, 2048, 1024, 8192 };
static void get_device_info_file(int fd, struct cmsfs *cmsfs)
{
@@ -151,14 +171,14 @@ static void get_device_info_file(int fd,
off_t offset;
int rc;
- cmsfs->blksize = 0;
+ cmsfs->label = 0;
/*
* Read the blocksize from label. Unfortunately the blocksize
* position depends on the blocksize... time for some heuristics.
*/
- for (i = 0; i < ARRAY_SIZE(blocksizes); i++) {
- offset = blocksizes[i] * 2;
+ for (i = 0; i < ARRAY_SIZE(label_offsets); i++) {
+ offset = label_offsets[i];
rc = lseek(fd, offset, SEEK_SET);
if (rc < 0)
@@ -170,19 +190,13 @@ static void get_device_info_file(int fd,
/* check if the label contains the CMS1 string */
if (memcmp(label, &cms_id, sizeof(cms_id)) == 0) {
- cmsfs->blksize = blocksizes[i];
+ cmsfs->label = offset;
break;
}
}
- if (!cmsfs->blksize)
- DIE("Error detecting blocksize from file!\n");
-
- /*
- * Hardcoded since the label doesn't contain that info.
- * Checking the disk identifier must be sufficient.
- */
- cmsfs->format = DASD_FORMAT_LDL;
+ if (!cmsfs->label)
+ DIE("Error CMS1 label not found!\n");
}
int get_device_info(struct cmsfs *cmsfs)
@@ -208,9 +222,17 @@ int get_device_info(struct cmsfs *cmsfs)
if (fstat(fd, &stat) < 0)
DIE_PERROR("fstat failed");
- if (S_ISBLK(stat.st_mode))
- get_device_info_bdev(fd, cmsfs);
- else if (S_ISREG(stat.st_mode))
+ if (S_ISBLK(stat.st_mode)) {
+ get_device_info_ioctl(fd, cmsfs);
+ cmsfs->label = 2 * cmsfs->blksize;
+
+ /* FBA disks have a different label location */
+ if (!disk_supported(fd, cmsfs)) {
+ cmsfs->label = cmsfs->blksize;
+ if (!disk_supported(fd, cmsfs))
+ goto error;
+ }
+ } else if (S_ISREG(stat.st_mode))
get_device_info_file(fd, cmsfs);
else
goto error;