summaryrefslogtreecommitdiff
path: root/fs/udf/super.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/udf/super.c')
-rw-r--r--fs/udf/super.c260
1 files changed, 132 insertions, 128 deletions
diff --git a/fs/udf/super.c b/fs/udf/super.c
index f73239a9a97d..7949c338efa5 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -64,14 +64,13 @@
#include <linux/init.h>
#include <linux/uaccess.h>
-#define VDS_POS_PRIMARY_VOL_DESC 0
-#define VDS_POS_UNALLOC_SPACE_DESC 1
-#define VDS_POS_LOGICAL_VOL_DESC 2
-#define VDS_POS_PARTITION_DESC 3
-#define VDS_POS_IMP_USE_VOL_DESC 4
-#define VDS_POS_VOL_DESC_PTR 5
-#define VDS_POS_TERMINATING_DESC 6
-#define VDS_POS_LENGTH 7
+enum {
+ VDS_POS_PRIMARY_VOL_DESC,
+ VDS_POS_UNALLOC_SPACE_DESC,
+ VDS_POS_LOGICAL_VOL_DESC,
+ VDS_POS_IMP_USE_VOL_DESC,
+ VDS_POS_LENGTH
+};
#define VSD_FIRST_SECTOR_OFFSET 32768
#define VSD_MAX_SECTOR_OFFSET 0x800000
@@ -223,10 +222,6 @@ struct udf_options {
unsigned int session;
unsigned int lastblock;
unsigned int anchor;
- unsigned int volume;
- unsigned short partition;
- unsigned int fileset;
- unsigned int rootdir;
unsigned int flags;
umode_t umask;
kgid_t gid;
@@ -349,12 +344,8 @@ static int udf_show_options(struct seq_file *seq, struct dentry *root)
seq_puts(seq, ",shortad");
if (UDF_QUERY_FLAG(sb, UDF_FLAG_UID_FORGET))
seq_puts(seq, ",uid=forget");
- if (UDF_QUERY_FLAG(sb, UDF_FLAG_UID_IGNORE))
- seq_puts(seq, ",uid=ignore");
if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_FORGET))
seq_puts(seq, ",gid=forget");
- if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_IGNORE))
- seq_puts(seq, ",gid=ignore");
if (UDF_QUERY_FLAG(sb, UDF_FLAG_UID_SET))
seq_printf(seq, ",uid=%u", from_kuid(&init_user_ns, sbi->s_uid));
if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_SET))
@@ -371,10 +362,6 @@ static int udf_show_options(struct seq_file *seq, struct dentry *root)
seq_printf(seq, ",lastblock=%u", sbi->s_last_block);
if (sbi->s_anchor != 0)
seq_printf(seq, ",anchor=%u", sbi->s_anchor);
- /*
- * volume, partition, fileset and rootdir seem to be ignored
- * currently
- */
if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8))
seq_puts(seq, ",utf8");
if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP) && sbi->s_nls_map)
@@ -487,14 +474,9 @@ static int udf_parse_options(char *options, struct udf_options *uopt,
int option;
uopt->novrs = 0;
- uopt->partition = 0xFFFF;
uopt->session = 0xFFFFFFFF;
uopt->lastblock = 0;
uopt->anchor = 0;
- uopt->volume = 0xFFFFFFFF;
- uopt->rootdir = 0xFFFFFFFF;
- uopt->fileset = 0xFFFFFFFF;
- uopt->nls_map = NULL;
if (!options)
return 1;
@@ -582,42 +564,30 @@ static int udf_parse_options(char *options, struct udf_options *uopt,
uopt->anchor = option;
break;
case Opt_volume:
- if (match_int(args, &option))
- return 0;
- uopt->volume = option;
- break;
case Opt_partition:
- if (match_int(args, &option))
- return 0;
- uopt->partition = option;
- break;
case Opt_fileset:
- if (match_int(args, &option))
- return 0;
- uopt->fileset = option;
- break;
case Opt_rootdir:
- if (match_int(args, &option))
- return 0;
- uopt->rootdir = option;
+ /* Ignored (never implemented properly) */
break;
case Opt_utf8:
uopt->flags |= (1 << UDF_FLAG_UTF8);
break;
#ifdef CONFIG_UDF_NLS
case Opt_iocharset:
- uopt->nls_map = load_nls(args[0].from);
- uopt->flags |= (1 << UDF_FLAG_NLS_MAP);
+ if (!remount) {
+ if (uopt->nls_map)
+ unload_nls(uopt->nls_map);
+ uopt->nls_map = load_nls(args[0].from);
+ uopt->flags |= (1 << UDF_FLAG_NLS_MAP);
+ }
break;
#endif
- case Opt_uignore:
- uopt->flags |= (1 << UDF_FLAG_UID_IGNORE);
- break;
case Opt_uforget:
uopt->flags |= (1 << UDF_FLAG_UID_FORGET);
break;
+ case Opt_uignore:
case Opt_gignore:
- uopt->flags |= (1 << UDF_FLAG_GID_IGNORE);
+ /* These options are superseeded by uid=<number> */
break;
case Opt_gforget:
uopt->flags |= (1 << UDF_FLAG_GID_FORGET);
@@ -660,6 +630,7 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
uopt.umask = sbi->s_umask;
uopt.fmode = sbi->s_fmode;
uopt.dmode = sbi->s_dmode;
+ uopt.nls_map = NULL;
if (!udf_parse_options(options, &uopt, true))
return -EINVAL;
@@ -1592,6 +1563,60 @@ static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_
sbi->s_lvid_bh = NULL;
}
+/*
+ * Step for reallocation of table of partition descriptor sequence numbers.
+ * Must be power of 2.
+ */
+#define PART_DESC_ALLOC_STEP 32
+
+struct desc_seq_scan_data {
+ struct udf_vds_record vds[VDS_POS_LENGTH];
+ unsigned int size_part_descs;
+ struct udf_vds_record *part_descs_loc;
+};
+
+static struct udf_vds_record *handle_partition_descriptor(
+ struct buffer_head *bh,
+ struct desc_seq_scan_data *data)
+{
+ struct partitionDesc *desc = (struct partitionDesc *)bh->b_data;
+ int partnum;
+
+ partnum = le16_to_cpu(desc->partitionNumber);
+ if (partnum >= data->size_part_descs) {
+ struct udf_vds_record *new_loc;
+ unsigned int new_size = ALIGN(partnum, PART_DESC_ALLOC_STEP);
+
+ new_loc = kzalloc(sizeof(*new_loc) * new_size, GFP_KERNEL);
+ if (!new_loc)
+ return ERR_PTR(-ENOMEM);
+ memcpy(new_loc, data->part_descs_loc,
+ data->size_part_descs * sizeof(*new_loc));
+ kfree(data->part_descs_loc);
+ data->part_descs_loc = new_loc;
+ data->size_part_descs = new_size;
+ }
+ return &(data->part_descs_loc[partnum]);
+}
+
+
+static struct udf_vds_record *get_volume_descriptor_record(uint16_t ident,
+ struct buffer_head *bh, struct desc_seq_scan_data *data)
+{
+ switch (ident) {
+ case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */
+ return &(data->vds[VDS_POS_PRIMARY_VOL_DESC]);
+ case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */
+ return &(data->vds[VDS_POS_IMP_USE_VOL_DESC]);
+ case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */
+ return &(data->vds[VDS_POS_LOGICAL_VOL_DESC]);
+ case TAG_IDENT_USD: /* ISO 13346 3/10.8 */
+ return &(data->vds[VDS_POS_UNALLOC_SPACE_DESC]);
+ case TAG_IDENT_PD: /* ISO 13346 3/10.5 */
+ return handle_partition_descriptor(bh, data);
+ }
+ return NULL;
+}
/*
* Process a main/reserve volume descriptor sequence.
@@ -1608,18 +1633,23 @@ static noinline int udf_process_sequence(
struct kernel_lb_addr *fileset)
{
struct buffer_head *bh = NULL;
- struct udf_vds_record vds[VDS_POS_LENGTH];
struct udf_vds_record *curr;
struct generic_desc *gd;
struct volDescPtr *vdp;
bool done = false;
uint32_t vdsn;
uint16_t ident;
- long next_s = 0, next_e = 0;
int ret;
unsigned int indirections = 0;
-
- memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH);
+ struct desc_seq_scan_data data;
+ unsigned int i;
+
+ memset(data.vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH);
+ data.size_part_descs = PART_DESC_ALLOC_STEP;
+ data.part_descs_loc = kzalloc(sizeof(*data.part_descs_loc) *
+ data.size_part_descs, GFP_KERNEL);
+ if (!data.part_descs_loc)
+ return -ENOMEM;
/*
* Read the main descriptor sequence and find which descriptors
@@ -1628,79 +1658,51 @@ static noinline int udf_process_sequence(
for (; (!done && block <= lastblock); block++) {
bh = udf_read_tagged(sb, block, block, &ident);
- if (!bh) {
- udf_err(sb,
- "Block %llu of volume descriptor sequence is corrupted or we could not read it\n",
- (unsigned long long)block);
- return -EAGAIN;
- }
+ if (!bh)
+ break;
/* Process each descriptor (ISO 13346 3/8.3-8.4) */
gd = (struct generic_desc *)bh->b_data;
vdsn = le32_to_cpu(gd->volDescSeqNum);
switch (ident) {
- case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */
- curr = &vds[VDS_POS_PRIMARY_VOL_DESC];
- if (vdsn >= curr->volDescSeqNum) {
- curr->volDescSeqNum = vdsn;
- curr->block = block;
- }
- break;
case TAG_IDENT_VDP: /* ISO 13346 3/10.3 */
- curr = &vds[VDS_POS_VOL_DESC_PTR];
- if (vdsn >= curr->volDescSeqNum) {
- curr->volDescSeqNum = vdsn;
- curr->block = block;
-
- vdp = (struct volDescPtr *)bh->b_data;
- next_s = le32_to_cpu(
- vdp->nextVolDescSeqExt.extLocation);
- next_e = le32_to_cpu(
- vdp->nextVolDescSeqExt.extLength);
- next_e = next_e >> sb->s_blocksize_bits;
- next_e += next_s;
+ if (++indirections > UDF_MAX_TD_NESTING) {
+ udf_err(sb, "too many Volume Descriptor "
+ "Pointers (max %u supported)\n",
+ UDF_MAX_TD_NESTING);
+ brelse(bh);
+ return -EIO;
}
+
+ vdp = (struct volDescPtr *)bh->b_data;
+ block = le32_to_cpu(vdp->nextVolDescSeqExt.extLocation);
+ lastblock = le32_to_cpu(
+ vdp->nextVolDescSeqExt.extLength) >>
+ sb->s_blocksize_bits;
+ lastblock += block - 1;
+ /* For loop is going to increment 'block' again */
+ block--;
break;
+ case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */
case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */
- curr = &vds[VDS_POS_IMP_USE_VOL_DESC];
- if (vdsn >= curr->volDescSeqNum) {
- curr->volDescSeqNum = vdsn;
- curr->block = block;
- }
- break;
- case TAG_IDENT_PD: /* ISO 13346 3/10.5 */
- curr = &vds[VDS_POS_PARTITION_DESC];
- if (!curr->block)
- curr->block = block;
- break;
case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */
- curr = &vds[VDS_POS_LOGICAL_VOL_DESC];
- if (vdsn >= curr->volDescSeqNum) {
- curr->volDescSeqNum = vdsn;
- curr->block = block;
- }
- break;
case TAG_IDENT_USD: /* ISO 13346 3/10.8 */
- curr = &vds[VDS_POS_UNALLOC_SPACE_DESC];
+ case TAG_IDENT_PD: /* ISO 13346 3/10.5 */
+ curr = get_volume_descriptor_record(ident, bh, &data);
+ if (IS_ERR(curr)) {
+ brelse(bh);
+ return PTR_ERR(curr);
+ }
+ /* Descriptor we don't care about? */
+ if (!curr)
+ break;
if (vdsn >= curr->volDescSeqNum) {
curr->volDescSeqNum = vdsn;
curr->block = block;
}
break;
case TAG_IDENT_TD: /* ISO 13346 3/10.9 */
- if (++indirections > UDF_MAX_TD_NESTING) {
- udf_err(sb, "too many TDs (max %u supported)\n", UDF_MAX_TD_NESTING);
- brelse(bh);
- return -EIO;
- }
-
- vds[VDS_POS_TERMINATING_DESC].block = block;
- if (next_e) {
- block = next_s;
- lastblock = next_e;
- next_s = next_e = 0;
- } else
- done = true;
+ done = true;
break;
}
brelse(bh);
@@ -1709,31 +1711,27 @@ static noinline int udf_process_sequence(
* Now read interesting descriptors again and process them
* in a suitable order
*/
- if (!vds[VDS_POS_PRIMARY_VOL_DESC].block) {
+ if (!data.vds[VDS_POS_PRIMARY_VOL_DESC].block) {
udf_err(sb, "Primary Volume Descriptor not found!\n");
return -EAGAIN;
}
- ret = udf_load_pvoldesc(sb, vds[VDS_POS_PRIMARY_VOL_DESC].block);
+ ret = udf_load_pvoldesc(sb, data.vds[VDS_POS_PRIMARY_VOL_DESC].block);
if (ret < 0)
return ret;
- if (vds[VDS_POS_LOGICAL_VOL_DESC].block) {
+ if (data.vds[VDS_POS_LOGICAL_VOL_DESC].block) {
ret = udf_load_logicalvol(sb,
- vds[VDS_POS_LOGICAL_VOL_DESC].block,
- fileset);
+ data.vds[VDS_POS_LOGICAL_VOL_DESC].block,
+ fileset);
if (ret < 0)
return ret;
}
- if (vds[VDS_POS_PARTITION_DESC].block) {
- /*
- * We rescan the whole descriptor sequence to find
- * partition descriptor blocks and process them.
- */
- for (block = vds[VDS_POS_PARTITION_DESC].block;
- block < vds[VDS_POS_TERMINATING_DESC].block;
- block++) {
- ret = udf_load_partdesc(sb, block);
+ /* Now handle prevailing Partition Descriptors */
+ for (i = 0; i < data.size_part_descs; i++) {
+ if (data.part_descs_loc[i].block) {
+ ret = udf_load_partdesc(sb,
+ data.part_descs_loc[i].block);
if (ret < 0)
return ret;
}
@@ -1760,13 +1758,13 @@ static int udf_load_sequence(struct super_block *sb, struct buffer_head *bh,
main_s = le32_to_cpu(anchor->mainVolDescSeqExt.extLocation);
main_e = le32_to_cpu(anchor->mainVolDescSeqExt.extLength);
main_e = main_e >> sb->s_blocksize_bits;
- main_e += main_s;
+ main_e += main_s - 1;
/* Locate the reserve sequence */
reserve_s = le32_to_cpu(anchor->reserveVolDescSeqExt.extLocation);
reserve_e = le32_to_cpu(anchor->reserveVolDescSeqExt.extLength);
reserve_e = reserve_e >> sb->s_blocksize_bits;
- reserve_e += reserve_s;
+ reserve_e += reserve_s - 1;
/* Process the main & reserve sequences */
/* responsible for finding the PartitionDesc(s) */
@@ -1994,7 +1992,10 @@ static void udf_open_lvid(struct super_block *sb)
lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
ktime_get_real_ts(&ts);
udf_time_to_disk_stamp(&lvid->recordingDateAndTime, ts);
- lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_OPEN);
+ if (le32_to_cpu(lvid->integrityType) == LVID_INTEGRITY_TYPE_CLOSE)
+ lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_OPEN);
+ else
+ UDF_SET_FLAG(sb, UDF_FLAG_INCONSISTENT);
lvid->descTag.descCRC = cpu_to_le16(
crc_itu_t(0, (char *)lvid + sizeof(struct tag),
@@ -2034,7 +2035,8 @@ static void udf_close_lvid(struct super_block *sb)
lvidiu->minUDFReadRev = cpu_to_le16(sbi->s_udfrev);
if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFWriteRev))
lvidiu->minUDFWriteRev = cpu_to_le16(sbi->s_udfrev);
- lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE);
+ if (!UDF_QUERY_FLAG(sb, UDF_FLAG_INCONSISTENT))
+ lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE);
lvid->descTag.descCRC = cpu_to_le16(
crc_itu_t(0, (char *)lvid + sizeof(struct tag),
@@ -2091,11 +2093,13 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
bool lvid_open = false;
uopt.flags = (1 << UDF_FLAG_USE_AD_IN_ICB) | (1 << UDF_FLAG_STRICT);
- uopt.uid = INVALID_UID;
- uopt.gid = INVALID_GID;
+ /* By default we'll use overflow[ug]id when UDF inode [ug]id == -1 */
+ uopt.uid = make_kuid(current_user_ns(), overflowuid);
+ uopt.gid = make_kgid(current_user_ns(), overflowgid);
uopt.umask = 0;
uopt.fmode = UDF_INVALID_MODE;
uopt.dmode = UDF_INVALID_MODE;
+ uopt.nls_map = NULL;
sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
@@ -2276,8 +2280,8 @@ error_out:
iput(sbi->s_vat_inode);
parse_options_failure:
#ifdef CONFIG_UDF_NLS
- if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
- unload_nls(sbi->s_nls_map);
+ if (uopt.nls_map)
+ unload_nls(uopt.nls_map);
#endif
if (lvid_open)
udf_close_lvid(sb);