aboutsummaryrefslogtreecommitdiff
path: root/fs/udf
diff options
context:
space:
mode:
Diffstat (limited to 'fs/udf')
-rw-r--r--fs/udf/Kconfig18
-rw-r--r--fs/udf/Makefile4
-rw-r--r--fs/udf/balloc.c1098
-rw-r--r--fs/udf/crc.c178
-rw-r--r--fs/udf/dir.c277
-rw-r--r--fs/udf/directory.c308
-rw-r--r--fs/udf/ecma_167.h584
-rw-r--r--fs/udf/file.c316
-rw-r--r--fs/udf/fsync.c56
-rw-r--r--fs/udf/ialloc.c163
-rw-r--r--fs/udf/inode.c2816
-rw-r--r--fs/udf/lowlevel.c38
-rw-r--r--fs/udf/misc.c248
-rw-r--r--fs/udf/namei.c1467
-rw-r--r--fs/udf/osta_udf.h95
-rw-r--r--fs/udf/partition.c353
-rw-r--r--fs/udf/super.c3087
-rw-r--r--fs/udf/symlink.c96
-rw-r--r--fs/udf/truncate.c411
-rw-r--r--fs/udf/udf_i.h76
-rw-r--r--fs/udf/udf_sb.h235
-rw-r--r--fs/udf/udfdecl.h241
-rw-r--r--fs/udf/udfend.h56
-rw-r--r--fs/udf/udftime.c128
-rw-r--r--fs/udf/unicode.c377
25 files changed, 6563 insertions, 6163 deletions
diff --git a/fs/udf/Kconfig b/fs/udf/Kconfig
new file mode 100644
index 00000000000..0e0e99bd6bc
--- /dev/null
+++ b/fs/udf/Kconfig
@@ -0,0 +1,18 @@
+config UDF_FS
+ tristate "UDF file system support"
+ select CRC_ITU_T
+ help
+ This is the new file system used on some CD-ROMs and DVDs. Say Y if
+ you intend to mount DVD discs or CDRW's written in packet mode, or
+ if written to by other UDF utilities, such as DirectCD.
+ Please read <file:Documentation/filesystems/udf.txt>.
+
+ To compile this file system support as a module, choose M here: the
+ module will be called udf.
+
+ If unsure, say N.
+
+config UDF_NLS
+ bool
+ default y
+ depends on (UDF_FS=m && NLS) || (UDF_FS=y && NLS=y)
diff --git a/fs/udf/Makefile b/fs/udf/Makefile
index be845e7540e..eb880f66c23 100644
--- a/fs/udf/Makefile
+++ b/fs/udf/Makefile
@@ -5,5 +5,5 @@
obj-$(CONFIG_UDF_FS) += udf.o
udf-objs := balloc.o dir.o file.o ialloc.o inode.o lowlevel.o namei.o \
- partition.o super.o truncate.o symlink.o fsync.o \
- crc.o directory.o misc.o udftime.o unicode.o
+ partition.o super.o truncate.o symlink.o \
+ directory.o misc.o udftime.o unicode.o
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c
index b9ded26b10a..1ba2baaf436 100644
--- a/fs/udf/balloc.c
+++ b/fs/udf/balloc.c
@@ -4,11 +4,6 @@
* PURPOSE
* Block allocation handling routines for the OSTA-UDF(tm) filesystem.
*
- * CONTACTS
- * E-mail regarding any portion of the Linux UDF file system should be
- * directed to the development team mailing list (run by majordomo):
- * linux_udf@hpesjro.fc.hp.com
- *
* COPYRIGHT
* This file is distributed under the terms of the GNU General Public
* License (GPL). Copies of the GPL can be obtained from:
@@ -26,109 +21,62 @@
#include "udfdecl.h"
-#include <linux/quotaops.h>
#include <linux/buffer_head.h>
#include <linux/bitops.h>
#include "udf_i.h"
#include "udf_sb.h"
-#define udf_clear_bit(nr,addr) ext2_clear_bit(nr,addr)
-#define udf_set_bit(nr,addr) ext2_set_bit(nr,addr)
-#define udf_test_bit(nr, addr) ext2_test_bit(nr, addr)
-#define udf_find_first_one_bit(addr, size) find_first_one_bit(addr, size)
-#define udf_find_next_one_bit(addr, size, offset) find_next_one_bit(addr, size, offset)
-
-#define leBPL_to_cpup(x) leNUM_to_cpup(BITS_PER_LONG, x)
-#define leNUM_to_cpup(x,y) xleNUM_to_cpup(x,y)
-#define xleNUM_to_cpup(x,y) (le ## x ## _to_cpup(y))
-#define uintBPL_t uint(BITS_PER_LONG)
-#define uint(x) xuint(x)
-#define xuint(x) __le ## x
+#define udf_clear_bit __test_and_clear_bit_le
+#define udf_set_bit __test_and_set_bit_le
+#define udf_test_bit test_bit_le
+#define udf_find_next_one_bit find_next_bit_le
-extern inline int find_next_one_bit (void * addr, int size, int offset)
-{
- uintBPL_t * p = ((uintBPL_t *) addr) + (offset / BITS_PER_LONG);
- int result = offset & ~(BITS_PER_LONG-1);
- unsigned long tmp;
-
- if (offset >= size)
- return size;
- size -= result;
- offset &= (BITS_PER_LONG-1);
- if (offset)
- {
- tmp = leBPL_to_cpup(p++);
- tmp &= ~0UL << offset;
- if (size < BITS_PER_LONG)
- goto found_first;
- if (tmp)
- goto found_middle;
- size -= BITS_PER_LONG;
- result += BITS_PER_LONG;
- }
- while (size & ~(BITS_PER_LONG-1))
- {
- if ((tmp = leBPL_to_cpup(p++)))
- goto found_middle;
- result += BITS_PER_LONG;
- size -= BITS_PER_LONG;
- }
- if (!size)
- return result;
- tmp = leBPL_to_cpup(p);
-found_first:
- tmp &= ~0UL >> (BITS_PER_LONG-size);
-found_middle:
- return result + ffz(~tmp);
-}
-
-#define find_first_one_bit(addr, size)\
- find_next_one_bit((addr), (size), 0)
-
-static int read_block_bitmap(struct super_block * sb,
- struct udf_bitmap *bitmap, unsigned int block, unsigned long bitmap_nr)
+static int read_block_bitmap(struct super_block *sb,
+ struct udf_bitmap *bitmap, unsigned int block,
+ unsigned long bitmap_nr)
{
struct buffer_head *bh = NULL;
int retval = 0;
- kernel_lb_addr loc;
+ struct kernel_lb_addr loc;
loc.logicalBlockNum = bitmap->s_extPosition;
- loc.partitionReferenceNum = UDF_SB_PARTITION(sb);
+ loc.partitionReferenceNum = UDF_SB(sb)->s_partition;
- bh = udf_tread(sb, udf_get_lb_pblock(sb, loc, block));
+ bh = udf_tread(sb, udf_get_lb_pblock(sb, &loc, block));
if (!bh)
- {
retval = -EIO;
- }
+
bitmap->s_block_bitmap[bitmap_nr] = bh;
return retval;
}
-static int __load_block_bitmap(struct super_block * sb,
- struct udf_bitmap *bitmap, unsigned int block_group)
+static int __load_block_bitmap(struct super_block *sb,
+ struct udf_bitmap *bitmap,
+ unsigned int block_group)
{
int retval = 0;
int nr_groups = bitmap->s_nr_groups;
- if (block_group >= nr_groups)
- {
- udf_debug("block_group (%d) > nr_groups (%d)\n", block_group, nr_groups);
+ if (block_group >= nr_groups) {
+ udf_debug("block_group (%d) > nr_groups (%d)\n",
+ block_group, nr_groups);
}
- if (bitmap->s_block_bitmap[block_group])
+ if (bitmap->s_block_bitmap[block_group]) {
return block_group;
- else
- {
- retval = read_block_bitmap(sb, bitmap, block_group, block_group);
+ } else {
+ retval = read_block_bitmap(sb, bitmap, block_group,
+ block_group);
if (retval < 0)
return retval;
return block_group;
}
}
-static inline int load_block_bitmap(struct super_block * sb,
- struct udf_bitmap *bitmap, unsigned int block_group)
+static inline int load_block_bitmap(struct super_block *sb,
+ struct udf_bitmap *bitmap,
+ unsigned int block_group)
{
int slot;
@@ -143,13 +91,28 @@ static inline int load_block_bitmap(struct super_block * sb,
return slot;
}
-static void udf_bitmap_free_blocks(struct super_block * sb,
- struct inode * inode,
- struct udf_bitmap *bitmap,
- kernel_lb_addr bloc, uint32_t offset, uint32_t count)
+static void udf_add_free_space(struct super_block *sb, u16 partition, u32 cnt)
+{
+ struct udf_sb_info *sbi = UDF_SB(sb);
+ struct logicalVolIntegrityDesc *lvid;
+
+ if (!sbi->s_lvid_bh)
+ return;
+
+ lvid = (struct logicalVolIntegrityDesc *)sbi->s_lvid_bh->b_data;
+ le32_add_cpu(&lvid->freeSpaceTable[partition], cnt);
+ udf_updated_lvid(sb);
+}
+
+static void udf_bitmap_free_blocks(struct super_block *sb,
+ struct udf_bitmap *bitmap,
+ struct kernel_lb_addr *bloc,
+ uint32_t offset,
+ uint32_t count)
{
struct udf_sb_info *sbi = UDF_SB(sb);
- struct buffer_head * bh = NULL;
+ struct buffer_head *bh = NULL;
+ struct udf_part_map *partmap;
unsigned long block;
unsigned long block_group;
unsigned long bit;
@@ -157,149 +120,122 @@ static void udf_bitmap_free_blocks(struct super_block * sb,
int bitmap_nr;
unsigned long overflow;
- down(&sbi->s_alloc_sem);
- if (bloc.logicalBlockNum < 0 ||
- (bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum))
- {
+ mutex_lock(&sbi->s_alloc_mutex);
+ partmap = &sbi->s_partmaps[bloc->partitionReferenceNum];
+ if (bloc->logicalBlockNum + count < count ||
+ (bloc->logicalBlockNum + count) > partmap->s_partition_len) {
udf_debug("%d < %d || %d + %d > %d\n",
- bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count,
- UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum));
+ bloc->logicalBlockNum, 0,
+ bloc->logicalBlockNum, count,
+ partmap->s_partition_len);
goto error_return;
}
- block = bloc.logicalBlockNum + offset + (sizeof(struct spaceBitmapDesc) << 3);
-
-do_more:
- overflow = 0;
- block_group = block >> (sb->s_blocksize_bits + 3);
- bit = block % (sb->s_blocksize << 3);
+ block = bloc->logicalBlockNum + offset +
+ (sizeof(struct spaceBitmapDesc) << 3);
- /*
- * Check to see if we are freeing blocks across a group boundary.
- */
- if (bit + count > (sb->s_blocksize << 3))
- {
- overflow = bit + count - (sb->s_blocksize << 3);
- count -= overflow;
- }
- bitmap_nr = load_block_bitmap(sb, bitmap, block_group);
- if (bitmap_nr < 0)
- goto error_return;
+ do {
+ overflow = 0;
+ block_group = block >> (sb->s_blocksize_bits + 3);
+ bit = block % (sb->s_blocksize << 3);
- bh = bitmap->s_block_bitmap[bitmap_nr];
- for (i=0; i < count; i++)
- {
- if (udf_set_bit(bit + i, bh->b_data))
- {
- udf_debug("bit %ld already set\n", bit + i);
- udf_debug("byte=%2x\n", ((char *)bh->b_data)[(bit + i) >> 3]);
+ /*
+ * Check to see if we are freeing blocks across a group boundary.
+ */
+ if (bit + count > (sb->s_blocksize << 3)) {
+ overflow = bit + count - (sb->s_blocksize << 3);
+ count -= overflow;
}
- else
- {
- if (inode)
- DQUOT_FREE_BLOCK(inode, 1);
- if (UDF_SB_LVIDBH(sb))
- {
- UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] =
- cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)])+1);
+ bitmap_nr = load_block_bitmap(sb, bitmap, block_group);
+ if (bitmap_nr < 0)
+ goto error_return;
+
+ bh = bitmap->s_block_bitmap[bitmap_nr];
+ for (i = 0; i < count; i++) {
+ if (udf_set_bit(bit + i, bh->b_data)) {
+ udf_debug("bit %ld already set\n", bit + i);
+ udf_debug("byte=%2x\n",
+ ((char *)bh->b_data)[(bit + i) >> 3]);
}
}
- }
- mark_buffer_dirty(bh);
- if (overflow)
- {
- block += count;
- count = overflow;
- goto do_more;
- }
+ udf_add_free_space(sb, sbi->s_partition, count);
+ mark_buffer_dirty(bh);
+ if (overflow) {
+ block += count;
+ count = overflow;
+ }
+ } while (overflow);
+
error_return:
- sb->s_dirt = 1;
- if (UDF_SB_LVIDBH(sb))
- mark_buffer_dirty(UDF_SB_LVIDBH(sb));
- up(&sbi->s_alloc_sem);
- return;
+ mutex_unlock(&sbi->s_alloc_mutex);
}
-static int udf_bitmap_prealloc_blocks(struct super_block * sb,
- struct inode * inode,
- struct udf_bitmap *bitmap, uint16_t partition, uint32_t first_block,
- uint32_t block_count)
+static int udf_bitmap_prealloc_blocks(struct super_block *sb,
+ struct udf_bitmap *bitmap,
+ uint16_t partition, uint32_t first_block,
+ uint32_t block_count)
{
struct udf_sb_info *sbi = UDF_SB(sb);
int alloc_count = 0;
int bit, block, block_group, group_start;
int nr_groups, bitmap_nr;
struct buffer_head *bh;
+ __u32 part_len;
- down(&sbi->s_alloc_sem);
- if (first_block < 0 || first_block >= UDF_SB_PARTLEN(sb, partition))
+ mutex_lock(&sbi->s_alloc_mutex);
+ part_len = sbi->s_partmaps[partition].s_partition_len;
+ if (first_block >= part_len)
goto out;
- if (first_block + block_count > UDF_SB_PARTLEN(sb, partition))
- block_count = UDF_SB_PARTLEN(sb, partition) - first_block;
+ if (first_block + block_count > part_len)
+ block_count = part_len - first_block;
-repeat:
- nr_groups = (UDF_SB_PARTLEN(sb, partition) +
- (sizeof(struct spaceBitmapDesc) << 3) + (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8);
- block = first_block + (sizeof(struct spaceBitmapDesc) << 3);
- block_group = block >> (sb->s_blocksize_bits + 3);
- group_start = block_group ? 0 : sizeof(struct spaceBitmapDesc);
+ do {
+ nr_groups = udf_compute_nr_groups(sb, partition);
+ block = first_block + (sizeof(struct spaceBitmapDesc) << 3);
+ block_group = block >> (sb->s_blocksize_bits + 3);
+ group_start = block_group ? 0 : sizeof(struct spaceBitmapDesc);
- bitmap_nr = load_block_bitmap(sb, bitmap, block_group);
- if (bitmap_nr < 0)
- goto out;
- bh = bitmap->s_block_bitmap[bitmap_nr];
+ bitmap_nr = load_block_bitmap(sb, bitmap, block_group);
+ if (bitmap_nr < 0)
+ goto out;
+ bh = bitmap->s_block_bitmap[bitmap_nr];
- bit = block % (sb->s_blocksize << 3);
+ bit = block % (sb->s_blocksize << 3);
- while (bit < (sb->s_blocksize << 3) && block_count > 0)
- {
- if (!udf_test_bit(bit, bh->b_data))
- goto out;
- else if (DQUOT_PREALLOC_BLOCK(inode, 1))
- goto out;
- else if (!udf_clear_bit(bit, bh->b_data))
- {
- udf_debug("bit already cleared for block %d\n", bit);
- DQUOT_FREE_BLOCK(inode, 1);
- goto out;
+ while (bit < (sb->s_blocksize << 3) && block_count > 0) {
+ if (!udf_clear_bit(bit, bh->b_data))
+ goto out;
+ block_count--;
+ alloc_count++;
+ bit++;
+ block++;
}
- block_count --;
- alloc_count ++;
- bit ++;
- block ++;
- }
- mark_buffer_dirty(bh);
- if (block_count > 0)
- goto repeat;
+ mark_buffer_dirty(bh);
+ } while (block_count > 0);
+
out:
- if (UDF_SB_LVIDBH(sb))
- {
- UDF_SB_LVID(sb)->freeSpaceTable[partition] =
- cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-alloc_count);
- mark_buffer_dirty(UDF_SB_LVIDBH(sb));
- }
- sb->s_dirt = 1;
- up(&sbi->s_alloc_sem);
+ udf_add_free_space(sb, partition, -alloc_count);
+ mutex_unlock(&sbi->s_alloc_mutex);
return alloc_count;
}
-static int udf_bitmap_new_block(struct super_block * sb,
- struct inode * inode,
- struct udf_bitmap *bitmap, uint16_t partition, uint32_t goal, int *err)
+static int udf_bitmap_new_block(struct super_block *sb,
+ struct udf_bitmap *bitmap, uint16_t partition,
+ uint32_t goal, int *err)
{
struct udf_sb_info *sbi = UDF_SB(sb);
- int newbit, bit=0, block, block_group, group_start;
+ int newbit, bit = 0, block, block_group, group_start;
int end_goal, nr_groups, bitmap_nr, i;
struct buffer_head *bh = NULL;
char *ptr;
int newblock = 0;
*err = -ENOSPC;
- down(&sbi->s_alloc_sem);
+ mutex_lock(&sbi->s_alloc_mutex);
repeat:
- if (goal < 0 || goal >= UDF_SB_PARTLEN(sb, partition))
+ if (goal >= sbi->s_partmaps[partition].s_partition_len)
goal = 0;
nr_groups = bitmap->s_nr_groups;
@@ -311,38 +247,37 @@ repeat:
if (bitmap_nr < 0)
goto error_return;
bh = bitmap->s_block_bitmap[bitmap_nr];
- ptr = memscan((char *)bh->b_data + group_start, 0xFF, sb->s_blocksize - group_start);
+ ptr = memscan((char *)bh->b_data + group_start, 0xFF,
+ sb->s_blocksize - group_start);
- if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize)
- {
+ if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize) {
bit = block % (sb->s_blocksize << 3);
-
if (udf_test_bit(bit, bh->b_data))
- {
goto got_block;
- }
+
end_goal = (bit + 63) & ~63;
bit = udf_find_next_one_bit(bh->b_data, end_goal, bit);
if (bit < end_goal)
goto got_block;
- ptr = memscan((char *)bh->b_data + (bit >> 3), 0xFF, sb->s_blocksize - ((bit + 7) >> 3));
+
+ ptr = memscan((char *)bh->b_data + (bit >> 3), 0xFF,
+ sb->s_blocksize - ((bit + 7) >> 3));
newbit = (ptr - ((char *)bh->b_data)) << 3;
- if (newbit < sb->s_blocksize << 3)
- {
+ if (newbit < sb->s_blocksize << 3) {
bit = newbit;
goto search_back;
}
- newbit = udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3, bit);
- if (newbit < sb->s_blocksize << 3)
- {
+
+ newbit = udf_find_next_one_bit(bh->b_data,
+ sb->s_blocksize << 3, bit);
+ if (newbit < sb->s_blocksize << 3) {
bit = newbit;
goto got_block;
}
}
- for (i=0; i<(nr_groups*2); i++)
- {
- block_group ++;
+ for (i = 0; i < (nr_groups * 2); i++) {
+ block_group++;
if (block_group >= nr_groups)
block_group = 0;
group_start = block_group ? 0 : sizeof(struct spaceBitmapDesc);
@@ -351,473 +286,424 @@ repeat:
if (bitmap_nr < 0)
goto error_return;
bh = bitmap->s_block_bitmap[bitmap_nr];
- if (i < nr_groups)
- {
- ptr = memscan((char *)bh->b_data + group_start, 0xFF, sb->s_blocksize - group_start);
- if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize)
- {
+ if (i < nr_groups) {
+ ptr = memscan((char *)bh->b_data + group_start, 0xFF,
+ sb->s_blocksize - group_start);
+ if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize) {
bit = (ptr - ((char *)bh->b_data)) << 3;
break;
}
- }
- else
- {
- bit = udf_find_next_one_bit((char *)bh->b_data, sb->s_blocksize << 3, group_start << 3);
+ } else {
+ bit = udf_find_next_one_bit(bh->b_data,
+ sb->s_blocksize << 3,
+ group_start << 3);
if (bit < sb->s_blocksize << 3)
break;
}
}
- if (i >= (nr_groups*2))
- {
- up(&sbi->s_alloc_sem);
+ if (i >= (nr_groups * 2)) {
+ mutex_unlock(&sbi->s_alloc_mutex);
return newblock;
}
if (bit < sb->s_blocksize << 3)
goto search_back;
else
- bit = udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3, group_start << 3);
- if (bit >= sb->s_blocksize << 3)
- {
- up(&sbi->s_alloc_sem);
+ bit = udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3,
+ group_start << 3);
+ if (bit >= sb->s_blocksize << 3) {
+ mutex_unlock(&sbi->s_alloc_mutex);
return 0;
}
search_back:
- for (i=0; i<7 && bit > (group_start << 3) && udf_test_bit(bit - 1, bh->b_data); i++, bit--);
-
-got_block:
-
- /*
- * Check quota for allocation of this block.
- */
- if (inode && DQUOT_ALLOC_BLOCK(inode, 1))
- {
- up(&sbi->s_alloc_sem);
- *err = -EDQUOT;
- return 0;
+ i = 0;
+ while (i < 7 && bit > (group_start << 3) &&
+ udf_test_bit(bit - 1, bh->b_data)) {
+ ++i;
+ --bit;
}
+got_block:
newblock = bit + (block_group << (sb->s_blocksize_bits + 3)) -
(sizeof(struct spaceBitmapDesc) << 3);
- if (!udf_clear_bit(bit, bh->b_data))
- {
+ if (!udf_clear_bit(bit, bh->b_data)) {
udf_debug("bit already cleared for block %d\n", bit);
goto repeat;
}
mark_buffer_dirty(bh);
- if (UDF_SB_LVIDBH(sb))
- {
- UDF_SB_LVID(sb)->freeSpaceTable[partition] =
- cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-1);
- mark_buffer_dirty(UDF_SB_LVIDBH(sb));
- }
- sb->s_dirt = 1;
- up(&sbi->s_alloc_sem);
+ udf_add_free_space(sb, partition, -1);
+ mutex_unlock(&sbi->s_alloc_mutex);
*err = 0;
return newblock;
error_return:
*err = -EIO;
- up(&sbi->s_alloc_sem);
+ mutex_unlock(&sbi->s_alloc_mutex);
return 0;
}
-static void udf_table_free_blocks(struct super_block * sb,
- struct inode * inode,
- struct inode * table,
- kernel_lb_addr bloc, uint32_t offset, uint32_t count)
+static void udf_table_free_blocks(struct super_block *sb,
+ struct inode *table,
+ struct kernel_lb_addr *bloc,
+ uint32_t offset,
+ uint32_t count)
{
struct udf_sb_info *sbi = UDF_SB(sb);
+ struct udf_part_map *partmap;
uint32_t start, end;
- uint32_t nextoffset, oextoffset, elen;
- kernel_lb_addr nbloc, obloc, eloc;
- struct buffer_head *obh, *nbh;
+ uint32_t elen;
+ struct kernel_lb_addr eloc;
+ struct extent_position oepos, epos;
int8_t etype;
int i;
+ struct udf_inode_info *iinfo;
- down(&sbi->s_alloc_sem);
- if (bloc.logicalBlockNum < 0 ||
- (bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum))
- {
+ mutex_lock(&sbi->s_alloc_mutex);
+ partmap = &sbi->s_partmaps[bloc->partitionReferenceNum];
+ if (bloc->logicalBlockNum + count < count ||
+ (bloc->logicalBlockNum + count) > partmap->s_partition_len) {
udf_debug("%d < %d || %d + %d > %d\n",
- bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count,
- UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum));
+ bloc->logicalBlockNum, 0,
+ bloc->logicalBlockNum, count,
+ partmap->s_partition_len);
goto error_return;
}
- /* We do this up front - There are some error conditions that could occure,
- but.. oh well */
- if (inode)
- DQUOT_FREE_BLOCK(inode, count);
- if (UDF_SB_LVIDBH(sb))
- {
- UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] =
- cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)])+count);
- mark_buffer_dirty(UDF_SB_LVIDBH(sb));
- }
+ iinfo = UDF_I(table);
+ udf_add_free_space(sb, sbi->s_partition, count);
- start = bloc.logicalBlockNum + offset;
- end = bloc.logicalBlockNum + offset + count - 1;
+ start = bloc->logicalBlockNum + offset;
+ end = bloc->logicalBlockNum + offset + count - 1;
- oextoffset = nextoffset = sizeof(struct unallocSpaceEntry);
+ epos.offset = oepos.offset = sizeof(struct unallocSpaceEntry);
elen = 0;
- obloc = nbloc = UDF_I_LOCATION(table);
-
- obh = nbh = NULL;
-
- while (count && (etype =
- udf_next_aext(table, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) != -1)
- {
- if (((eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits)) ==
- start))
- {
- if ((0x3FFFFFFF - elen) < (count << sb->s_blocksize_bits))
- {
- count -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
- start += ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
- elen = (etype << 30) | (0x40000000 - sb->s_blocksize);
- }
- else
- {
+ epos.block = oepos.block = iinfo->i_location;
+ epos.bh = oepos.bh = NULL;
+
+ while (count &&
+ (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) {
+ if (((eloc.logicalBlockNum +
+ (elen >> sb->s_blocksize_bits)) == start)) {
+ if ((0x3FFFFFFF - elen) <
+ (count << sb->s_blocksize_bits)) {
+ uint32_t tmp = ((0x3FFFFFFF - elen) >>
+ sb->s_blocksize_bits);
+ count -= tmp;
+ start += tmp;
elen = (etype << 30) |
- (elen + (count << sb->s_blocksize_bits));
+ (0x40000000 - sb->s_blocksize);
+ } else {
+ elen = (etype << 30) |
+ (elen +
+ (count << sb->s_blocksize_bits));
start += count;
count = 0;
}
- udf_write_aext(table, obloc, &oextoffset, eloc, elen, obh, 1);
- }
- else if (eloc.logicalBlockNum == (end + 1))
- {
- if ((0x3FFFFFFF - elen) < (count << sb->s_blocksize_bits))
- {
- count -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
- end -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
- eloc.logicalBlockNum -=
- ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
- elen = (etype << 30) | (0x40000000 - sb->s_blocksize);
- }
- else
- {
+ udf_write_aext(table, &oepos, &eloc, elen, 1);
+ } else if (eloc.logicalBlockNum == (end + 1)) {
+ if ((0x3FFFFFFF - elen) <
+ (count << sb->s_blocksize_bits)) {
+ uint32_t tmp = ((0x3FFFFFFF - elen) >>
+ sb->s_blocksize_bits);
+ count -= tmp;
+ end -= tmp;
+ eloc.logicalBlockNum -= tmp;
+ elen = (etype << 30) |
+ (0x40000000 - sb->s_blocksize);
+ } else {
eloc.logicalBlockNum = start;
elen = (etype << 30) |
- (elen + (count << sb->s_blocksize_bits));
+ (elen +
+ (count << sb->s_blocksize_bits));
end -= count;
count = 0;
}
- udf_write_aext(table, obloc, &oextoffset, eloc, elen, obh, 1);
+ udf_write_aext(table, &oepos, &eloc, elen, 1);
}
- if (nbh != obh)
- {
+ if (epos.bh != oepos.bh) {
i = -1;
- obloc = nbloc;
- udf_release_data(obh);
- atomic_inc(&nbh->b_count);
- obh = nbh;
- oextoffset = 0;
+ oepos.block = epos.block;
+ brelse(oepos.bh);
+ get_bh(epos.bh);
+ oepos.bh = epos.bh;
+ oepos.offset = 0;
+ } else {
+ oepos.offset = epos.offset;
}
- else
- oextoffset = nextoffset;
}
- if (count)
- {
- /* NOTE: we CANNOT use udf_add_aext here, as it can try to allocate
- a new block, and since we hold the super block lock already
- very bad things would happen :)
-
- We copy the behavior of udf_add_aext, but instead of
- trying to allocate a new block close to the existing one,
- we just steal a block from the extent we are trying to add.
-
- It would be nice if the blocks were close together, but it
- isn't required.
- */
+ if (count) {
+ /*
+ * NOTE: we CANNOT use udf_add_aext here, as it can try to
+ * allocate a new block, and since we hold the super block
+ * lock already very bad things would happen :)
+ *
+ * We copy the behavior of udf_add_aext, but instead of
+ * trying to allocate a new block close to the existing one,
+ * we just steal a block from the extent we are trying to add.
+ *
+ * It would be nice if the blocks were close together, but it
+ * isn't required.
+ */
int adsize;
- short_ad *sad = NULL;
- long_ad *lad = NULL;
+ struct short_ad *sad = NULL;
+ struct long_ad *lad = NULL;
struct allocExtDesc *aed;
eloc.logicalBlockNum = start;
elen = EXT_RECORDED_ALLOCATED |
(count << sb->s_blocksize_bits);
- if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_SHORT)
- adsize = sizeof(short_ad);
- else if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_LONG)
- adsize = sizeof(long_ad);
- else
- {
- udf_release_data(obh);
- udf_release_data(nbh);
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+ adsize = sizeof(struct short_ad);
+ else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+ adsize = sizeof(struct long_ad);
+ else {
+ brelse(oepos.bh);
+ brelse(epos.bh);
goto error_return;
}
- if (nextoffset + (2 * adsize) > sb->s_blocksize)
- {
- char *sptr, *dptr;
+ if (epos.offset + (2 * adsize) > sb->s_blocksize) {
+ unsigned char *sptr, *dptr;
int loffset;
-
- udf_release_data(obh);
- obh = nbh;
- obloc = nbloc;
- oextoffset = nextoffset;
+
+ brelse(oepos.bh);
+ oepos = epos;
/* Steal a block from the extent being free'd */
- nbloc.logicalBlockNum = eloc.logicalBlockNum;
- eloc.logicalBlockNum ++;
+ epos.block.logicalBlockNum = eloc.logicalBlockNum;
+ eloc.logicalBlockNum++;
elen -= sb->s_blocksize;
- if (!(nbh = udf_tread(sb,
- udf_get_lb_pblock(sb, nbloc, 0))))
- {
- udf_release_data(obh);
+ epos.bh = udf_tread(sb,
+ udf_get_lb_pblock(sb, &epos.block, 0));
+ if (!epos.bh) {
+ brelse(oepos.bh);
goto error_return;
}
- aed = (struct allocExtDesc *)(nbh->b_data);
- aed->previousAllocExtLocation = cpu_to_le32(obloc.logicalBlockNum);
- if (nextoffset + adsize > sb->s_blocksize)
- {
- loffset = nextoffset;
+ aed = (struct allocExtDesc *)(epos.bh->b_data);
+ aed->previousAllocExtLocation =
+ cpu_to_le32(oepos.block.logicalBlockNum);
+ if (epos.offset + adsize > sb->s_blocksize) {
+ loffset = epos.offset;
aed->lengthAllocDescs = cpu_to_le32(adsize);
- if (obh)
- sptr = UDF_I_DATA(inode) + nextoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode) - adsize;
- else
- sptr = obh->b_data + nextoffset - adsize;
- dptr = nbh->b_data + sizeof(struct allocExtDesc);
+ sptr = iinfo->i_ext.i_data + epos.offset
+ - adsize;
+ dptr = epos.bh->b_data +
+ sizeof(struct allocExtDesc);
memcpy(dptr, sptr, adsize);
- nextoffset = sizeof(struct allocExtDesc) + adsize;
- }
- else
- {
- loffset = nextoffset + adsize;
+ epos.offset = sizeof(struct allocExtDesc) +
+ adsize;
+ } else {
+ loffset = epos.offset + adsize;
aed->lengthAllocDescs = cpu_to_le32(0);
- sptr = (obh)->b_data + nextoffset;
- nextoffset = sizeof(struct allocExtDesc);
-
- if (obh)
- {
- aed = (struct allocExtDesc *)(obh)->b_data;
- aed->lengthAllocDescs =
- cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
- }
- else
- {
- UDF_I_LENALLOC(table) += adsize;
+ if (oepos.bh) {
+ sptr = oepos.bh->b_data + epos.offset;
+ aed = (struct allocExtDesc *)
+ oepos.bh->b_data;
+ le32_add_cpu(&aed->lengthAllocDescs,
+ adsize);
+ } else {
+ sptr = iinfo->i_ext.i_data +
+ epos.offset;
+ iinfo->i_lenAlloc += adsize;
mark_inode_dirty(table);
}
+ epos.offset = sizeof(struct allocExtDesc);
}
- if (UDF_SB_UDFREV(sb) >= 0x0200)
- udf_new_tag(nbh->b_data, TAG_IDENT_AED, 3, 1,
- nbloc.logicalBlockNum, sizeof(tag));
+ if (sbi->s_udfrev >= 0x0200)
+ udf_new_tag(epos.bh->b_data, TAG_IDENT_AED,
+ 3, 1, epos.block.logicalBlockNum,
+ sizeof(struct tag));
else
- udf_new_tag(nbh->b_data, TAG_IDENT_AED, 2, 1,
- nbloc.logicalBlockNum, sizeof(tag));
- switch (UDF_I_ALLOCTYPE(table))
- {
- case ICBTAG_FLAG_AD_SHORT:
- {
- sad = (short_ad *)sptr;
- sad->extLength = cpu_to_le32(
- EXT_NEXT_EXTENT_ALLOCDECS |
- sb->s_blocksize);
- sad->extPosition = cpu_to_le32(nbloc.logicalBlockNum);
- break;
- }
- case ICBTAG_FLAG_AD_LONG:
- {
- lad = (long_ad *)sptr;
- lad->extLength = cpu_to_le32(
- EXT_NEXT_EXTENT_ALLOCDECS |
- sb->s_blocksize);
- lad->extLocation = cpu_to_lelb(nbloc);
- break;
- }
- }
- if (obh)
- {
- udf_update_tag(obh->b_data, loffset);
- mark_buffer_dirty(obh);
+ udf_new_tag(epos.bh->b_data, TAG_IDENT_AED,
+ 2, 1, epos.block.logicalBlockNum,
+ sizeof(struct tag));
+
+ switch (iinfo->i_alloc_type) {
+ case ICBTAG_FLAG_AD_SHORT:
+ sad = (struct short_ad *)sptr;
+ sad->extLength = cpu_to_le32(
+ EXT_NEXT_EXTENT_ALLOCDECS |
+ sb->s_blocksize);
+ sad->extPosition =
+ cpu_to_le32(epos.block.logicalBlockNum);
+ break;
+ case ICBTAG_FLAG_AD_LONG:
+ lad = (struct long_ad *)sptr;
+ lad->extLength = cpu_to_le32(
+ EXT_NEXT_EXTENT_ALLOCDECS |
+ sb->s_blocksize);
+ lad->extLocation =
+ cpu_to_lelb(epos.block);
+ break;
}
- else
+ if (oepos.bh) {
+ udf_update_tag(oepos.bh->b_data, loffset);
+ mark_buffer_dirty(oepos.bh);
+ } else {
mark_inode_dirty(table);
+ }
}
- if (elen) /* It's possible that stealing the block emptied the extent */
- {
- udf_write_aext(table, nbloc, &nextoffset, eloc, elen, nbh, 1);
+ /* It's possible that stealing the block emptied the extent */
+ if (elen) {
+ udf_write_aext(table, &epos, &eloc, elen, 1);
- if (!nbh)
- {
- UDF_I_LENALLOC(table) += adsize;
+ if (!epos.bh) {
+ iinfo->i_lenAlloc += adsize;
mark_inode_dirty(table);
- }
- else
- {
- aed = (struct allocExtDesc *)nbh->b_data;
- aed->lengthAllocDescs =
- cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
- udf_update_tag(nbh->b_data, nextoffset);
- mark_buffer_dirty(nbh);
+ } else {
+ aed = (struct allocExtDesc *)epos.bh->b_data;
+ le32_add_cpu(&aed->lengthAllocDescs, adsize);
+ udf_update_tag(epos.bh->b_data, epos.offset);
+ mark_buffer_dirty(epos.bh);
}
}
}
- udf_release_data(nbh);
- udf_release_data(obh);
+ brelse(epos.bh);
+ brelse(oepos.bh);
error_return:
- sb->s_dirt = 1;
- up(&sbi->s_alloc_sem);
+ mutex_unlock(&sbi->s_alloc_mutex);
return;
}
-static int udf_table_prealloc_blocks(struct super_block * sb,
- struct inode * inode,
- struct inode *table, uint16_t partition, uint32_t first_block,
- uint32_t block_count)
+static int udf_table_prealloc_blocks(struct super_block *sb,
+ struct inode *table, uint16_t partition,
+ uint32_t first_block, uint32_t block_count)
{
struct udf_sb_info *sbi = UDF_SB(sb);
int alloc_count = 0;
- uint32_t extoffset, elen, adsize;
- kernel_lb_addr bloc, eloc;
- struct buffer_head *bh;
+ uint32_t elen, adsize;
+ struct kernel_lb_addr eloc;
+ struct extent_position epos;
int8_t etype = -1;
+ struct udf_inode_info *iinfo;
- if (first_block < 0 || first_block >= UDF_SB_PARTLEN(sb, partition))
+ if (first_block >= sbi->s_partmaps[partition].s_partition_len)
return 0;
- if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_SHORT)
- adsize = sizeof(short_ad);
- else if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_LONG)
- adsize = sizeof(long_ad);
+ iinfo = UDF_I(table);
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+ adsize = sizeof(struct short_ad);
+ else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+ adsize = sizeof(struct long_ad);
else
return 0;
- down(&sbi->s_alloc_sem);
- extoffset = sizeof(struct unallocSpaceEntry);
- bloc = UDF_I_LOCATION(table);
-
- bh = NULL;
+ mutex_lock(&sbi->s_alloc_mutex);
+ epos.offset = sizeof(struct unallocSpaceEntry);
+ epos.block = iinfo->i_location;
+ epos.bh = NULL;
eloc.logicalBlockNum = 0xFFFFFFFF;
- while (first_block != eloc.logicalBlockNum && (etype =
- udf_next_aext(table, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
- {
+ while (first_block != eloc.logicalBlockNum &&
+ (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) {
udf_debug("eloc=%d, elen=%d, first_block=%d\n",
- eloc.logicalBlockNum, elen, first_block);
+ eloc.logicalBlockNum, elen, first_block);
; /* empty loop body */
}
- if (first_block == eloc.logicalBlockNum)
- {
- extoffset -= adsize;
+ if (first_block == eloc.logicalBlockNum) {
+ epos.offset -= adsize;
alloc_count = (elen >> sb->s_blocksize_bits);
- if (inode && DQUOT_PREALLOC_BLOCK(inode, alloc_count > block_count ? block_count : alloc_count))
- alloc_count = 0;
- else if (alloc_count > block_count)
- {
+ if (alloc_count > block_count) {
alloc_count = block_count;
eloc.logicalBlockNum += alloc_count;
elen -= (alloc_count << sb->s_blocksize_bits);
- udf_write_aext(table, bloc, &extoffset, eloc, (etype << 30) | elen, bh, 1);
- }
- else
- udf_delete_aext(table, bloc, extoffset, eloc, (etype << 30) | elen, bh);
- }
- else
+ udf_write_aext(table, &epos, &eloc,
+ (etype << 30) | elen, 1);
+ } else
+ udf_delete_aext(table, epos, eloc,
+ (etype << 30) | elen);
+ } else {
alloc_count = 0;
+ }
- udf_release_data(bh);
+ brelse(epos.bh);
- if (alloc_count && UDF_SB_LVIDBH(sb))
- {
- UDF_SB_LVID(sb)->freeSpaceTable[partition] =
- cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-alloc_count);
- mark_buffer_dirty(UDF_SB_LVIDBH(sb));
- sb->s_dirt = 1;
- }
- up(&sbi->s_alloc_sem);
+ if (alloc_count)
+ udf_add_free_space(sb, partition, -alloc_count);
+ mutex_unlock(&sbi->s_alloc_mutex);
return alloc_count;
}
-static int udf_table_new_block(struct super_block * sb,
- struct inode * inode,
- struct inode *table, uint16_t partition, uint32_t goal, int *err)
+static int udf_table_new_block(struct super_block *sb,
+ struct inode *table, uint16_t partition,
+ uint32_t goal, int *err)
{
struct udf_sb_info *sbi = UDF_SB(sb);
uint32_t spread = 0xFFFFFFFF, nspread = 0xFFFFFFFF;
uint32_t newblock = 0, adsize;
- uint32_t extoffset, goal_extoffset, elen, goal_elen = 0;
- kernel_lb_addr bloc, goal_bloc, eloc, goal_eloc;
- struct buffer_head *bh, *goal_bh;
+ uint32_t elen, goal_elen = 0;
+ struct kernel_lb_addr eloc, uninitialized_var(goal_eloc);
+ struct extent_position epos, goal_epos;
int8_t etype;
+ struct udf_inode_info *iinfo = UDF_I(table);
*err = -ENOSPC;
- if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_SHORT)
- adsize = sizeof(short_ad);
- else if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_LONG)
- adsize = sizeof(long_ad);
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+ adsize = sizeof(struct short_ad);
+ else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+ adsize = sizeof(struct long_ad);
else
return newblock;
- down(&sbi->s_alloc_sem);
- if (goal < 0 || goal >= UDF_SB_PARTLEN(sb, partition))
+ mutex_lock(&sbi->s_alloc_mutex);
+ if (goal >= sbi->s_partmaps[partition].s_partition_len)
goal = 0;
- /* We search for the closest matching block to goal. If we find a exact hit,
- we stop. Otherwise we keep going till we run out of extents.
- We store the buffer_head, bloc, and extoffset of the current closest
- match and use that when we are done.
- */
-
- extoffset = sizeof(struct unallocSpaceEntry);
- bloc = UDF_I_LOCATION(table);
-
- goal_bh = bh = NULL;
-
- while (spread && (etype =
- udf_next_aext(table, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
- {
- if (goal >= eloc.logicalBlockNum)
- {
- if (goal < eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits))
+ /* We search for the closest matching block to goal. If we find
+ a exact hit, we stop. Otherwise we keep going till we run out
+ of extents. We store the buffer_head, bloc, and extoffset
+ of the current closest match and use that when we are done.
+ */
+ epos.offset = sizeof(struct unallocSpaceEntry);
+ epos.block = iinfo->i_location;
+ epos.bh = goal_epos.bh = NULL;
+
+ while (spread &&
+ (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) {
+ if (goal >= eloc.logicalBlockNum) {
+ if (goal < eloc.logicalBlockNum +
+ (elen >> sb->s_blocksize_bits))
nspread = 0;
else
nspread = goal - eloc.logicalBlockNum -
(elen >> sb->s_blocksize_bits);
- }
- else
+ } else {
nspread = eloc.logicalBlockNum - goal;
+ }
- if (nspread < spread)
- {
+ if (nspread < spread) {
spread = nspread;
- if (goal_bh != bh)
- {
- udf_release_data(goal_bh);
- goal_bh = bh;
- atomic_inc(&goal_bh->b_count);
+ if (goal_epos.bh != epos.bh) {
+ brelse(goal_epos.bh);
+ goal_epos.bh = epos.bh;
+ get_bh(goal_epos.bh);
}
- goal_bloc = bloc;
- goal_extoffset = extoffset - adsize;
+ goal_epos.block = epos.block;
+ goal_epos.offset = epos.offset - adsize;
goal_eloc = eloc;
goal_elen = (etype << 30) | elen;
}
}
- udf_release_data(bh);
+ brelse(epos.bh);
- if (spread == 0xFFFFFFFF)
- {
- udf_release_data(goal_bh);
- up(&sbi->s_alloc_sem);
+ if (spread == 0xFFFFFFFF) {
+ brelse(goal_epos.bh);
+ mutex_unlock(&sbi->s_alloc_mutex);
return 0;
}
@@ -827,133 +713,113 @@ static int udf_table_new_block(struct super_block * sb,
/* This works, but very poorly.... */
newblock = goal_eloc.logicalBlockNum;
- goal_eloc.logicalBlockNum ++;
+ goal_eloc.logicalBlockNum++;
goal_elen -= sb->s_blocksize;
- if (inode && DQUOT_ALLOC_BLOCK(inode, 1))
- {
- udf_release_data(goal_bh);
- up(&sbi->s_alloc_sem);
- *err = -EDQUOT;
- return 0;
- }
-
if (goal_elen)
- udf_write_aext(table, goal_bloc, &goal_extoffset, goal_eloc, goal_elen, goal_bh, 1);
+ udf_write_aext(table, &goal_epos, &goal_eloc, goal_elen, 1);
else
- udf_delete_aext(table, goal_bloc, goal_extoffset, goal_eloc, goal_elen, goal_bh);
- udf_release_data(goal_bh);
-
- if (UDF_SB_LVIDBH(sb))
- {
- UDF_SB_LVID(sb)->freeSpaceTable[partition] =
- cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-1);
- mark_buffer_dirty(UDF_SB_LVIDBH(sb));
- }
+ udf_delete_aext(table, goal_epos, goal_eloc, goal_elen);
+ brelse(goal_epos.bh);
+
+ udf_add_free_space(sb, partition, -1);
- sb->s_dirt = 1;
- up(&sbi->s_alloc_sem);
+ mutex_unlock(&sbi->s_alloc_mutex);
*err = 0;
return newblock;
}
-inline void udf_free_blocks(struct super_block * sb,
- struct inode * inode,
- kernel_lb_addr bloc, uint32_t offset, uint32_t count)
+void udf_free_blocks(struct super_block *sb, struct inode *inode,
+ struct kernel_lb_addr *bloc, uint32_t offset,
+ uint32_t count)
{
- uint16_t partition = bloc.partitionReferenceNum;
-
- if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
- {
- return udf_bitmap_free_blocks(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
- bloc, offset, count);
- }
- else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE)
- {
- return udf_table_free_blocks(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
- bloc, offset, count);
- }
- else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP)
- {
- return udf_bitmap_free_blocks(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
- bloc, offset, count);
- }
- else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE)
- {
- return udf_table_free_blocks(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
- bloc, offset, count);
+ uint16_t partition = bloc->partitionReferenceNum;
+ struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition];
+
+ if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) {
+ udf_bitmap_free_blocks(sb, map->s_uspace.s_bitmap,
+ bloc, offset, count);
+ } else if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) {
+ udf_table_free_blocks(sb, map->s_uspace.s_table,
+ bloc, offset, count);
+ } else if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP) {
+ udf_bitmap_free_blocks(sb, map->s_fspace.s_bitmap,
+ bloc, offset, count);
+ } else if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE) {
+ udf_table_free_blocks(sb, map->s_fspace.s_table,
+ bloc, offset, count);
+ }
+
+ if (inode) {
+ inode_sub_bytes(inode,
+ ((sector_t)count) << sb->s_blocksize_bits);
}
- else
- return;
}
-inline int udf_prealloc_blocks(struct super_block * sb,
- struct inode * inode,
- uint16_t partition, uint32_t first_block, uint32_t block_count)
+inline int udf_prealloc_blocks(struct super_block *sb,
+ struct inode *inode,
+ uint16_t partition, uint32_t first_block,
+ uint32_t block_count)
{
- if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
- {
- return udf_bitmap_prealloc_blocks(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
- partition, first_block, block_count);
- }
- else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE)
- {
- return udf_table_prealloc_blocks(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
- partition, first_block, block_count);
- }
- else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP)
- {
- return udf_bitmap_prealloc_blocks(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
- partition, first_block, block_count);
- }
- else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE)
- {
- return udf_table_prealloc_blocks(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
- partition, first_block, block_count);
- }
+ struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition];
+ sector_t allocated;
+
+ if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP)
+ allocated = udf_bitmap_prealloc_blocks(sb,
+ map->s_uspace.s_bitmap,
+ partition, first_block,
+ block_count);
+ else if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE)
+ allocated = udf_table_prealloc_blocks(sb,
+ map->s_uspace.s_table,
+ partition, first_block,
+ block_count);
+ else if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP)
+ allocated = udf_bitmap_prealloc_blocks(sb,
+ map->s_fspace.s_bitmap,
+ partition, first_block,
+ block_count);
+ else if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE)
+ allocated = udf_table_prealloc_blocks(sb,
+ map->s_fspace.s_table,
+ partition, first_block,
+ block_count);
else
return 0;
+
+ if (inode && allocated > 0)
+ inode_add_bytes(inode, allocated << sb->s_blocksize_bits);
+ return allocated;
}
-inline int udf_new_block(struct super_block * sb,
- struct inode * inode,
- uint16_t partition, uint32_t goal, int *err)
+inline int udf_new_block(struct super_block *sb,
+ struct inode *inode,
+ uint16_t partition, uint32_t goal, int *err)
{
- if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
- {
- return udf_bitmap_new_block(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
- partition, goal, err);
- }
- else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE)
- {
- return udf_table_new_block(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
- partition, goal, err);
- }
- else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP)
- {
- return udf_bitmap_new_block(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
- partition, goal, err);
- }
- else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE)
- {
- return udf_table_new_block(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
- partition, goal, err);
- }
- else
- {
+ struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition];
+ int block;
+
+ if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP)
+ block = udf_bitmap_new_block(sb,
+ map->s_uspace.s_bitmap,
+ partition, goal, err);
+ else if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE)
+ block = udf_table_new_block(sb,
+ map->s_uspace.s_table,
+ partition, goal, err);
+ else if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP)
+ block = udf_bitmap_new_block(sb,
+ map->s_fspace.s_bitmap,
+ partition, goal, err);
+ else if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE)
+ block = udf_table_new_block(sb,
+ map->s_fspace.s_table,
+ partition, goal, err);
+ else {
*err = -EIO;
return 0;
}
+ if (inode && block)
+ inode_add_bytes(inode, sb->s_blocksize);
+ return block;
}
diff --git a/fs/udf/crc.c b/fs/udf/crc.c
deleted file mode 100644
index d95c6e38a45..00000000000
--- a/fs/udf/crc.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * crc.c
- *
- * PURPOSE
- * Routines to generate, calculate, and test a 16-bit CRC.
- *
- * DESCRIPTION
- * The CRC code was devised by Don P. Mitchell of AT&T Bell Laboratories
- * and Ned W. Rhodes of Software Systems Group. It has been published in
- * "Design and Validation of Computer Protocols", Prentice Hall,
- * Englewood Cliffs, NJ, 1991, Chapter 3, ISBN 0-13-539925-4.
- *
- * Copyright is held by AT&T.
- *
- * AT&T gives permission for the free use of the CRC source code.
- *
- * CONTACTS
- * E-mail regarding any portion of the Linux UDF file system should be
- * directed to the development team mailing list (run by majordomo):
- * linux_udf@hpesjro.fc.hp.com
- *
- * COPYRIGHT
- * This file is distributed under the terms of the GNU General Public
- * License (GPL). Copies of the GPL can be obtained from:
- * ftp://prep.ai.mit.edu/pub/gnu/GPL
- * Each contributing author retains all rights to their own work.
- */
-
-#include "udfdecl.h"
-
-static uint16_t crc_table[256] = {
- 0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50a5U, 0x60c6U, 0x70e7U,
- 0x8108U, 0x9129U, 0xa14aU, 0xb16bU, 0xc18cU, 0xd1adU, 0xe1ceU, 0xf1efU,
- 0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52b5U, 0x4294U, 0x72f7U, 0x62d6U,
- 0x9339U, 0x8318U, 0xb37bU, 0xa35aU, 0xd3bdU, 0xc39cU, 0xf3ffU, 0xe3deU,
- 0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64e6U, 0x74c7U, 0x44a4U, 0x5485U,
- 0xa56aU, 0xb54bU, 0x8528U, 0x9509U, 0xe5eeU, 0xf5cfU, 0xc5acU, 0xd58dU,
- 0x3653U, 0x2672U, 0x1611U, 0x0630U, 0x76d7U, 0x66f6U, 0x5695U, 0x46b4U,
- 0xb75bU, 0xa77aU, 0x9719U, 0x8738U, 0xf7dfU, 0xe7feU, 0xd79dU, 0xc7bcU,
- 0x48c4U, 0x58e5U, 0x6886U, 0x78a7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U,
- 0xc9ccU, 0xd9edU, 0xe98eU, 0xf9afU, 0x8948U, 0x9969U, 0xa90aU, 0xb92bU,
- 0x5af5U, 0x4ad4U, 0x7ab7U, 0x6a96U, 0x1a71U, 0x0a50U, 0x3a33U, 0x2a12U,
- 0xdbfdU, 0xcbdcU, 0xfbbfU, 0xeb9eU, 0x9b79U, 0x8b58U, 0xbb3bU, 0xab1aU,
- 0x6ca6U, 0x7c87U, 0x4ce4U, 0x5cc5U, 0x2c22U, 0x3c03U, 0x0c60U, 0x1c41U,
- 0xedaeU, 0xfd8fU, 0xcdecU, 0xddcdU, 0xad2aU, 0xbd0bU, 0x8d68U, 0x9d49U,
- 0x7e97U, 0x6eb6U, 0x5ed5U, 0x4ef4U, 0x3e13U, 0x2e32U, 0x1e51U, 0x0e70U,
- 0xff9fU, 0xefbeU, 0xdfddU, 0xcffcU, 0xbf1bU, 0xaf3aU, 0x9f59U, 0x8f78U,
- 0x9188U, 0x81a9U, 0xb1caU, 0xa1ebU, 0xd10cU, 0xc12dU, 0xf14eU, 0xe16fU,
- 0x1080U, 0x00a1U, 0x30c2U, 0x20e3U, 0x5004U, 0x4025U, 0x7046U, 0x6067U,
- 0x83b9U, 0x9398U, 0xa3fbU, 0xb3daU, 0xc33dU, 0xd31cU, 0xe37fU, 0xf35eU,
- 0x02b1U, 0x1290U, 0x22f3U, 0x32d2U, 0x4235U, 0x5214U, 0x6277U, 0x7256U,
- 0xb5eaU, 0xa5cbU, 0x95a8U, 0x8589U, 0xf56eU, 0xe54fU, 0xd52cU, 0xc50dU,
- 0x34e2U, 0x24c3U, 0x14a0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U,
- 0xa7dbU, 0xb7faU, 0x8799U, 0x97b8U, 0xe75fU, 0xf77eU, 0xc71dU, 0xd73cU,
- 0x26d3U, 0x36f2U, 0x0691U, 0x16b0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U,
- 0xd94cU, 0xc96dU, 0xf90eU, 0xe92fU, 0x99c8U, 0x89e9U, 0xb98aU, 0xa9abU,
- 0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18c0U, 0x08e1U, 0x3882U, 0x28a3U,
- 0xcb7dU, 0xdb5cU, 0xeb3fU, 0xfb1eU, 0x8bf9U, 0x9bd8U, 0xabbbU, 0xbb9aU,
- 0x4a75U, 0x5a54U, 0x6a37U, 0x7a16U, 0x0af1U, 0x1ad0U, 0x2ab3U, 0x3a92U,
- 0xfd2eU, 0xed0fU, 0xdd6cU, 0xcd4dU, 0xbdaaU, 0xad8bU, 0x9de8U, 0x8dc9U,
- 0x7c26U, 0x6c07U, 0x5c64U, 0x4c45U, 0x3ca2U, 0x2c83U, 0x1ce0U, 0x0cc1U,
- 0xef1fU, 0xff3eU, 0xcf5dU, 0xdf7cU, 0xaf9bU, 0xbfbaU, 0x8fd9U, 0x9ff8U,
- 0x6e17U, 0x7e36U, 0x4e55U, 0x5e74U, 0x2e93U, 0x3eb2U, 0x0ed1U, 0x1ef0U
-};
-
-/*
- * udf_crc
- *
- * PURPOSE
- * Calculate a 16-bit CRC checksum using ITU-T V.41 polynomial.
- *
- * DESCRIPTION
- * The OSTA-UDF(tm) 1.50 standard states that using CRCs is mandatory.
- * The polynomial used is: x^16 + x^12 + x^15 + 1
- *
- * PRE-CONDITIONS
- * data Pointer to the data block.
- * size Size of the data block.
- *
- * POST-CONDITIONS
- * <return> CRC of the data block.
- *
- * HISTORY
- * July 21, 1997 - Andrew E. Mileski
- * Adapted from OSTA-UDF(tm) 1.50 standard.
- */
-uint16_t
-udf_crc(uint8_t *data, uint32_t size, uint16_t crc)
-{
- while (size--)
- crc = crc_table[(crc >> 8 ^ *(data++)) & 0xffU] ^ (crc << 8);
-
- return crc;
-}
-
-/****************************************************************************/
-#if defined(TEST)
-
-/*
- * PURPOSE
- * Test udf_crc()
- *
- * HISTORY
- * July 21, 1997 - Andrew E. Mileski
- * Adapted from OSTA-UDF(tm) 1.50 standard.
- */
-
-unsigned char bytes[] = { 0x70U, 0x6AU, 0x77U };
-
-int main(void)
-{
- unsigned short x;
-
- x = udf_crc16(bytes, sizeof bytes);
- printf("udf_crc16: calculated = %4.4x, correct = %4.4x\n", x, 0x3299U);
-
- return 0;
-}
-
-#endif /* defined(TEST) */
-
-/****************************************************************************/
-#if defined(GENERATE)
-
-/*
- * PURPOSE
- * Generate a table for fast 16-bit CRC calculations (any polynomial).
- *
- * DESCRIPTION
- * The ITU-T V.41 polynomial is 010041.
- *
- * HISTORY
- * July 21, 1997 - Andrew E. Mileski
- * Adapted from OSTA-UDF(tm) 1.50 standard.
- */
-
-#include <stdio.h>
-
-int main(int argc, char **argv)
-{
- unsigned long crc, poly;
- int n, i;
-
- /* Get the polynomial */
- sscanf(argv[1], "%lo", &poly);
- if (poly & 0xffff0000U){
- fprintf(stderr, "polynomial is too large\en");
- exit(1);
- }
-
- printf("/* CRC 0%o */\n", poly);
-
- /* Create a table */
- printf("static unsigned short crc_table[256] = {\n");
- for (n = 0; n < 256; n++){
- if (n % 8 == 0)
- printf("\t");
- crc = n << 8;
- for (i = 0; i < 8; i++){
- if(crc & 0x8000U)
- crc = (crc << 1) ^ poly;
- else
- crc <<= 1;
- crc &= 0xFFFFU;
- }
- if (n == 255)
- printf("0x%04xU ", crc);
- else
- printf("0x%04xU, ", crc);
- if(n % 8 == 7)
- printf("\n");
- }
- printf("};\n");
-
- return 0;
-}
-
-#endif /* defined(GENERATE) */
diff --git a/fs/udf/dir.c b/fs/udf/dir.c
index 82440b73114..a012c51caff 100644
--- a/fs/udf/dir.c
+++ b/fs/udf/dir.c
@@ -4,11 +4,6 @@
* PURPOSE
* Directory handling routines for the OSTA-UDF(tm) filesystem.
*
- * CONTACTS
- * E-mail regarding any portion of the Linux UDF file system should be
- * directed to the development team mailing list (run by majordomo):
- * linux_udf@hpesjro.fc.hp.com
- *
* COPYRIGHT
* This file is distributed under the terms of the GNU General Public
* License (GPL). Copies of the GPL can be obtained from:
@@ -35,234 +30,170 @@
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
#include "udf_i.h"
#include "udf_sb.h"
-/* Prototypes for file operations */
-static int udf_readdir(struct file *, void *, filldir_t);
-static int do_udf_readdir(struct inode *, struct file *, filldir_t, void *);
-
-/* readdir and lookup functions */
-
-struct file_operations udf_dir_operations = {
- .read = generic_read_dir,
- .readdir = udf_readdir,
- .ioctl = udf_ioctl,
- .fsync = udf_fsync_file,
-};
-/*
- * udf_readdir
- *
- * PURPOSE
- * Read a directory entry.
- *
- * DESCRIPTION
- * Optional - sys_getdents() will return -ENOTDIR if this routine is not
- * available.
- *
- * Refer to sys_getdents() in fs/readdir.c
- * sys_getdents() -> .
- *
- * PRE-CONDITIONS
- * filp Pointer to directory file.
- * buf Pointer to directory entry buffer.
- * filldir Pointer to filldir function.
- *
- * POST-CONDITIONS
- * <return> >=0 on success.
- *
- * HISTORY
- * July 1, 1997 - Andrew E. Mileski
- * Written, tested, and released.
- */
-
-int udf_readdir(struct file *filp, void *dirent, filldir_t filldir)
+static int udf_readdir(struct file *file, struct dir_context *ctx)
{
- struct inode *dir = filp->f_dentry->d_inode;
- int result;
-
- lock_kernel();
-
- if ( filp->f_pos == 0 )
- {
- if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR) < 0)
- {
- unlock_kernel();
- return 0;
- }
- filp->f_pos ++;
- }
-
- result = do_udf_readdir(dir, filp, filldir, dirent);
- unlock_kernel();
- return result;
-}
-
-static int
-do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *dirent)
-{
- struct udf_fileident_bh fibh;
- struct fileIdentDesc *fi=NULL;
+ struct inode *dir = file_inode(file);
+ struct udf_inode_info *iinfo = UDF_I(dir);
+ struct udf_fileident_bh fibh = { .sbh = NULL, .ebh = NULL};
+ struct fileIdentDesc *fi = NULL;
struct fileIdentDesc cfi;
int block, iblock;
- loff_t nf_pos = filp->f_pos - 1;
+ loff_t nf_pos;
int flen;
- char fname[UDF_NAME_LEN];
- char *nameptr;
+ unsigned char *fname = NULL;
+ unsigned char *nameptr;
uint16_t liu;
uint8_t lfi;
- loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
- struct buffer_head * bh = NULL, * tmp, * bha[16];
- kernel_lb_addr bloc, eloc;
- uint32_t extoffset, elen, offset;
- int i, num;
- unsigned int dt_type;
-
+ loff_t size = udf_ext0_offset(dir) + dir->i_size;
+ struct buffer_head *tmp, *bha[16];
+ struct kernel_lb_addr eloc;
+ uint32_t elen;
+ sector_t offset;
+ int i, num, ret = 0;
+ struct extent_position epos = { NULL, 0, {0, 0} };
+
+ if (ctx->pos == 0) {
+ if (!dir_emit_dot(file, ctx))
+ return 0;
+ ctx->pos = 1;
+ }
+ nf_pos = (ctx->pos - 1) << 2;
if (nf_pos >= size)
- return 0;
+ goto out;
- if (nf_pos == 0)
- nf_pos = (udf_ext0_offset(dir) >> 2);
+ fname = kmalloc(UDF_NAME_LEN, GFP_NOFS);
+ if (!fname) {
+ ret = -ENOMEM;
+ goto out;
+ }
- fibh.soffset = fibh.eoffset = (nf_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
- fibh.sbh = fibh.ebh = NULL;
- else if (inode_bmap(dir, nf_pos >> (dir->i_sb->s_blocksize_bits - 2),
- &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30))
- {
- offset >>= dir->i_sb->s_blocksize_bits;
- block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
- if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
- {
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
- extoffset -= sizeof(short_ad);
- else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
- extoffset -= sizeof(long_ad);
+ if (nf_pos == 0)
+ nf_pos = udf_ext0_offset(dir);
+
+ fibh.soffset = fibh.eoffset = nf_pos & (dir->i_sb->s_blocksize - 1);
+ if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+ if (inode_bmap(dir, nf_pos >> dir->i_sb->s_blocksize_bits,
+ &epos, &eloc, &elen, &offset)
+ != (EXT_RECORDED_ALLOCATED >> 30)) {
+ ret = -ENOENT;
+ goto out;
}
- else
+ block = udf_get_lb_pblock(dir->i_sb, &eloc, offset);
+ if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+ epos.offset -= sizeof(struct short_ad);
+ else if (iinfo->i_alloc_type ==
+ ICBTAG_FLAG_AD_LONG)
+ epos.offset -= sizeof(struct long_ad);
+ } else {
offset = 0;
+ }
- if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block)))
- {
- udf_release_data(bh);
- return -EIO;
+ if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) {
+ ret = -EIO;
+ goto out;
}
-
- if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9))-1)))
- {
+
+ if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9)) - 1))) {
i = 16 >> (dir->i_sb->s_blocksize_bits - 9);
- if (i+offset > (elen >> dir->i_sb->s_blocksize_bits))
- i = (elen >> dir->i_sb->s_blocksize_bits)-offset;
- for (num=0; i>0; i--)
- {
- block = udf_get_lb_pblock(dir->i_sb, eloc, offset+i);
+ if (i + offset > (elen >> dir->i_sb->s_blocksize_bits))
+ i = (elen >> dir->i_sb->s_blocksize_bits) - offset;
+ for (num = 0; i > 0; i--) {
+ block = udf_get_lb_pblock(dir->i_sb, &eloc, offset + i);
tmp = udf_tgetblk(dir->i_sb, block);
if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
bha[num++] = tmp;
else
brelse(tmp);
}
- if (num)
- {
+ if (num) {
ll_rw_block(READA, num, bha);
- for (i=0; i<num; i++)
+ for (i = 0; i < num; i++)
brelse(bha[i]);
}
}
}
- else
- {
- udf_release_data(bh);
- return -ENOENT;
- }
- while ( nf_pos < size )
- {
- filp->f_pos = nf_pos + 1;
+ while (nf_pos < size) {
+ struct kernel_lb_addr tloc;
- fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
+ ctx->pos = (nf_pos >> 2) + 1;
+ fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc,
+ &elen, &offset);
if (!fi)
- {
- if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
- udf_release_data(bh);
- return 0;
- }
+ goto out;
liu = le16_to_cpu(cfi.lengthOfImpUse);
lfi = cfi.lengthFileIdent;
- if (fibh.sbh == fibh.ebh)
+ if (fibh.sbh == fibh.ebh) {
nameptr = fi->fileIdent + liu;
- else
- {
+ } else {
int poffset; /* Unpaded ending offset */
poffset = fibh.soffset + sizeof(struct fileIdentDesc) + liu + lfi;
- if (poffset >= lfi)
+ if (poffset >= lfi) {
nameptr = (char *)(fibh.ebh->b_data + poffset - lfi);
- else
- {
+ } else {
nameptr = fname;
- memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
- memcpy(nameptr + lfi - poffset, fibh.ebh->b_data, poffset);
+ memcpy(nameptr, fi->fileIdent + liu,
+ lfi - poffset);
+ memcpy(nameptr + lfi - poffset,
+ fibh.ebh->b_data, poffset);
}
}
- if ( (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) != 0 )
- {
- if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE) )
+ if ((cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
+ if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE))
continue;
}
-
- if ( (cfi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0 )
- {
- if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE) )
+
+ if ((cfi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) {
+ if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE))
continue;
}
- if ( cfi.fileCharacteristics & FID_FILE_CHAR_PARENT )
- {
- iblock = parent_ino(filp->f_dentry);
- flen = 2;
- memcpy(fname, "..", flen);
- dt_type = DT_DIR;
+ if (cfi.fileCharacteristics & FID_FILE_CHAR_PARENT) {
+ if (!dir_emit_dotdot(file, ctx))
+ goto out;
+ continue;
}
- else
- {
- kernel_lb_addr tloc = lelb_to_cpu(cfi.icb.extLocation);
- iblock = udf_get_lb_pblock(dir->i_sb, tloc, 0);
- flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi);
- dt_type = DT_UNKNOWN;
- }
+ flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi);
+ if (!flen)
+ continue;
- if (flen)
- {
- if (filldir(dirent, fname, flen, filp->f_pos, iblock, dt_type) < 0)
- {
- if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
- udf_release_data(bh);
- return 0;
- }
- }
+ tloc = lelb_to_cpu(cfi.icb.extLocation);
+ iblock = udf_get_lb_pblock(dir->i_sb, &tloc, 0);
+ if (!dir_emit(ctx, fname, flen, iblock, DT_UNKNOWN))
+ goto out;
} /* end while */
- filp->f_pos = nf_pos + 1;
+ ctx->pos = (nf_pos >> 2) + 1;
+out:
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
- udf_release_data(bh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
+ brelse(epos.bh);
+ kfree(fname);
- return 0;
+ return ret;
}
+
+/* readdir and lookup functions */
+const struct file_operations udf_dir_operations = {
+ .llseek = generic_file_llseek,
+ .read = generic_read_dir,
+ .iterate = udf_readdir,
+ .unlocked_ioctl = udf_ioctl,
+ .fsync = generic_file_fsync,
+};
diff --git a/fs/udf/directory.c b/fs/udf/directory.c
index 9a61ecc5451..3e44f575fb9 100644
--- a/fs/udf/directory.c
+++ b/fs/udf/directory.c
@@ -4,11 +4,6 @@
* PURPOSE
* Directory related functions
*
- * CONTACTS
- * E-mail regarding any portion of the Linux UDF file system should be
- * directed to the development team mailing list (run by majordomo):
- * linux_udf@hpesjro.fc.hp.com
- *
* COPYRIGHT
* This file is distributed under the terms of the GNU General Public
* License (GPL). Copies of the GPL can be obtained from:
@@ -23,233 +18,170 @@
#include <linux/string.h>
#include <linux/buffer_head.h>
-#if 0
-static uint8_t *
-udf_filead_read(struct inode *dir, uint8_t *tmpad, uint8_t ad_size,
- kernel_lb_addr fe_loc, int *pos, int *offset,
- struct buffer_head **bh, int *error)
-{
- int loffset = *offset;
- int block;
- uint8_t *ad;
- int remainder;
-
- *error = 0;
-
- ad = (uint8_t *)(*bh)->b_data + *offset;
- *offset += ad_size;
-
- if (!ad)
- {
- udf_release_data(*bh);
- *error = 1;
- return NULL;
- }
-
- if (*offset == dir->i_sb->s_blocksize)
- {
- udf_release_data(*bh);
- block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
- if (!block)
- return NULL;
- if (!(*bh = udf_tread(dir->i_sb, block)))
- return NULL;
- }
- else if (*offset > dir->i_sb->s_blocksize)
- {
- ad = tmpad;
-
- remainder = dir->i_sb->s_blocksize - loffset;
- memcpy((uint8_t *)ad, (*bh)->b_data + loffset, remainder);
-
- udf_release_data(*bh);
- block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
- if (!block)
- return NULL;
- if (!((*bh) = udf_tread(dir->i_sb, block)))
- return NULL;
-
- memcpy((uint8_t *)ad + remainder, (*bh)->b_data, ad_size - remainder);
- *offset = ad_size - remainder;
- }
- return ad;
-}
-#endif
-
-struct fileIdentDesc *
-udf_fileident_read(struct inode *dir, loff_t *nf_pos,
- struct udf_fileident_bh *fibh,
- struct fileIdentDesc *cfi,
- kernel_lb_addr *bloc, uint32_t *extoffset,
- kernel_lb_addr *eloc, uint32_t *elen,
- uint32_t *offset, struct buffer_head **bh)
+struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos,
+ struct udf_fileident_bh *fibh,
+ struct fileIdentDesc *cfi,
+ struct extent_position *epos,
+ struct kernel_lb_addr *eloc, uint32_t *elen,
+ sector_t *offset)
{
struct fileIdentDesc *fi;
int i, num, block;
- struct buffer_head * tmp, * bha[16];
+ struct buffer_head *tmp, *bha[16];
+ struct udf_inode_info *iinfo = UDF_I(dir);
fibh->soffset = fibh->eoffset;
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
- {
- fi = udf_get_fileident(UDF_I_DATA(dir) -
- (UDF_I_EFE(dir) ?
- sizeof(struct extendedFileEntry) :
- sizeof(struct fileEntry)),
- dir->i_sb->s_blocksize, &(fibh->eoffset));
-
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+ fi = udf_get_fileident(iinfo->i_ext.i_data -
+ (iinfo->i_efe ?
+ sizeof(struct extendedFileEntry) :
+ sizeof(struct fileEntry)),
+ dir->i_sb->s_blocksize,
+ &(fibh->eoffset));
if (!fi)
return NULL;
- *nf_pos += ((fibh->eoffset - fibh->soffset) >> 2);
+ *nf_pos += fibh->eoffset - fibh->soffset;
- memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc));
+ memcpy((uint8_t *)cfi, (uint8_t *)fi,
+ sizeof(struct fileIdentDesc));
return fi;
}
- if (fibh->eoffset == dir->i_sb->s_blocksize)
- {
- int lextoffset = *extoffset;
+ if (fibh->eoffset == dir->i_sb->s_blocksize) {
+ int lextoffset = epos->offset;
+ unsigned char blocksize_bits = dir->i_sb->s_blocksize_bits;
- if (udf_next_aext(dir, bloc, extoffset, eloc, elen, bh, 1) !=
- (EXT_RECORDED_ALLOCATED >> 30))
- {
+ if (udf_next_aext(dir, epos, eloc, elen, 1) !=
+ (EXT_RECORDED_ALLOCATED >> 30))
return NULL;
- }
- block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset);
+ block = udf_get_lb_pblock(dir->i_sb, eloc, *offset);
- (*offset) ++;
+ (*offset)++;
- if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen)
+ if ((*offset << blocksize_bits) >= *elen)
*offset = 0;
else
- *extoffset = lextoffset;
+ epos->offset = lextoffset;
- udf_release_data(fibh->sbh);
- if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
+ brelse(fibh->sbh);
+ fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
+ if (!fibh->sbh)
return NULL;
fibh->soffset = fibh->eoffset = 0;
- if (!(*offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9))-1)))
- {
- i = 16 >> (dir->i_sb->s_blocksize_bits - 9);
- if (i+*offset > (*elen >> dir->i_sb->s_blocksize_bits))
- i = (*elen >> dir->i_sb->s_blocksize_bits)-*offset;
- for (num=0; i>0; i--)
- {
- block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset+i);
+ if (!(*offset & ((16 >> (blocksize_bits - 9)) - 1))) {
+ i = 16 >> (blocksize_bits - 9);
+ if (i + *offset > (*elen >> blocksize_bits))
+ i = (*elen >> blocksize_bits)-*offset;
+ for (num = 0; i > 0; i--) {
+ block = udf_get_lb_pblock(dir->i_sb, eloc,
+ *offset + i);
tmp = udf_tgetblk(dir->i_sb, block);
- if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
+ if (tmp && !buffer_uptodate(tmp) &&
+ !buffer_locked(tmp))
bha[num++] = tmp;
else
brelse(tmp);
}
- if (num)
- {
+ if (num) {
ll_rw_block(READA, num, bha);
- for (i=0; i<num; i++)
+ for (i = 0; i < num; i++)
brelse(bha[i]);
}
}
- }
- else if (fibh->sbh != fibh->ebh)
- {
- udf_release_data(fibh->sbh);
+ } else if (fibh->sbh != fibh->ebh) {
+ brelse(fibh->sbh);
fibh->sbh = fibh->ebh;
}
fi = udf_get_fileident(fibh->sbh->b_data, dir->i_sb->s_blocksize,
- &(fibh->eoffset));
+ &(fibh->eoffset));
if (!fi)
return NULL;
- *nf_pos += ((fibh->eoffset - fibh->soffset) >> 2);
+ *nf_pos += fibh->eoffset - fibh->soffset;
- if (fibh->eoffset <= dir->i_sb->s_blocksize)
- {
- memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc));
- }
- else if (fibh->eoffset > dir->i_sb->s_blocksize)
- {
- int lextoffset = *extoffset;
+ if (fibh->eoffset <= dir->i_sb->s_blocksize) {
+ memcpy((uint8_t *)cfi, (uint8_t *)fi,
+ sizeof(struct fileIdentDesc));
+ } else if (fibh->eoffset > dir->i_sb->s_blocksize) {
+ int lextoffset = epos->offset;
- if (udf_next_aext(dir, bloc, extoffset, eloc, elen, bh, 1) !=
- (EXT_RECORDED_ALLOCATED >> 30))
- {
+ if (udf_next_aext(dir, epos, eloc, elen, 1) !=
+ (EXT_RECORDED_ALLOCATED >> 30))
return NULL;
- }
- block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset);
+ block = udf_get_lb_pblock(dir->i_sb, eloc, *offset);
- (*offset) ++;
+ (*offset)++;
if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen)
*offset = 0;
else
- *extoffset = lextoffset;
+ epos->offset = lextoffset;
fibh->soffset -= dir->i_sb->s_blocksize;
fibh->eoffset -= dir->i_sb->s_blocksize;
- if (!(fibh->ebh = udf_tread(dir->i_sb, block)))
+ fibh->ebh = udf_tread(dir->i_sb, block);
+ if (!fibh->ebh)
return NULL;
- if (sizeof(struct fileIdentDesc) > - fibh->soffset)
- {
+ if (sizeof(struct fileIdentDesc) > -fibh->soffset) {
int fi_len;
- memcpy((uint8_t *)cfi, (uint8_t *)fi, - fibh->soffset);
- memcpy((uint8_t *)cfi - fibh->soffset, fibh->ebh->b_data,
- sizeof(struct fileIdentDesc) + fibh->soffset);
+ memcpy((uint8_t *)cfi, (uint8_t *)fi, -fibh->soffset);
+ memcpy((uint8_t *)cfi - fibh->soffset,
+ fibh->ebh->b_data,
+ sizeof(struct fileIdentDesc) + fibh->soffset);
- fi_len = (sizeof(struct fileIdentDesc) + cfi->lengthFileIdent +
- le16_to_cpu(cfi->lengthOfImpUse) + 3) & ~3;
+ fi_len = (sizeof(struct fileIdentDesc) +
+ cfi->lengthFileIdent +
+ le16_to_cpu(cfi->lengthOfImpUse) + 3) & ~3;
- *nf_pos += ((fi_len - (fibh->eoffset - fibh->soffset)) >> 2);
+ *nf_pos += fi_len - (fibh->eoffset - fibh->soffset);
fibh->eoffset = fibh->soffset + fi_len;
- }
- else
- {
- memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc));
+ } else {
+ memcpy((uint8_t *)cfi, (uint8_t *)fi,
+ sizeof(struct fileIdentDesc));
}
}
return fi;
}
-struct fileIdentDesc *
-udf_get_fileident(void * buffer, int bufsize, int * offset)
+struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize, int *offset)
{
struct fileIdentDesc *fi;
int lengthThisIdent;
- uint8_t * ptr;
+ uint8_t *ptr;
int padlen;
- if ( (!buffer) || (!offset) ) {
- udf_debug("invalidparms\n, buffer=%p, offset=%p\n", buffer, offset);
+ if ((!buffer) || (!offset)) {
+ udf_debug("invalidparms, buffer=%p, offset=%p\n",
+ buffer, offset);
return NULL;
}
ptr = buffer;
- if ( (*offset > 0) && (*offset < bufsize) ) {
+ if ((*offset > 0) && (*offset < bufsize))
ptr += *offset;
- }
- fi=(struct fileIdentDesc *)ptr;
- if (le16_to_cpu(fi->descTag.tagIdent) != TAG_IDENT_FID)
- {
+ fi = (struct fileIdentDesc *)ptr;
+ if (fi->descTag.tagIdent != cpu_to_le16(TAG_IDENT_FID)) {
udf_debug("0x%x != TAG_IDENT_FID\n",
- le16_to_cpu(fi->descTag.tagIdent));
+ le16_to_cpu(fi->descTag.tagIdent));
udf_debug("offset: %u sizeof: %lu bufsize: %u\n",
- *offset, (unsigned long)sizeof(struct fileIdentDesc), bufsize);
+ *offset, (unsigned long)sizeof(struct fileIdentDesc),
+ bufsize);
return NULL;
}
- if ( (*offset + sizeof(struct fileIdentDesc)) > bufsize )
- {
+ if ((*offset + sizeof(struct fileIdentDesc)) > bufsize)
lengthThisIdent = sizeof(struct fileIdentDesc);
- }
else
lengthThisIdent = sizeof(struct fileIdentDesc) +
fi->lengthFileIdent + le16_to_cpu(fi->lengthOfImpUse);
@@ -263,81 +195,47 @@ udf_get_fileident(void * buffer, int bufsize, int * offset)
return fi;
}
-#if 0
-static extent_ad *
-udf_get_fileextent(void * buffer, int bufsize, int * offset)
+struct short_ad *udf_get_fileshortad(uint8_t *ptr, int maxoffset, uint32_t *offset,
+ int inc)
{
- extent_ad * ext;
- struct fileEntry *fe;
- uint8_t * ptr;
-
- if ( (!buffer) || (!offset) )
- {
- printk(KERN_ERR "udf: udf_get_fileextent() invalidparms\n");
- return NULL;
- }
-
- fe = (struct fileEntry *)buffer;
+ struct short_ad *sa;
- if ( le16_to_cpu(fe->descTag.tagIdent) != TAG_IDENT_FE )
- {
- udf_debug("0x%x != TAG_IDENT_FE\n",
- le16_to_cpu(fe->descTag.tagIdent));
+ if ((!ptr) || (!offset)) {
+ pr_err("%s: invalidparms\n", __func__);
return NULL;
}
- ptr=(uint8_t *)(fe->extendedAttr) + le32_to_cpu(fe->lengthExtendedAttr);
-
- if ( (*offset > 0) && (*offset < le32_to_cpu(fe->lengthAllocDescs)) )
- {
- ptr += *offset;
- }
-
- ext = (extent_ad *)ptr;
-
- *offset = *offset + sizeof(extent_ad);
- return ext;
-}
-#endif
-
-short_ad *
-udf_get_fileshortad(uint8_t *ptr, int maxoffset, int *offset, int inc)
-{
- short_ad *sa;
-
- if ( (!ptr) || (!offset) )
- {
- printk(KERN_ERR "udf: udf_get_fileshortad() invalidparms\n");
+ if ((*offset + sizeof(struct short_ad)) > maxoffset)
return NULL;
+ else {
+ sa = (struct short_ad *)ptr;
+ if (sa->extLength == 0)
+ return NULL;
}
- if ( (*offset < 0) || ((*offset + sizeof(short_ad)) > maxoffset) )
- return NULL;
- else if ((sa = (short_ad *)ptr)->extLength == 0)
- return NULL;
-
if (inc)
- *offset += sizeof(short_ad);
+ *offset += sizeof(struct short_ad);
return sa;
}
-long_ad *
-udf_get_filelongad(uint8_t *ptr, int maxoffset, int * offset, int inc)
+struct long_ad *udf_get_filelongad(uint8_t *ptr, int maxoffset, uint32_t *offset, int inc)
{
- long_ad *la;
+ struct long_ad *la;
- if ( (!ptr) || (!offset) )
- {
- printk(KERN_ERR "udf: udf_get_filelongad() invalidparms\n");
+ if ((!ptr) || (!offset)) {
+ pr_err("%s: invalidparms\n", __func__);
return NULL;
}
- if ( (*offset < 0) || ((*offset + sizeof(long_ad)) > maxoffset) )
- return NULL;
- else if ((la = (long_ad *)ptr)->extLength == 0)
+ if ((*offset + sizeof(struct long_ad)) > maxoffset)
return NULL;
+ else {
+ la = (struct long_ad *)ptr;
+ if (la->extLength == 0)
+ return NULL;
+ }
if (inc)
- *offset += sizeof(long_ad);
+ *offset += sizeof(struct long_ad);
return la;
}
diff --git a/fs/udf/ecma_167.h b/fs/udf/ecma_167.h
index f81f2ebbf50..4792b771aa8 100644
--- a/fs/udf/ecma_167.h
+++ b/fs/udf/ecma_167.h
@@ -38,11 +38,10 @@
#define _ECMA_167_H 1
/* Character set specification (ECMA 167r3 1/7.2.1) */
-typedef struct
-{
+struct charspec {
uint8_t charSetType;
uint8_t charSetInfo[63];
-} __attribute__ ((packed)) charspec;
+} __attribute__ ((packed));
/* Character Set Type (ECMA 167r3 1/7.2.1.1) */
#define CHARSPEC_TYPE_CS0 0x00 /* (1/7.2.2) */
@@ -58,8 +57,7 @@ typedef struct
typedef uint8_t dstring;
/* Timestamp (ECMA 167r3 1/7.3) */
-typedef struct
-{
+struct timestamp {
__le16 typeAndTimezone;
__le16 year;
uint8_t month;
@@ -70,21 +68,7 @@ typedef struct
uint8_t centiseconds;
uint8_t hundredsOfMicroseconds;
uint8_t microseconds;
-} __attribute__ ((packed)) timestamp;
-
-typedef struct
-{
- uint16_t typeAndTimezone;
- int16_t year;
- uint8_t month;
- uint8_t day;
- uint8_t hour;
- uint8_t minute;
- uint8_t second;
- uint8_t centiseconds;
- uint8_t hundredsOfMicroseconds;
- uint8_t microseconds;
-} __attribute__ ((packed)) kernel_timestamp;
+} __attribute__ ((packed));
/* Type and Time Zone (ECMA 167r3 1/7.3.1) */
#define TIMESTAMP_TYPE_MASK 0xF000
@@ -94,12 +78,11 @@ typedef struct
#define TIMESTAMP_TIMEZONE_MASK 0x0FFF
/* Entity identifier (ECMA 167r3 1/7.4) */
-typedef struct
-{
+struct regid {
uint8_t flags;
uint8_t ident[23];
uint8_t identSuffix[8];
-} __attribute__ ((packed)) regid;
+} __attribute__ ((packed));
/* Flags (ECMA 167r3 1/7.4.1) */
#define ENTITYID_FLAGS_DIRTY 0x00
@@ -107,8 +90,7 @@ typedef struct
/* Volume Structure Descriptor (ECMA 167r3 2/9.1) */
#define VSD_STD_ID_LEN 5
-struct volStructDesc
-{
+struct volStructDesc {
uint8_t structType;
uint8_t stdIdent[VSD_STD_ID_LEN];
uint8_t structVersion;
@@ -127,8 +109,7 @@ struct volStructDesc
#define VSD_STD_ID_TEA01 "TEA01" /* (2/9.3) */
/* Beginning Extended Area Descriptor (ECMA 167r3 2/9.2) */
-struct beginningExtendedAreaDesc
-{
+struct beginningExtendedAreaDesc {
uint8_t structType;
uint8_t stdIdent[VSD_STD_ID_LEN];
uint8_t structVersion;
@@ -136,8 +117,7 @@ struct beginningExtendedAreaDesc
} __attribute__ ((packed));
/* Terminating Extended Area Descriptor (ECMA 167r3 2/9.3) */
-struct terminatingExtendedAreaDesc
-{
+struct terminatingExtendedAreaDesc {
uint8_t structType;
uint8_t stdIdent[VSD_STD_ID_LEN];
uint8_t structVersion;
@@ -145,43 +125,39 @@ struct terminatingExtendedAreaDesc
} __attribute__ ((packed));
/* Boot Descriptor (ECMA 167r3 2/9.4) */
-struct bootDesc
-{
- uint8_t structType;
- uint8_t stdIdent[VSD_STD_ID_LEN];
- uint8_t structVersion;
- uint8_t reserved1;
- regid archType;
- regid bootIdent;
- __le32 bootExtLocation;
- __le32 bootExtLength;
- __le64 loadAddress;
- __le64 startAddress;
- timestamp descCreationDateAndTime;
- __le16 flags;
- uint8_t reserved2[32];
- uint8_t bootUse[1906];
+struct bootDesc {
+ uint8_t structType;
+ uint8_t stdIdent[VSD_STD_ID_LEN];
+ uint8_t structVersion;
+ uint8_t reserved1;
+ struct regid archType;
+ struct regid bootIdent;
+ __le32 bootExtLocation;
+ __le32 bootExtLength;
+ __le64 loadAddress;
+ __le64 startAddress;
+ struct timestamp descCreationDateAndTime;
+ __le16 flags;
+ uint8_t reserved2[32];
+ uint8_t bootUse[1906];
} __attribute__ ((packed));
/* Flags (ECMA 167r3 2/9.4.12) */
#define BOOT_FLAGS_ERASE 0x01
/* Extent Descriptor (ECMA 167r3 3/7.1) */
-typedef struct
-{
+struct extent_ad {
__le32 extLength;
__le32 extLocation;
-} __attribute__ ((packed)) extent_ad;
+} __attribute__ ((packed));
-typedef struct
-{
+struct kernel_extent_ad {
uint32_t extLength;
uint32_t extLocation;
-} kernel_extent_ad;
+};
/* Descriptor Tag (ECMA 167r3 3/7.2) */
-typedef struct
-{
+struct tag {
__le16 tagIdent;
__le16 descVersion;
uint8_t tagChecksum;
@@ -190,7 +166,7 @@ typedef struct
__le16 descCRC;
__le16 descCRCLength;
__le32 tagLocation;
-} __attribute__ ((packed)) tag;
+} __attribute__ ((packed));
/* Tag Identifier (ECMA 167r3 3/7.2.1) */
#define TAG_IDENT_PVD 0x0001
@@ -204,87 +180,81 @@ typedef struct
#define TAG_IDENT_LVID 0x0009
/* NSR Descriptor (ECMA 167r3 3/9.1) */
-struct NSRDesc
-{
+struct NSRDesc {
uint8_t structType;
uint8_t stdIdent[VSD_STD_ID_LEN];
uint8_t structVersion;
uint8_t reserved;
uint8_t structData[2040];
} __attribute__ ((packed));
-
+
/* Primary Volume Descriptor (ECMA 167r3 3/10.1) */
-struct primaryVolDesc
-{
- tag descTag;
- __le32 volDescSeqNum;
- __le32 primaryVolDescNum;
- dstring volIdent[32];
- __le16 volSeqNum;
- __le16 maxVolSeqNum;
- __le16 interchangeLvl;
- __le16 maxInterchangeLvl;
- __le32 charSetList;
- __le32 maxCharSetList;
- dstring volSetIdent[128];
- charspec descCharSet;
- charspec explanatoryCharSet;
- extent_ad volAbstract;
- extent_ad volCopyright;
- regid appIdent;
- timestamp recordingDateAndTime;
- regid impIdent;
- uint8_t impUse[64];
- __le32 predecessorVolDescSeqLocation;
- __le16 flags;
- uint8_t reserved[22];
+struct primaryVolDesc {
+ struct tag descTag;
+ __le32 volDescSeqNum;
+ __le32 primaryVolDescNum;
+ dstring volIdent[32];
+ __le16 volSeqNum;
+ __le16 maxVolSeqNum;
+ __le16 interchangeLvl;
+ __le16 maxInterchangeLvl;
+ __le32 charSetList;
+ __le32 maxCharSetList;
+ dstring volSetIdent[128];
+ struct charspec descCharSet;
+ struct charspec explanatoryCharSet;
+ struct extent_ad volAbstract;
+ struct extent_ad volCopyright;
+ struct regid appIdent;
+ struct timestamp recordingDateAndTime;
+ struct regid impIdent;
+ uint8_t impUse[64];
+ __le32 predecessorVolDescSeqLocation;
+ __le16 flags;
+ uint8_t reserved[22];
} __attribute__ ((packed));
/* Flags (ECMA 167r3 3/10.1.21) */
#define PVD_FLAGS_VSID_COMMON 0x0001
/* Anchor Volume Descriptor Pointer (ECMA 167r3 3/10.2) */
-struct anchorVolDescPtr
-{
- tag descTag;
- extent_ad mainVolDescSeqExt;
- extent_ad reserveVolDescSeqExt;
- uint8_t reserved[480];
+struct anchorVolDescPtr {
+ struct tag descTag;
+ struct extent_ad mainVolDescSeqExt;
+ struct extent_ad reserveVolDescSeqExt;
+ uint8_t reserved[480];
} __attribute__ ((packed));
/* Volume Descriptor Pointer (ECMA 167r3 3/10.3) */
-struct volDescPtr
-{
- tag descTag;
- __le32 volDescSeqNum;
- extent_ad nextVolDescSeqExt;
- uint8_t reserved[484];
+struct volDescPtr {
+ struct tag descTag;
+ __le32 volDescSeqNum;
+ struct extent_ad nextVolDescSeqExt;
+ uint8_t reserved[484];
} __attribute__ ((packed));
/* Implementation Use Volume Descriptor (ECMA 167r3 3/10.4) */
-struct impUseVolDesc
-{
- tag descTag;
+struct impUseVolDesc {
+ struct tag descTag;
__le32 volDescSeqNum;
- regid impIdent;
+ struct regid impIdent;
uint8_t impUse[460];
} __attribute__ ((packed));
/* Partition Descriptor (ECMA 167r3 3/10.5) */
-struct partitionDesc
-{
- tag descTag;
- __le32 volDescSeqNum;
- __le16 partitionFlags;
- __le16 partitionNumber;
- regid partitionContents;
- uint8_t partitionContentsUse[128];
- __le32 accessType;
- __le32 partitionStartingLocation;
- __le32 partitionLength;
- regid impIdent;
- uint8_t impUse[128];
- uint8_t reserved[156];
+struct partitionDesc {
+ struct tag descTag;
+ __le32 volDescSeqNum;
+ __le16 partitionFlags;
+ __le16 partitionNumber;
+ struct regid partitionContents;
+ uint8_t partitionContentsUse[128];
+ __le32 accessType;
+ __le32 partitionStartingLocation;
+ __le32 partitionLength;
+ struct regid impIdent;
+ uint8_t impUse[128];
+ uint8_t reserved[156];
} __attribute__ ((packed));
/* Partition Flags (ECMA 167r3 3/10.5.3) */
@@ -307,26 +277,24 @@ struct partitionDesc
#define PD_ACCESS_TYPE_OVERWRITABLE 0x00000004
/* Logical Volume Descriptor (ECMA 167r3 3/10.6) */
-struct logicalVolDesc
-{
- tag descTag;
- __le32 volDescSeqNum;
- charspec descCharSet;
- dstring logicalVolIdent[128];
- __le32 logicalBlockSize;
- regid domainIdent;
- uint8_t logicalVolContentsUse[16];
- __le32 mapTableLength;
- __le32 numPartitionMaps;
- regid impIdent;
- uint8_t impUse[128];
- extent_ad integritySeqExt;
- uint8_t partitionMaps[0];
+struct logicalVolDesc {
+ struct tag descTag;
+ __le32 volDescSeqNum;
+ struct charspec descCharSet;
+ dstring logicalVolIdent[128];
+ __le32 logicalBlockSize;
+ struct regid domainIdent;
+ uint8_t logicalVolContentsUse[16];
+ __le32 mapTableLength;
+ __le32 numPartitionMaps;
+ struct regid impIdent;
+ uint8_t impUse[128];
+ struct extent_ad integritySeqExt;
+ uint8_t partitionMaps[0];
} __attribute__ ((packed));
/* Generic Partition Map (ECMA 167r3 3/10.7.1) */
-struct genericPartitionMap
-{
+struct genericPartitionMap {
uint8_t partitionMapType;
uint8_t partitionMapLength;
uint8_t partitionMapping[0];
@@ -338,8 +306,7 @@ struct genericPartitionMap
#define GP_PARTITION_MAP_TYPE_2 0x02
/* Type 1 Partition Map (ECMA 167r3 3/10.7.2) */
-struct genericPartitionMap1
-{
+struct genericPartitionMap1 {
uint8_t partitionMapType;
uint8_t partitionMapLength;
__le16 volSeqNum;
@@ -347,42 +314,38 @@ struct genericPartitionMap1
} __attribute__ ((packed));
/* Type 2 Partition Map (ECMA 167r3 3/10.7.3) */
-struct genericPartitionMap2
-{
+struct genericPartitionMap2 {
uint8_t partitionMapType;
- uint8_t partitionMapLength;
+ uint8_t partitionMapLength;
uint8_t partitionIdent[62];
} __attribute__ ((packed));
/* Unallocated Space Descriptor (ECMA 167r3 3/10.8) */
-struct unallocSpaceDesc
-{
- tag descTag;
- __le32 volDescSeqNum;
- __le32 numAllocDescs;
- extent_ad allocDescs[0];
+struct unallocSpaceDesc {
+ struct tag descTag;
+ __le32 volDescSeqNum;
+ __le32 numAllocDescs;
+ struct extent_ad allocDescs[0];
} __attribute__ ((packed));
/* Terminating Descriptor (ECMA 167r3 3/10.9) */
-struct terminatingDesc
-{
- tag descTag;
+struct terminatingDesc {
+ struct tag descTag;
uint8_t reserved[496];
} __attribute__ ((packed));
/* Logical Volume Integrity Descriptor (ECMA 167r3 3/10.10) */
-struct logicalVolIntegrityDesc
-{
- tag descTag;
- timestamp recordingDateAndTime;
- __le32 integrityType;
- extent_ad nextIntegrityExt;
- uint8_t logicalVolContentsUse[32];
- __le32 numOfPartitions;
- __le32 lengthOfImpUse;
- __le32 freeSpaceTable[0];
- __le32 sizeTable[0];
- uint8_t impUse[0];
+struct logicalVolIntegrityDesc {
+ struct tag descTag;
+ struct timestamp recordingDateAndTime;
+ __le32 integrityType;
+ struct extent_ad nextIntegrityExt;
+ uint8_t logicalVolContentsUse[32];
+ __le32 numOfPartitions;
+ __le32 lengthOfImpUse;
+ __le32 freeSpaceTable[0];
+ __le32 sizeTable[0];
+ uint8_t impUse[0];
} __attribute__ ((packed));
/* Integrity Type (ECMA 167r3 3/10.10.3) */
@@ -390,57 +353,50 @@ struct logicalVolIntegrityDesc
#define LVID_INTEGRITY_TYPE_CLOSE 0x00000001
/* Recorded Address (ECMA 167r3 4/7.1) */
-typedef struct
-{
+struct lb_addr {
__le32 logicalBlockNum;
__le16 partitionReferenceNum;
-} __attribute__ ((packed)) lb_addr;
+} __attribute__ ((packed));
/* ... and its in-core analog */
-typedef struct
-{
+struct kernel_lb_addr {
uint32_t logicalBlockNum;
uint16_t partitionReferenceNum;
-} kernel_lb_addr;
+};
/* Short Allocation Descriptor (ECMA 167r3 4/14.14.1) */
-typedef struct
-{
+struct short_ad {
__le32 extLength;
__le32 extPosition;
-} __attribute__ ((packed)) short_ad;
+} __attribute__ ((packed));
/* Long Allocation Descriptor (ECMA 167r3 4/14.14.2) */
-typedef struct
-{
+struct long_ad {
__le32 extLength;
- lb_addr extLocation;
+ struct lb_addr extLocation;
uint8_t impUse[6];
-} __attribute__ ((packed)) long_ad;
+} __attribute__ ((packed));
-typedef struct
-{
- uint32_t extLength;
- kernel_lb_addr extLocation;
- uint8_t impUse[6];
-} kernel_long_ad;
+struct kernel_long_ad {
+ uint32_t extLength;
+ struct kernel_lb_addr extLocation;
+ uint8_t impUse[6];
+};
/* Extended Allocation Descriptor (ECMA 167r3 4/14.14.3) */
-typedef struct
-{
+struct ext_ad {
__le32 extLength;
__le32 recordedLength;
__le32 informationLength;
- lb_addr extLocation;
-} __attribute__ ((packed)) ext_ad;
+ struct lb_addr extLocation;
+} __attribute__ ((packed));
-typedef struct
-{
- uint32_t extLength;
- uint32_t recordedLength;
- uint32_t informationLength;
- kernel_lb_addr extLocation;
-} kernel_ext_ad;
+struct kernel_ext_ad {
+ uint32_t extLength;
+ uint32_t recordedLength;
+ uint32_t informationLength;
+ struct kernel_lb_addr extLocation;
+};
/* Descriptor Tag (ECMA 167r3 4/7.2 - See 3/7.2) */
@@ -458,48 +414,45 @@ typedef struct
#define TAG_IDENT_EFE 0x010A
/* File Set Descriptor (ECMA 167r3 4/14.1) */
-struct fileSetDesc
-{
- tag descTag;
- timestamp recordingDateAndTime;
- __le16 interchangeLvl;
- __le16 maxInterchangeLvl;
- __le32 charSetList;
- __le32 maxCharSetList;
- __le32 fileSetNum;
- __le32 fileSetDescNum;
- charspec logicalVolIdentCharSet;
- dstring logicalVolIdent[128];
- charspec fileSetCharSet;
- dstring fileSetIdent[32];
- dstring copyrightFileIdent[32];
- dstring abstractFileIdent[32];
- long_ad rootDirectoryICB;
- regid domainIdent;
- long_ad nextExt;
- long_ad streamDirectoryICB;
- uint8_t reserved[32];
+struct fileSetDesc {
+ struct tag descTag;
+ struct timestamp recordingDateAndTime;
+ __le16 interchangeLvl;
+ __le16 maxInterchangeLvl;
+ __le32 charSetList;
+ __le32 maxCharSetList;
+ __le32 fileSetNum;
+ __le32 fileSetDescNum;
+ struct charspec logicalVolIdentCharSet;
+ dstring logicalVolIdent[128];
+ struct charspec fileSetCharSet;
+ dstring fileSetIdent[32];
+ dstring copyrightFileIdent[32];
+ dstring abstractFileIdent[32];
+ struct long_ad rootDirectoryICB;
+ struct regid domainIdent;
+ struct long_ad nextExt;
+ struct long_ad streamDirectoryICB;
+ uint8_t reserved[32];
} __attribute__ ((packed));
/* Partition Header Descriptor (ECMA 167r3 4/14.3) */
-struct partitionHeaderDesc
-{
- short_ad unallocSpaceTable;
- short_ad unallocSpaceBitmap;
- short_ad partitionIntegrityTable;
- short_ad freedSpaceTable;
- short_ad freedSpaceBitmap;
+struct partitionHeaderDesc {
+ struct short_ad unallocSpaceTable;
+ struct short_ad unallocSpaceBitmap;
+ struct short_ad partitionIntegrityTable;
+ struct short_ad freedSpaceTable;
+ struct short_ad freedSpaceBitmap;
uint8_t reserved[88];
} __attribute__ ((packed));
/* File Identifier Descriptor (ECMA 167r3 4/14.4) */
-struct fileIdentDesc
-{
- tag descTag;
+struct fileIdentDesc {
+ struct tag descTag;
__le16 fileVersionNum;
uint8_t fileCharacteristics;
uint8_t lengthFileIdent;
- long_ad icb;
+ struct long_ad icb;
__le16 lengthOfImpUse;
uint8_t impUse[0];
uint8_t fileIdent[0];
@@ -514,25 +467,23 @@ struct fileIdentDesc
#define FID_FILE_CHAR_METADATA 0x10
/* Allocation Ext Descriptor (ECMA 167r3 4/14.5) */
-struct allocExtDesc
-{
- tag descTag;
+struct allocExtDesc {
+ struct tag descTag;
__le32 previousAllocExtLocation;
__le32 lengthAllocDescs;
} __attribute__ ((packed));
/* ICB Tag (ECMA 167r3 4/14.6) */
-typedef struct
-{
+struct icbtag {
__le32 priorRecordedNumDirectEntries;
__le16 strategyType;
__le16 strategyParameter;
__le16 numEntries;
uint8_t reserved;
uint8_t fileType;
- lb_addr parentICBLocation;
+ struct lb_addr parentICBLocation;
__le16 flags;
-} __attribute__ ((packed)) icbtag;
+} __attribute__ ((packed));
/* Strategy Type (ECMA 167r3 4/14.6.2) */
#define ICBTAG_STRATEGY_TYPE_UNDEF 0x0000
@@ -576,45 +527,42 @@ typedef struct
#define ICBTAG_FLAG_STREAM 0x2000
/* Indirect Entry (ECMA 167r3 4/14.7) */
-struct indirectEntry
-{
- tag descTag;
- icbtag icbTag;
- long_ad indirectICB;
+struct indirectEntry {
+ struct tag descTag;
+ struct icbtag icbTag;
+ struct long_ad indirectICB;
} __attribute__ ((packed));
/* Terminal Entry (ECMA 167r3 4/14.8) */
-struct terminalEntry
-{
- tag descTag;
- icbtag icbTag;
+struct terminalEntry {
+ struct tag descTag;
+ struct icbtag icbTag;
} __attribute__ ((packed));
/* File Entry (ECMA 167r3 4/14.9) */
-struct fileEntry
-{
- tag descTag;
- icbtag icbTag;
- __le32 uid;
- __le32 gid;
- __le32 permissions;
- __le16 fileLinkCount;
- uint8_t recordFormat;
- uint8_t recordDisplayAttr;
- __le32 recordLength;
- __le64 informationLength;
- __le64 logicalBlocksRecorded;
- timestamp accessTime;
- timestamp modificationTime;
- timestamp attrTime;
- __le32 checkpoint;
- long_ad extendedAttrICB;
- regid impIdent;
- __le64 uniqueID;
- __le32 lengthExtendedAttr;
- __le32 lengthAllocDescs;
- uint8_t extendedAttr[0];
- uint8_t allocDescs[0];
+struct fileEntry {
+ struct tag descTag;
+ struct icbtag icbTag;
+ __le32 uid;
+ __le32 gid;
+ __le32 permissions;
+ __le16 fileLinkCount;
+ uint8_t recordFormat;
+ uint8_t recordDisplayAttr;
+ __le32 recordLength;
+ __le64 informationLength;
+ __le64 logicalBlocksRecorded;
+ struct timestamp accessTime;
+ struct timestamp modificationTime;
+ struct timestamp attrTime;
+ __le32 checkpoint;
+ struct long_ad extendedAttrICB;
+ struct regid impIdent;
+ __le64 uniqueID;
+ __le32 lengthExtendedAttr;
+ __le32 lengthAllocDescs;
+ uint8_t extendedAttr[0];
+ uint8_t allocDescs[0];
} __attribute__ ((packed));
/* Permissions (ECMA 167r3 4/14.9.5) */
@@ -655,16 +603,14 @@ struct fileEntry
#define FE_RECORD_DISPLAY_ATTR_3 0x03
/* Extended Attribute Header Descriptor (ECMA 167r3 4/14.10.1) */
-struct extendedAttrHeaderDesc
-{
- tag descTag;
+struct extendedAttrHeaderDesc {
+ struct tag descTag;
__le32 impAttrLocation;
__le32 appAttrLocation;
} __attribute__ ((packed));
/* Generic Format (ECMA 167r3 4/14.10.2) */
-struct genericFormat
-{
+struct genericFormat {
__le32 attrType;
uint8_t attrSubtype;
uint8_t reserved[3];
@@ -673,8 +619,7 @@ struct genericFormat
} __attribute__ ((packed));
/* Character Set Information (ECMA 167r3 4/14.10.3) */
-struct charSetInfo
-{
+struct charSetInfo {
__le32 attrType;
uint8_t attrSubtype;
uint8_t reserved[3];
@@ -685,8 +630,7 @@ struct charSetInfo
} __attribute__ ((packed));
/* Alternate Permissions (ECMA 167r3 4/14.10.4) */
-struct altPerms
-{
+struct altPerms {
__le32 attrType;
uint8_t attrSubtype;
uint8_t reserved[3];
@@ -697,8 +641,7 @@ struct altPerms
} __attribute__ ((packed));
/* File Times Extended Attribute (ECMA 167r3 4/14.10.5) */
-struct fileTimesExtAttr
-{
+struct fileTimesExtAttr {
__le32 attrType;
uint8_t attrSubtype;
uint8_t reserved[3];
@@ -715,8 +658,7 @@ struct fileTimesExtAttr
#define FTE_BACKUP 0x00000002
/* Information Times Extended Attribute (ECMA 167r3 4/14.10.6) */
-struct infoTimesExtAttr
-{
+struct infoTimesExtAttr {
__le32 attrType;
uint8_t attrSubtype;
uint8_t reserved[3];
@@ -727,8 +669,7 @@ struct infoTimesExtAttr
} __attribute__ ((packed));
/* Device Specification (ECMA 167r3 4/14.10.7) */
-struct deviceSpec
-{
+struct deviceSpec {
__le32 attrType;
uint8_t attrSubtype;
uint8_t reserved[3];
@@ -740,26 +681,24 @@ struct deviceSpec
} __attribute__ ((packed));
/* Implementation Use Extended Attr (ECMA 167r3 4/14.10.8) */
-struct impUseExtAttr
-{
+struct impUseExtAttr {
__le32 attrType;
uint8_t attrSubtype;
uint8_t reserved[3];
__le32 attrLength;
__le32 impUseLength;
- regid impIdent;
+ struct regid impIdent;
uint8_t impUse[0];
} __attribute__ ((packed));
/* Application Use Extended Attribute (ECMA 167r3 4/14.10.9) */
-struct appUseExtAttr
-{
+struct appUseExtAttr {
__le32 attrType;
uint8_t attrSubtype;
uint8_t reserved[3];
__le32 attrLength;
__le32 appUseLength;
- regid appIdent;
+ struct regid appIdent;
uint8_t appUse[0];
} __attribute__ ((packed));
@@ -771,35 +710,31 @@ struct appUseExtAttr
#define EXTATTR_IMP_USE 2048
#define EXTATTR_APP_USE 65536
-
/* Unallocated Space Entry (ECMA 167r3 4/14.11) */
-struct unallocSpaceEntry
-{
- tag descTag;
- icbtag icbTag;
+struct unallocSpaceEntry {
+ struct tag descTag;
+ struct icbtag icbTag;
__le32 lengthAllocDescs;
uint8_t allocDescs[0];
} __attribute__ ((packed));
/* Space Bitmap Descriptor (ECMA 167r3 4/14.12) */
-struct spaceBitmapDesc
-{
- tag descTag;
+struct spaceBitmapDesc {
+ struct tag descTag;
__le32 numOfBits;
__le32 numOfBytes;
uint8_t bitmap[0];
} __attribute__ ((packed));
/* Partition Integrity Entry (ECMA 167r3 4/14.13) */
-struct partitionIntegrityEntry
-{
- tag descTag;
- icbtag icbTag;
- timestamp recordingDateAndTime;
- uint8_t integrityType;
- uint8_t reserved[175];
- regid impIdent;
- uint8_t impUse[256];
+struct partitionIntegrityEntry {
+ struct tag descTag;
+ struct icbtag icbTag;
+ struct timestamp recordingDateAndTime;
+ uint8_t integrityType;
+ uint8_t reserved[175];
+ struct regid impIdent;
+ uint8_t impUse[256];
} __attribute__ ((packed));
/* Short Allocation Descriptor (ECMA 167r3 4/14.14.1) */
@@ -815,15 +750,13 @@ struct partitionIntegrityEntry
/* Extended Allocation Descriptor (ECMA 167r3 4/14.14.3) */
/* Logical Volume Header Descriptor (ECMA 167r3 4/14.15) */
-struct logicalVolHeaderDesc
-{
+struct logicalVolHeaderDesc {
__le64 uniqueID;
uint8_t reserved[24];
} __attribute__ ((packed));
/* Path Component (ECMA 167r3 4/14.16.1) */
-struct pathComponent
-{
+struct pathComponent {
uint8_t componentType;
uint8_t lengthComponentIdent;
__le16 componentFileVersionNum;
@@ -831,34 +764,33 @@ struct pathComponent
} __attribute__ ((packed));
/* File Entry (ECMA 167r3 4/14.17) */
-struct extendedFileEntry
-{
- tag descTag;
- icbtag icbTag;
- __le32 uid;
- __le32 gid;
- __le32 permissions;
- __le16 fileLinkCount;
- uint8_t recordFormat;
- uint8_t recordDisplayAttr;
- __le32 recordLength;
- __le64 informationLength;
- __le64 objectSize;
- __le64 logicalBlocksRecorded;
- timestamp accessTime;
- timestamp modificationTime;
- timestamp createTime;
- timestamp attrTime;
- __le32 checkpoint;
- __le32 reserved;
- long_ad extendedAttrICB;
- long_ad streamDirectoryICB;
- regid impIdent;
- __le64 uniqueID;
- __le32 lengthExtendedAttr;
- __le32 lengthAllocDescs;
- uint8_t extendedAttr[0];
- uint8_t allocDescs[0];
+struct extendedFileEntry {
+ struct tag descTag;
+ struct icbtag icbTag;
+ __le32 uid;
+ __le32 gid;
+ __le32 permissions;
+ __le16 fileLinkCount;
+ uint8_t recordFormat;
+ uint8_t recordDisplayAttr;
+ __le32 recordLength;
+ __le64 informationLength;
+ __le64 objectSize;
+ __le64 logicalBlocksRecorded;
+ struct timestamp accessTime;
+ struct timestamp modificationTime;
+ struct timestamp createTime;
+ struct timestamp attrTime;
+ __le32 checkpoint;
+ __le32 reserved;
+ struct long_ad extendedAttrICB;
+ struct long_ad streamDirectoryICB;
+ struct regid impIdent;
+ __le64 uniqueID;
+ __le32 lengthExtendedAttr;
+ __le32 lengthAllocDescs;
+ uint8_t extendedAttr[0];
+ uint8_t allocDescs[0];
} __attribute__ ((packed));
#endif /* _ECMA_167_H */
diff --git a/fs/udf/file.c b/fs/udf/file.c
index bb40d63f328..d80738fdf42 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -4,11 +4,6 @@
* PURPOSE
* File handling routines for the OSTA-UDF(tm) filesystem.
*
- * CONTACTS
- * E-mail regarding any portion of the Linux UDF file system should be
- * directed to the development team mailing list (run by majordomo):
- * linux_udf@hpesjro.fc.hp.com
- *
* COPYRIGHT
* This file is distributed under the terms of the GNU General Public
* License (GPL). Copies of the GPL can be obtained from:
@@ -32,237 +27,264 @@
#include "udfdecl.h"
#include <linux/fs.h>
-#include <linux/udf_fs.h>
#include <asm/uaccess.h>
#include <linux/kernel.h>
#include <linux/string.h> /* memset */
+#include <linux/capability.h>
#include <linux/errno.h>
-#include <linux/smp_lock.h>
#include <linux/pagemap.h>
#include <linux/buffer_head.h>
+#include <linux/aio.h>
#include "udf_i.h"
#include "udf_sb.h"
-static int udf_adinicb_readpage(struct file *file, struct page * page)
+static void __udf_adinicb_readpage(struct page *page)
{
struct inode *inode = page->mapping->host;
char *kaddr;
-
- BUG_ON(!PageLocked(page));
+ struct udf_inode_info *iinfo = UDF_I(inode);
kaddr = kmap(page);
- memset(kaddr, 0, PAGE_CACHE_SIZE);
- memcpy(kaddr, UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), inode->i_size);
+ memcpy(kaddr, iinfo->i_ext.i_data + iinfo->i_lenEAttr, inode->i_size);
+ memset(kaddr + inode->i_size, 0, PAGE_CACHE_SIZE - inode->i_size);
flush_dcache_page(page);
SetPageUptodate(page);
kunmap(page);
+}
+
+static int udf_adinicb_readpage(struct file *file, struct page *page)
+{
+ BUG_ON(!PageLocked(page));
+ __udf_adinicb_readpage(page);
unlock_page(page);
+
return 0;
}
-static int udf_adinicb_writepage(struct page *page, struct writeback_control *wbc)
+static int udf_adinicb_writepage(struct page *page,
+ struct writeback_control *wbc)
{
struct inode *inode = page->mapping->host;
char *kaddr;
+ struct udf_inode_info *iinfo = UDF_I(inode);
BUG_ON(!PageLocked(page));
kaddr = kmap(page);
- memcpy(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), kaddr, inode->i_size);
+ memcpy(iinfo->i_ext.i_data + iinfo->i_lenEAttr, kaddr, inode->i_size);
mark_inode_dirty(inode);
SetPageUptodate(page);
kunmap(page);
unlock_page(page);
+
return 0;
}
-static int udf_adinicb_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
+static int udf_adinicb_write_begin(struct file *file,
+ struct address_space *mapping, loff_t pos,
+ unsigned len, unsigned flags, struct page **pagep,
+ void **fsdata)
{
- kmap(page);
+ struct page *page;
+
+ if (WARN_ON_ONCE(pos >= PAGE_CACHE_SIZE))
+ return -EIO;
+ page = grab_cache_page_write_begin(mapping, 0, flags);
+ if (!page)
+ return -ENOMEM;
+ *pagep = page;
+
+ if (!PageUptodate(page) && len != PAGE_CACHE_SIZE)
+ __udf_adinicb_readpage(page);
return 0;
}
-static int udf_adinicb_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
+static int udf_adinicb_write_end(struct file *file,
+ struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned copied,
+ struct page *page, void *fsdata)
{
- struct inode *inode = page->mapping->host;
- char *kaddr = page_address(page);
+ struct inode *inode = mapping->host;
+ unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
+ char *kaddr;
+ struct udf_inode_info *iinfo = UDF_I(inode);
- memcpy(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode) + offset,
- kaddr + offset, to - offset);
- mark_inode_dirty(inode);
- SetPageUptodate(page);
- kunmap(page);
- /* only one page here */
- if (to > inode->i_size)
- inode->i_size = to;
+ kaddr = kmap_atomic(page);
+ memcpy(iinfo->i_ext.i_data + iinfo->i_lenEAttr + offset,
+ kaddr + offset, copied);
+ kunmap_atomic(kaddr);
+
+ return simple_write_end(file, mapping, pos, len, copied, page, fsdata);
+}
+
+static ssize_t udf_adinicb_direct_IO(int rw, struct kiocb *iocb,
+ struct iov_iter *iter,
+ loff_t offset)
+{
+ /* Fallback to buffered I/O. */
return 0;
}
-struct address_space_operations udf_adinicb_aops = {
- .readpage = udf_adinicb_readpage,
- .writepage = udf_adinicb_writepage,
- .sync_page = block_sync_page,
- .prepare_write = udf_adinicb_prepare_write,
- .commit_write = udf_adinicb_commit_write,
+const struct address_space_operations udf_adinicb_aops = {
+ .readpage = udf_adinicb_readpage,
+ .writepage = udf_adinicb_writepage,
+ .write_begin = udf_adinicb_write_begin,
+ .write_end = udf_adinicb_write_end,
+ .direct_IO = udf_adinicb_direct_IO,
};
-static ssize_t udf_file_write(struct file * file, const char __user * buf,
- size_t count, loff_t *ppos)
+static ssize_t udf_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
ssize_t retval;
- struct inode *inode = file->f_dentry->d_inode;
+ struct file *file = iocb->ki_filp;
+ struct inode *inode = file_inode(file);
int err, pos;
+ size_t count = iocb->ki_nbytes;
+ struct udf_inode_info *iinfo = UDF_I(inode);
- if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
- {
+ mutex_lock(&inode->i_mutex);
+ down_write(&iinfo->i_data_sem);
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
if (file->f_flags & O_APPEND)
pos = inode->i_size;
else
- pos = *ppos;
-
- if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) +
- pos + count))
- {
- udf_expand_file_adinicb(inode, pos + count, &err);
- if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
- {
+ pos = iocb->ki_pos;
+
+ if (inode->i_sb->s_blocksize <
+ (udf_file_entry_alloc_offset(inode) +
+ pos + count)) {
+ err = udf_expand_file_adinicb(inode);
+ if (err) {
+ mutex_unlock(&inode->i_mutex);
udf_debug("udf_expand_adinicb: err=%d\n", err);
return err;
}
- }
- else
- {
+ } else {
if (pos + count > inode->i_size)
- UDF_I_LENALLOC(inode) = pos + count;
+ iinfo->i_lenAlloc = pos + count;
else
- UDF_I_LENALLOC(inode) = inode->i_size;
+ iinfo->i_lenAlloc = inode->i_size;
+ up_write(&iinfo->i_data_sem);
}
- }
+ } else
+ up_write(&iinfo->i_data_sem);
- retval = generic_file_write(file, buf, count, ppos);
+ retval = __generic_file_write_iter(iocb, from);
+ mutex_unlock(&inode->i_mutex);
+
+ if (retval > 0) {
+ ssize_t err;
- if (retval > 0)
mark_inode_dirty(inode);
+ err = generic_write_sync(file, iocb->ki_pos - retval, retval);
+ if (err < 0)
+ retval = err;
+ }
+
return retval;
}
-/*
- * udf_ioctl
- *
- * PURPOSE
- * Issue an ioctl.
- *
- * DESCRIPTION
- * Optional - sys_ioctl() will return -ENOTTY if this routine is not
- * available, and the ioctl cannot be handled without filesystem help.
- *
- * sys_ioctl() handles these ioctls that apply only to regular files:
- * FIBMAP [requires udf_block_map()], FIGETBSZ, FIONREAD
- * These ioctls are also handled by sys_ioctl():
- * FIOCLEX, FIONCLEX, FIONBIO, FIOASYNC
- * All other ioctls are passed to the filesystem.
- *
- * Refer to sys_ioctl() in fs/ioctl.c
- * sys_ioctl() -> .
- *
- * PRE-CONDITIONS
- * inode Pointer to inode that ioctl was issued on.
- * filp Pointer to file that ioctl was issued on.
- * cmd The ioctl command.
- * arg The ioctl argument [can be interpreted as a
- * user-space pointer if desired].
- *
- * POST-CONDITIONS
- * <return> Success (>=0) or an error code (<=0) that
- * sys_ioctl() will return.
- *
- * HISTORY
- * July 1, 1997 - Andrew E. Mileski
- * Written, tested, and released.
- */
-int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
+ struct inode *inode = file_inode(filp);
+ long old_block, new_block;
int result = -EINVAL;
- if ( permission(inode, MAY_READ, NULL) != 0 )
- {
- udf_debug("no permission to access inode %lu\n",
- inode->i_ino);
- return -EPERM;
+ if (inode_permission(inode, MAY_READ) != 0) {
+ udf_debug("no permission to access inode %lu\n", inode->i_ino);
+ result = -EPERM;
+ goto out;
}
- if ( !arg )
- {
+ if (!arg) {
udf_debug("invalid argument to udf_ioctl\n");
- return -EINVAL;
+ result = -EINVAL;
+ goto out;
}
- switch (cmd)
- {
- case UDF_GETVOLIDENT:
- return copy_to_user((char __user *)arg,
- UDF_SB_VOLIDENT(inode->i_sb), 32) ? -EFAULT : 0;
- case UDF_RELOCATE_BLOCKS:
- {
- long old, new;
-
- if (!capable(CAP_SYS_ADMIN)) return -EACCES;
- if (get_user(old, (long __user *)arg)) return -EFAULT;
- if ((result = udf_relocate_blocks(inode->i_sb,
- old, &new)) == 0)
- result = put_user(new, (long __user *)arg);
-
- return result;
+ switch (cmd) {
+ case UDF_GETVOLIDENT:
+ if (copy_to_user((char __user *)arg,
+ UDF_SB(inode->i_sb)->s_volume_ident, 32))
+ result = -EFAULT;
+ else
+ result = 0;
+ goto out;
+ case UDF_RELOCATE_BLOCKS:
+ if (!capable(CAP_SYS_ADMIN)) {
+ result = -EPERM;
+ goto out;
+ }
+ if (get_user(old_block, (long __user *)arg)) {
+ result = -EFAULT;
+ goto out;
}
- case UDF_GETEASIZE:
- result = put_user(UDF_I_LENEATTR(inode), (int __user *)arg);
- break;
-
- case UDF_GETEABLOCK:
- result = copy_to_user((char __user *)arg, UDF_I_DATA(inode),
- UDF_I_LENEATTR(inode)) ? -EFAULT : 0;
- break;
+ result = udf_relocate_blocks(inode->i_sb,
+ old_block, &new_block);
+ if (result == 0)
+ result = put_user(new_block, (long __user *)arg);
+ goto out;
+ case UDF_GETEASIZE:
+ result = put_user(UDF_I(inode)->i_lenEAttr, (int __user *)arg);
+ goto out;
+ case UDF_GETEABLOCK:
+ result = copy_to_user((char __user *)arg,
+ UDF_I(inode)->i_ext.i_data,
+ UDF_I(inode)->i_lenEAttr) ? -EFAULT : 0;
+ goto out;
}
+out:
return result;
}
-/*
- * udf_release_file
- *
- * PURPOSE
- * Called when all references to the file are closed
- *
- * DESCRIPTION
- * Discard prealloced blocks
- *
- * HISTORY
- *
- */
-static int udf_release_file(struct inode * inode, struct file * filp)
+static int udf_release_file(struct inode *inode, struct file *filp)
{
- if (filp->f_mode & FMODE_WRITE)
- {
- lock_kernel();
+ if (filp->f_mode & FMODE_WRITE) {
+ down_write(&UDF_I(inode)->i_data_sem);
udf_discard_prealloc(inode);
- unlock_kernel();
+ udf_truncate_tail_extent(inode);
+ up_write(&UDF_I(inode)->i_data_sem);
}
return 0;
}
-struct file_operations udf_file_operations = {
- .read = generic_file_read,
- .ioctl = udf_ioctl,
+const struct file_operations udf_file_operations = {
+ .read = new_sync_read,
+ .read_iter = generic_file_read_iter,
+ .unlocked_ioctl = udf_ioctl,
.open = generic_file_open,
.mmap = generic_file_mmap,
- .write = udf_file_write,
+ .write = new_sync_write,
+ .write_iter = udf_file_write_iter,
.release = udf_release_file,
- .fsync = udf_fsync_file,
- .sendfile = generic_file_sendfile,
+ .fsync = generic_file_fsync,
+ .splice_read = generic_file_splice_read,
+ .llseek = generic_file_llseek,
};
-struct inode_operations udf_file_inode_operations = {
- .truncate = udf_truncate,
+static int udf_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ struct inode *inode = dentry->d_inode;
+ int error;
+
+ error = inode_change_ok(inode, attr);
+ if (error)
+ return error;
+
+ if ((attr->ia_valid & ATTR_SIZE) &&
+ attr->ia_size != i_size_read(inode)) {
+ error = udf_setsize(inode, attr->ia_size);
+ if (error)
+ return error;
+ }
+
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+ return 0;
+}
+
+const struct inode_operations udf_file_inode_operations = {
+ .setattr = udf_setattr,
};
diff --git a/fs/udf/fsync.c b/fs/udf/fsync.c
deleted file mode 100644
index 2dde6b888c2..00000000000
--- a/fs/udf/fsync.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * fsync.c
- *
- * PURPOSE
- * Fsync handling routines for the OSTA-UDF(tm) filesystem.
- *
- * CONTACTS
- * E-mail regarding any portion of the Linux UDF file system should be
- * directed to the development team mailing list (run by majordomo):
- * linux_udf@hpesjro.fc.hp.com
- *
- * COPYRIGHT
- * This file is distributed under the terms of the GNU General Public
- * License (GPL). Copies of the GPL can be obtained from:
- * ftp://prep.ai.mit.edu/pub/gnu/GPL
- * Each contributing author retains all rights to their own work.
- *
- * (C) 1999-2001 Ben Fennema
- * (C) 1999-2000 Stelias Computing Inc
- *
- * HISTORY
- *
- * 05/22/99 blf Created.
- */
-
-#include "udfdecl.h"
-
-#include <linux/fs.h>
-#include <linux/smp_lock.h>
-
-static int udf_fsync_inode(struct inode *, int);
-
-/*
- * File may be NULL when we are called. Perhaps we shouldn't
- * even pass file to fsync ?
- */
-
-int udf_fsync_file(struct file * file, struct dentry *dentry, int datasync)
-{
- struct inode *inode = dentry->d_inode;
- return udf_fsync_inode(inode, datasync);
-}
-
-static int udf_fsync_inode(struct inode *inode, int datasync)
-{
- int err;
-
- err = sync_mapping_buffers(inode->i_mapping);
- if (!(inode->i_state & I_DIRTY))
- return err;
- if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
- return err;
-
- err |= udf_sync_inode (inode);
- return err ? -EIO : 0;
-}
diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c
index a7e5d40f1eb..6eaf5edf1ea 100644
--- a/fs/udf/ialloc.c
+++ b/fs/udf/ialloc.c
@@ -4,11 +4,6 @@
* PURPOSE
* Inode allocation handling routines for the OSTA-UDF(tm) filesystem.
*
- * CONTACTS
- * E-mail regarding any portion of the Linux UDF file system should be
- * directed to the development team mailing list (run by majordomo):
- * linux_udf@hpesjro.fc.hp.com
- *
* COPYRIGHT
* This file is distributed under the terms of the GNU General Public
* License (GPL). Copies of the GPL can be obtained from:
@@ -25,145 +20,111 @@
#include "udfdecl.h"
#include <linux/fs.h>
-#include <linux/quotaops.h>
-#include <linux/udf_fs.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include "udf_i.h"
#include "udf_sb.h"
-void udf_free_inode(struct inode * inode)
+void udf_free_inode(struct inode *inode)
{
struct super_block *sb = inode->i_sb;
struct udf_sb_info *sbi = UDF_SB(sb);
+ struct logicalVolIntegrityDescImpUse *lvidiu = udf_sb_lvidiu(sb);
- /*
- * Note: we must free any quota before locking the superblock,
- * as writing the quota to disk may need the lock as well.
- */
- DQUOT_FREE_INODE(inode);
- DQUOT_DROP(inode);
-
- clear_inode(inode);
-
- down(&sbi->s_alloc_sem);
- if (sbi->s_lvidbh) {
+ if (lvidiu) {
+ mutex_lock(&sbi->s_alloc_mutex);
if (S_ISDIR(inode->i_mode))
- UDF_SB_LVIDIU(sb)->numDirs =
- cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs) - 1);
+ le32_add_cpu(&lvidiu->numDirs, -1);
else
- UDF_SB_LVIDIU(sb)->numFiles =
- cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) - 1);
-
- mark_buffer_dirty(sbi->s_lvidbh);
+ le32_add_cpu(&lvidiu->numFiles, -1);
+ udf_updated_lvid(sb);
+ mutex_unlock(&sbi->s_alloc_mutex);
}
- up(&sbi->s_alloc_sem);
- udf_free_blocks(sb, NULL, UDF_I_LOCATION(inode), 0, 1);
+ udf_free_blocks(sb, NULL, &UDF_I(inode)->i_location, 0, 1);
}
-struct inode * udf_new_inode (struct inode *dir, int mode, int * err)
+struct inode *udf_new_inode(struct inode *dir, umode_t mode, int *err)
{
struct super_block *sb = dir->i_sb;
struct udf_sb_info *sbi = UDF_SB(sb);
- struct inode * inode;
+ struct inode *inode;
int block;
- uint32_t start = UDF_I_LOCATION(dir).logicalBlockNum;
+ uint32_t start = UDF_I(dir)->i_location.logicalBlockNum;
+ struct udf_inode_info *iinfo;
+ struct udf_inode_info *dinfo = UDF_I(dir);
+ struct logicalVolIntegrityDescImpUse *lvidiu;
inode = new_inode(sb);
- if (!inode)
- {
+ if (!inode) {
*err = -ENOMEM;
return NULL;
}
*err = -ENOSPC;
- block = udf_new_block(dir->i_sb, NULL, UDF_I_LOCATION(dir).partitionReferenceNum,
- start, err);
- if (*err)
- {
+ iinfo = UDF_I(inode);
+ if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_EXTENDED_FE)) {
+ iinfo->i_efe = 1;
+ if (UDF_VERS_USE_EXTENDED_FE > sbi->s_udfrev)
+ sbi->s_udfrev = UDF_VERS_USE_EXTENDED_FE;
+ iinfo->i_ext.i_data = kzalloc(inode->i_sb->s_blocksize -
+ sizeof(struct extendedFileEntry),
+ GFP_KERNEL);
+ } else {
+ iinfo->i_efe = 0;
+ iinfo->i_ext.i_data = kzalloc(inode->i_sb->s_blocksize -
+ sizeof(struct fileEntry),
+ GFP_KERNEL);
+ }
+ if (!iinfo->i_ext.i_data) {
iput(inode);
+ *err = -ENOMEM;
return NULL;
}
- down(&sbi->s_alloc_sem);
- UDF_I_UNIQUE(inode) = 0;
- UDF_I_LENEXTENTS(inode) = 0;
- UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
- UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
- UDF_I_STRAT4096(inode) = 0;
- if (UDF_SB_LVIDBH(sb))
- {
- struct logicalVolHeaderDesc *lvhd;
- uint64_t uniqueID;
- lvhd = (struct logicalVolHeaderDesc *)(UDF_SB_LVID(sb)->logicalVolContentsUse);
- if (S_ISDIR(mode))
- UDF_SB_LVIDIU(sb)->numDirs =
- cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs) + 1);
- else
- UDF_SB_LVIDIU(sb)->numFiles =
- cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) + 1);
- UDF_I_UNIQUE(inode) = uniqueID = le64_to_cpu(lvhd->uniqueID);
- if (!(++uniqueID & 0x00000000FFFFFFFFUL))
- uniqueID += 16;
- lvhd->uniqueID = cpu_to_le64(uniqueID);
- mark_buffer_dirty(UDF_SB_LVIDBH(sb));
+ block = udf_new_block(dir->i_sb, NULL,
+ dinfo->i_location.partitionReferenceNum,
+ start, err);
+ if (*err) {
+ iput(inode);
+ return NULL;
}
- inode->i_mode = mode;
- inode->i_uid = current->fsuid;
- if (dir->i_mode & S_ISGID)
- {
- inode->i_gid = dir->i_gid;
+
+ lvidiu = udf_sb_lvidiu(sb);
+ if (lvidiu) {
+ iinfo->i_unique = lvid_get_unique_id(sb);
+ mutex_lock(&sbi->s_alloc_mutex);
if (S_ISDIR(mode))
- mode |= S_ISGID;
+ le32_add_cpu(&lvidiu->numDirs, 1);
+ else
+ le32_add_cpu(&lvidiu->numFiles, 1);
+ udf_updated_lvid(sb);
+ mutex_unlock(&sbi->s_alloc_mutex);
}
- else
- inode->i_gid = current->fsgid;
- UDF_I_LOCATION(inode).logicalBlockNum = block;
- UDF_I_LOCATION(inode).partitionReferenceNum = UDF_I_LOCATION(dir).partitionReferenceNum;
- inode->i_ino = udf_get_lb_pblock(sb, UDF_I_LOCATION(inode), 0);
- inode->i_blksize = PAGE_SIZE;
+ inode_init_owner(inode, dir, mode);
+
+ iinfo->i_location.logicalBlockNum = block;
+ iinfo->i_location.partitionReferenceNum =
+ dinfo->i_location.partitionReferenceNum;
+ inode->i_ino = udf_get_lb_pblock(sb, &iinfo->i_location, 0);
inode->i_blocks = 0;
- UDF_I_LENEATTR(inode) = 0;
- UDF_I_LENALLOC(inode) = 0;
- UDF_I_USE(inode) = 0;
- if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_EXTENDED_FE))
- {
- UDF_I_EFE(inode) = 1;
- UDF_UPDATE_UDFREV(inode->i_sb, UDF_VERS_USE_EXTENDED_FE);
- UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry), GFP_KERNEL);
- memset(UDF_I_DATA(inode), 0x00, inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry));
- }
- else
- {
- UDF_I_EFE(inode) = 0;
- UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct fileEntry), GFP_KERNEL);
- memset(UDF_I_DATA(inode), 0x00, inode->i_sb->s_blocksize - sizeof(struct fileEntry));
- }
+ iinfo->i_lenEAttr = 0;
+ iinfo->i_lenAlloc = 0;
+ iinfo->i_use = 0;
+ iinfo->i_checkpoint = 1;
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_AD_IN_ICB))
- UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB;
+ iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB;
else if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
- UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_SHORT;
+ iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT;
else
- UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_LONG;
+ iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG;
inode->i_mtime = inode->i_atime = inode->i_ctime =
- UDF_I_CRTIME(inode) = current_fs_time(inode->i_sb);
+ iinfo->i_crtime = current_fs_time(inode->i_sb);
insert_inode_hash(inode);
mark_inode_dirty(inode);
- up(&sbi->s_alloc_sem);
-
- if (DQUOT_ALLOC_INODE(inode))
- {
- DQUOT_DROP(inode);
- inode->i_flags |= S_NOQUOTA;
- inode->i_nlink = 0;
- iput(inode);
- *err = -EDQUOT;
- return NULL;
- }
*err = 0;
return inode;
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index b83890beaaa..236cd48184c 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -4,11 +4,6 @@
* PURPOSE
* Inode handling routines for the OSTA-UDF(tm) filesystem.
*
- * CONTACTS
- * E-mail regarding any portion of the Linux UDF file system should be
- * directed to the development team mailing list (run by majordomo):
- * linux_udf@hpesjro.fc.hp.com
- *
* COPYRIGHT
* This file is distributed under the terms of the GNU General Public
* License (GPL). Copies of the GPL can be obtained from:
@@ -24,7 +19,8 @@
* 10/04/98 dgb Added rudimentary directory functions
* 10/07/98 Fully working udf_block_map! It works!
* 11/25/98 bmap altered to better support extents
- * 12/06/98 blf partition support in udf_iget, udf_block_map and udf_read_inode
+ * 12/06/98 blf partition support in udf_iget, udf_block_map
+ * and udf_read_inode
* 12/12/98 rewrote udf_block_map to handle next extents and descs across
* block boundaries (which is not actually allowed)
* 12/20/98 added support for strategy 4096
@@ -35,12 +31,14 @@
#include "udfdecl.h"
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/module.h>
#include <linux/pagemap.h>
#include <linux/buffer_head.h>
#include <linux/writeback.h>
#include <linux/slab.h>
+#include <linux/crc-itu-t.h>
+#include <linux/mpage.h>
+#include <linux/aio.h>
#include "udf_i.h"
#include "udf_sb.h"
@@ -51,70 +49,137 @@ MODULE_LICENSE("GPL");
#define EXTENT_MERGE_SIZE 5
-static mode_t udf_convert_permissions(struct fileEntry *);
+static umode_t udf_convert_permissions(struct fileEntry *);
static int udf_update_inode(struct inode *, int);
static void udf_fill_inode(struct inode *, struct buffer_head *);
-static struct buffer_head *inode_getblk(struct inode *, long, int *,
- long *, int *);
-static int8_t udf_insert_aext(struct inode *, kernel_lb_addr, int,
- kernel_lb_addr, uint32_t, struct buffer_head *);
+static int udf_sync_inode(struct inode *inode);
+static int udf_alloc_i_data(struct inode *inode, size_t size);
+static sector_t inode_getblk(struct inode *, sector_t, int *, int *);
+static int8_t udf_insert_aext(struct inode *, struct extent_position,
+ struct kernel_lb_addr, uint32_t);
static void udf_split_extents(struct inode *, int *, int, int,
- kernel_long_ad [EXTENT_MERGE_SIZE], int *);
+ struct kernel_long_ad[EXTENT_MERGE_SIZE], int *);
static void udf_prealloc_extents(struct inode *, int, int,
- kernel_long_ad [EXTENT_MERGE_SIZE], int *);
+ struct kernel_long_ad[EXTENT_MERGE_SIZE], int *);
static void udf_merge_extents(struct inode *,
- kernel_long_ad [EXTENT_MERGE_SIZE], int *);
+ struct kernel_long_ad[EXTENT_MERGE_SIZE], int *);
static void udf_update_extents(struct inode *,
- kernel_long_ad [EXTENT_MERGE_SIZE], int, int,
- kernel_lb_addr, uint32_t, struct buffer_head **);
+ struct kernel_long_ad[EXTENT_MERGE_SIZE], int, int,
+ struct extent_position *);
static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int);
-/*
- * udf_delete_inode
- *
- * PURPOSE
- * Clean-up before the specified inode is destroyed.
- *
- * DESCRIPTION
- * This routine is called when the kernel destroys an inode structure
- * ie. when iput() finds i_count == 0.
- *
- * HISTORY
- * July 1, 1997 - Andrew E. Mileski
- * Written, tested, and released.
- *
- * Called at the last iput() if i_nlink is zero.
- */
-void udf_delete_inode(struct inode * inode)
+static void __udf_clear_extent_cache(struct inode *inode)
{
- truncate_inode_pages(&inode->i_data, 0);
+ struct udf_inode_info *iinfo = UDF_I(inode);
- if (is_bad_inode(inode))
- goto no_delete;
+ if (iinfo->cached_extent.lstart != -1) {
+ brelse(iinfo->cached_extent.epos.bh);
+ iinfo->cached_extent.lstart = -1;
+ }
+}
- inode->i_size = 0;
- udf_truncate(inode);
- lock_kernel();
+/* Invalidate extent cache */
+static void udf_clear_extent_cache(struct inode *inode)
+{
+ struct udf_inode_info *iinfo = UDF_I(inode);
- udf_update_inode(inode, IS_SYNC(inode));
- udf_free_inode(inode);
+ spin_lock(&iinfo->i_extent_cache_lock);
+ __udf_clear_extent_cache(inode);
+ spin_unlock(&iinfo->i_extent_cache_lock);
+}
- unlock_kernel();
- return;
-no_delete:
- clear_inode(inode);
+/* Return contents of extent cache */
+static int udf_read_extent_cache(struct inode *inode, loff_t bcount,
+ loff_t *lbcount, struct extent_position *pos)
+{
+ struct udf_inode_info *iinfo = UDF_I(inode);
+ int ret = 0;
+
+ spin_lock(&iinfo->i_extent_cache_lock);
+ if ((iinfo->cached_extent.lstart <= bcount) &&
+ (iinfo->cached_extent.lstart != -1)) {
+ /* Cache hit */
+ *lbcount = iinfo->cached_extent.lstart;
+ memcpy(pos, &iinfo->cached_extent.epos,
+ sizeof(struct extent_position));
+ if (pos->bh)
+ get_bh(pos->bh);
+ ret = 1;
+ }
+ spin_unlock(&iinfo->i_extent_cache_lock);
+ return ret;
}
-void udf_clear_inode(struct inode *inode)
+/* Add extent to extent cache */
+static void udf_update_extent_cache(struct inode *inode, loff_t estart,
+ struct extent_position *pos, int next_epos)
{
- if (!(inode->i_sb->s_flags & MS_RDONLY)) {
- lock_kernel();
- udf_discard_prealloc(inode);
- unlock_kernel();
+ struct udf_inode_info *iinfo = UDF_I(inode);
+
+ spin_lock(&iinfo->i_extent_cache_lock);
+ /* Invalidate previously cached extent */
+ __udf_clear_extent_cache(inode);
+ if (pos->bh)
+ get_bh(pos->bh);
+ memcpy(&iinfo->cached_extent.epos, pos,
+ sizeof(struct extent_position));
+ iinfo->cached_extent.lstart = estart;
+ if (next_epos)
+ switch (iinfo->i_alloc_type) {
+ case ICBTAG_FLAG_AD_SHORT:
+ iinfo->cached_extent.epos.offset -=
+ sizeof(struct short_ad);
+ break;
+ case ICBTAG_FLAG_AD_LONG:
+ iinfo->cached_extent.epos.offset -=
+ sizeof(struct long_ad);
+ }
+ spin_unlock(&iinfo->i_extent_cache_lock);
+}
+
+void udf_evict_inode(struct inode *inode)
+{
+ struct udf_inode_info *iinfo = UDF_I(inode);
+ int want_delete = 0;
+
+ if (!inode->i_nlink && !is_bad_inode(inode)) {
+ want_delete = 1;
+ udf_setsize(inode, 0);
+ udf_update_inode(inode, IS_SYNC(inode));
+ }
+ truncate_inode_pages_final(&inode->i_data);
+ invalidate_inode_buffers(inode);
+ clear_inode(inode);
+ if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB &&
+ inode->i_size != iinfo->i_lenExtents) {
+ udf_warn(inode->i_sb, "Inode %lu (mode %o) has inode size %llu different from extent length %llu. Filesystem need not be standards compliant.\n",
+ inode->i_ino, inode->i_mode,
+ (unsigned long long)inode->i_size,
+ (unsigned long long)iinfo->i_lenExtents);
+ }
+ kfree(iinfo->i_ext.i_data);
+ iinfo->i_ext.i_data = NULL;
+ udf_clear_extent_cache(inode);
+ if (want_delete) {
+ udf_free_inode(inode);
}
+}
- kfree(UDF_I_DATA(inode));
- UDF_I_DATA(inode) = NULL;
+static void udf_write_failed(struct address_space *mapping, loff_t to)
+{
+ struct inode *inode = mapping->host;
+ struct udf_inode_info *iinfo = UDF_I(inode);
+ loff_t isize = inode->i_size;
+
+ if (to > isize) {
+ truncate_pagecache(inode, isize);
+ if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+ down_write(&iinfo->i_data_sem);
+ udf_clear_extent_cache(inode);
+ udf_truncate_extents(inode);
+ up_write(&iinfo->i_data_sem);
+ }
+ }
}
static int udf_writepage(struct page *page, struct writeback_control *wbc)
@@ -122,114 +187,182 @@ static int udf_writepage(struct page *page, struct writeback_control *wbc)
return block_write_full_page(page, udf_get_block, wbc);
}
+static int udf_writepages(struct address_space *mapping,
+ struct writeback_control *wbc)
+{
+ return mpage_writepages(mapping, wbc, udf_get_block);
+}
+
static int udf_readpage(struct file *file, struct page *page)
{
- return block_read_full_page(page, udf_get_block);
+ return mpage_readpage(page, udf_get_block);
}
-static int udf_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
+static int udf_readpages(struct file *file, struct address_space *mapping,
+ struct list_head *pages, unsigned nr_pages)
{
- return block_prepare_write(page, from, to, udf_get_block);
+ return mpage_readpages(mapping, pages, nr_pages, udf_get_block);
+}
+
+static int udf_write_begin(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned flags,
+ struct page **pagep, void **fsdata)
+{
+ int ret;
+
+ ret = block_write_begin(mapping, pos, len, flags, pagep, udf_get_block);
+ if (unlikely(ret))
+ udf_write_failed(mapping, pos + len);
+ return ret;
+}
+
+static ssize_t udf_direct_IO(int rw, struct kiocb *iocb,
+ struct iov_iter *iter,
+ loff_t offset)
+{
+ struct file *file = iocb->ki_filp;
+ struct address_space *mapping = file->f_mapping;
+ struct inode *inode = mapping->host;
+ size_t count = iov_iter_count(iter);
+ ssize_t ret;
+
+ ret = blockdev_direct_IO(rw, iocb, inode, iter, offset, udf_get_block);
+ if (unlikely(ret < 0 && (rw & WRITE)))
+ udf_write_failed(mapping, offset + count);
+ return ret;
}
static sector_t udf_bmap(struct address_space *mapping, sector_t block)
{
- return generic_block_bmap(mapping,block,udf_get_block);
+ return generic_block_bmap(mapping, block, udf_get_block);
}
-struct address_space_operations udf_aops = {
- .readpage = udf_readpage,
- .writepage = udf_writepage,
- .sync_page = block_sync_page,
- .prepare_write = udf_prepare_write,
- .commit_write = generic_commit_write,
- .bmap = udf_bmap,
+const struct address_space_operations udf_aops = {
+ .readpage = udf_readpage,
+ .readpages = udf_readpages,
+ .writepage = udf_writepage,
+ .writepages = udf_writepages,
+ .write_begin = udf_write_begin,
+ .write_end = generic_write_end,
+ .direct_IO = udf_direct_IO,
+ .bmap = udf_bmap,
};
-void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err)
+/*
+ * Expand file stored in ICB to a normal one-block-file
+ *
+ * This function requires i_data_sem for writing and releases it.
+ * This function requires i_mutex held
+ */
+int udf_expand_file_adinicb(struct inode *inode)
{
struct page *page;
char *kaddr;
+ struct udf_inode_info *iinfo = UDF_I(inode);
+ int err;
struct writeback_control udf_wbc = {
.sync_mode = WB_SYNC_NONE,
.nr_to_write = 1,
};
- /* from now on we have normal address_space methods */
- inode->i_data.a_ops = &udf_aops;
-
- if (!UDF_I_LENALLOC(inode))
- {
+ WARN_ON_ONCE(!mutex_is_locked(&inode->i_mutex));
+ if (!iinfo->i_lenAlloc) {
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
- UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_SHORT;
+ iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT;
else
- UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_LONG;
+ iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG;
+ /* from now on we have normal address_space methods */
+ inode->i_data.a_ops = &udf_aops;
+ up_write(&iinfo->i_data_sem);
mark_inode_dirty(inode);
- return;
+ return 0;
}
+ /*
+ * Release i_data_sem so that we can lock a page - page lock ranks
+ * above i_data_sem. i_mutex still protects us against file changes.
+ */
+ up_write(&iinfo->i_data_sem);
- page = grab_cache_page(inode->i_mapping, 0);
- BUG_ON(!PageLocked(page));
+ page = find_or_create_page(inode->i_mapping, 0, GFP_NOFS);
+ if (!page)
+ return -ENOMEM;
- if (!PageUptodate(page))
- {
+ if (!PageUptodate(page)) {
kaddr = kmap(page);
- memset(kaddr + UDF_I_LENALLOC(inode), 0x00,
- PAGE_CACHE_SIZE - UDF_I_LENALLOC(inode));
- memcpy(kaddr, UDF_I_DATA(inode) + UDF_I_LENEATTR(inode),
- UDF_I_LENALLOC(inode));
+ memset(kaddr + iinfo->i_lenAlloc, 0x00,
+ PAGE_CACHE_SIZE - iinfo->i_lenAlloc);
+ memcpy(kaddr, iinfo->i_ext.i_data + iinfo->i_lenEAttr,
+ iinfo->i_lenAlloc);
flush_dcache_page(page);
SetPageUptodate(page);
kunmap(page);
}
- memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), 0x00,
- UDF_I_LENALLOC(inode));
- UDF_I_LENALLOC(inode) = 0;
+ down_write(&iinfo->i_data_sem);
+ memset(iinfo->i_ext.i_data + iinfo->i_lenEAttr, 0x00,
+ iinfo->i_lenAlloc);
+ iinfo->i_lenAlloc = 0;
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
- UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_SHORT;
+ iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT;
else
- UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_LONG;
-
- inode->i_data.a_ops->writepage(page, &udf_wbc);
+ iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG;
+ /* from now on we have normal address_space methods */
+ inode->i_data.a_ops = &udf_aops;
+ up_write(&iinfo->i_data_sem);
+ err = inode->i_data.a_ops->writepage(page, &udf_wbc);
+ if (err) {
+ /* Restore everything back so that we don't lose data... */
+ lock_page(page);
+ kaddr = kmap(page);
+ down_write(&iinfo->i_data_sem);
+ memcpy(iinfo->i_ext.i_data + iinfo->i_lenEAttr, kaddr,
+ inode->i_size);
+ kunmap(page);
+ unlock_page(page);
+ iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB;
+ inode->i_data.a_ops = &udf_adinicb_aops;
+ up_write(&iinfo->i_data_sem);
+ }
page_cache_release(page);
-
mark_inode_dirty(inode);
+
+ return err;
}
-struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int *err)
+struct buffer_head *udf_expand_dir_adinicb(struct inode *inode, int *block,
+ int *err)
{
int newblock;
- struct buffer_head *sbh = NULL, *dbh = NULL;
- kernel_lb_addr bloc, eloc;
- uint32_t elen, extoffset;
+ struct buffer_head *dbh = NULL;
+ struct kernel_lb_addr eloc;
uint8_t alloctype;
+ struct extent_position epos;
struct udf_fileident_bh sfibh, dfibh;
- loff_t f_pos = udf_ext0_offset(inode) >> 2;
- int size = (udf_ext0_offset(inode) + inode->i_size) >> 2;
+ loff_t f_pos = udf_ext0_offset(inode);
+ int size = udf_ext0_offset(inode) + inode->i_size;
struct fileIdentDesc cfi, *sfi, *dfi;
+ struct udf_inode_info *iinfo = UDF_I(inode);
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
alloctype = ICBTAG_FLAG_AD_SHORT;
else
alloctype = ICBTAG_FLAG_AD_LONG;
- if (!inode->i_size)
- {
- UDF_I_ALLOCTYPE(inode) = alloctype;
+ if (!inode->i_size) {
+ iinfo->i_alloc_type = alloctype;
mark_inode_dirty(inode);
return NULL;
}
/* alloc block, and copy data to it */
*block = udf_new_block(inode->i_sb, inode,
- UDF_I_LOCATION(inode).partitionReferenceNum,
- UDF_I_LOCATION(inode).logicalBlockNum, err);
-
+ iinfo->i_location.partitionReferenceNum,
+ iinfo->i_location.logicalBlockNum, err);
if (!(*block))
return NULL;
newblock = udf_get_pblock(inode->i_sb, *block,
- UDF_I_LOCATION(inode).partitionReferenceNum, 0);
+ iinfo->i_location.partitionReferenceNum,
+ 0);
if (!newblock)
return NULL;
dbh = udf_tgetblk(inode->i_sb, newblock);
@@ -241,58 +374,60 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int
unlock_buffer(dbh);
mark_buffer_dirty_inode(dbh, inode);
- sfibh.soffset = sfibh.eoffset = (f_pos & ((inode->i_sb->s_blocksize - 1) >> 2)) << 2;
- sbh = sfibh.sbh = sfibh.ebh = NULL;
+ sfibh.soffset = sfibh.eoffset =
+ f_pos & (inode->i_sb->s_blocksize - 1);
+ sfibh.sbh = sfibh.ebh = NULL;
dfibh.soffset = dfibh.eoffset = 0;
dfibh.sbh = dfibh.ebh = dbh;
- while ( (f_pos < size) )
- {
- UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB;
- sfi = udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL, NULL, NULL, NULL, NULL, NULL);
- if (!sfi)
- {
- udf_release_data(dbh);
+ while (f_pos < size) {
+ iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB;
+ sfi = udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL,
+ NULL, NULL, NULL);
+ if (!sfi) {
+ brelse(dbh);
return NULL;
}
- UDF_I_ALLOCTYPE(inode) = alloctype;
+ iinfo->i_alloc_type = alloctype;
sfi->descTag.tagLocation = cpu_to_le32(*block);
dfibh.soffset = dfibh.eoffset;
dfibh.eoffset += (sfibh.eoffset - sfibh.soffset);
dfi = (struct fileIdentDesc *)(dbh->b_data + dfibh.soffset);
if (udf_write_fi(inode, sfi, dfi, &dfibh, sfi->impUse,
- sfi->fileIdent + le16_to_cpu(sfi->lengthOfImpUse)))
- {
- UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB;
- udf_release_data(dbh);
+ sfi->fileIdent +
+ le16_to_cpu(sfi->lengthOfImpUse))) {
+ iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB;
+ brelse(dbh);
return NULL;
}
}
mark_buffer_dirty_inode(dbh, inode);
- memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), 0, UDF_I_LENALLOC(inode));
- UDF_I_LENALLOC(inode) = 0;
- bloc = UDF_I_LOCATION(inode);
+ memset(iinfo->i_ext.i_data + iinfo->i_lenEAttr, 0,
+ iinfo->i_lenAlloc);
+ iinfo->i_lenAlloc = 0;
eloc.logicalBlockNum = *block;
- eloc.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
- elen = inode->i_size;
- UDF_I_LENEXTENTS(inode) = elen;
- extoffset = udf_file_entry_alloc_offset(inode);
- udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &sbh, 0);
+ eloc.partitionReferenceNum =
+ iinfo->i_location.partitionReferenceNum;
+ iinfo->i_lenExtents = inode->i_size;
+ epos.bh = NULL;
+ epos.block = iinfo->i_location;
+ epos.offset = udf_file_entry_alloc_offset(inode);
+ udf_add_aext(inode, &epos, &eloc, inode->i_size, 0);
/* UniqueID stuff */
- udf_release_data(sbh);
+ brelse(epos.bh);
mark_inode_dirty(inode);
return dbh;
}
-static int udf_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_result, int create)
+static int udf_get_block(struct inode *inode, sector_t block,
+ struct buffer_head *bh_result, int create)
{
int err, new;
- struct buffer_head *bh;
- unsigned long phys;
+ sector_t phys = 0;
+ struct udf_inode_info *iinfo;
- if (!create)
- {
+ if (!create) {
phys = udf_block_map(inode, block);
if (phys)
map_bh(bh_result, inode->i_sb, phys);
@@ -301,55 +436,40 @@ static int udf_get_block(struct inode *inode, sector_t block, struct buffer_head
err = -EIO;
new = 0;
- bh = NULL;
+ iinfo = UDF_I(inode);
- lock_kernel();
-
- if (block < 0)
- goto abort_negative;
-
- if (block == UDF_I_NEXT_ALLOC_BLOCK(inode) + 1)
- {
- UDF_I_NEXT_ALLOC_BLOCK(inode) ++;
- UDF_I_NEXT_ALLOC_GOAL(inode) ++;
+ down_write(&iinfo->i_data_sem);
+ if (block == iinfo->i_next_alloc_block + 1) {
+ iinfo->i_next_alloc_block++;
+ iinfo->i_next_alloc_goal++;
}
- err = 0;
-
- bh = inode_getblk(inode, block, &err, &phys, &new);
- if (bh)
- BUG();
- if (err)
- goto abort;
+ udf_clear_extent_cache(inode);
+ phys = inode_getblk(inode, block, &err, &new);
if (!phys)
- BUG();
+ goto abort;
if (new)
set_buffer_new(bh_result);
map_bh(bh_result, inode->i_sb, phys);
+
abort:
- unlock_kernel();
+ up_write(&iinfo->i_data_sem);
return err;
-
-abort_negative:
- udf_warning(inode->i_sb, "udf_get_block", "block < 0");
- goto abort;
}
-static struct buffer_head *
-udf_getblk(struct inode *inode, long block, int create, int *err)
+static struct buffer_head *udf_getblk(struct inode *inode, long block,
+ int create, int *err)
{
+ struct buffer_head *bh;
struct buffer_head dummy;
dummy.b_state = 0;
dummy.b_blocknr = -1000;
*err = udf_get_block(inode, block, &dummy, create);
- if (!*err && buffer_mapped(&dummy))
- {
- struct buffer_head *bh;
+ if (!*err && buffer_mapped(&dummy)) {
bh = sb_getblk(inode->i_sb, dummy.b_blocknr);
- if (buffer_new(&dummy))
- {
+ if (buffer_new(&dummy)) {
lock_buffer(bh);
memset(bh->b_data, 0x00, inode->i_sb->s_blocksize);
set_buffer_uptodate(bh);
@@ -358,56 +478,235 @@ udf_getblk(struct inode *inode, long block, int create, int *err)
}
return bh;
}
+
return NULL;
}
-static struct buffer_head * inode_getblk(struct inode * inode, long block,
- int *err, long *phys, int *new)
+/* Extend the file by 'blocks' blocks, return the number of extents added */
+static int udf_do_extend_file(struct inode *inode,
+ struct extent_position *last_pos,
+ struct kernel_long_ad *last_ext,
+ sector_t blocks)
+{
+ sector_t add;
+ int count = 0, fake = !(last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
+ struct super_block *sb = inode->i_sb;
+ struct kernel_lb_addr prealloc_loc = {};
+ int prealloc_len = 0;
+ struct udf_inode_info *iinfo;
+ int err;
+
+ /* The previous extent is fake and we should not extend by anything
+ * - there's nothing to do... */
+ if (!blocks && fake)
+ return 0;
+
+ iinfo = UDF_I(inode);
+ /* Round the last extent up to a multiple of block size */
+ if (last_ext->extLength & (sb->s_blocksize - 1)) {
+ last_ext->extLength =
+ (last_ext->extLength & UDF_EXTENT_FLAG_MASK) |
+ (((last_ext->extLength & UDF_EXTENT_LENGTH_MASK) +
+ sb->s_blocksize - 1) & ~(sb->s_blocksize - 1));
+ iinfo->i_lenExtents =
+ (iinfo->i_lenExtents + sb->s_blocksize - 1) &
+ ~(sb->s_blocksize - 1);
+ }
+
+ /* Last extent are just preallocated blocks? */
+ if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) ==
+ EXT_NOT_RECORDED_ALLOCATED) {
+ /* Save the extent so that we can reattach it to the end */
+ prealloc_loc = last_ext->extLocation;
+ prealloc_len = last_ext->extLength;
+ /* Mark the extent as a hole */
+ last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
+ (last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
+ last_ext->extLocation.logicalBlockNum = 0;
+ last_ext->extLocation.partitionReferenceNum = 0;
+ }
+
+ /* Can we merge with the previous extent? */
+ if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) ==
+ EXT_NOT_RECORDED_NOT_ALLOCATED) {
+ add = ((1 << 30) - sb->s_blocksize -
+ (last_ext->extLength & UDF_EXTENT_LENGTH_MASK)) >>
+ sb->s_blocksize_bits;
+ if (add > blocks)
+ add = blocks;
+ blocks -= add;
+ last_ext->extLength += add << sb->s_blocksize_bits;
+ }
+
+ if (fake) {
+ udf_add_aext(inode, last_pos, &last_ext->extLocation,
+ last_ext->extLength, 1);
+ count++;
+ } else
+ udf_write_aext(inode, last_pos, &last_ext->extLocation,
+ last_ext->extLength, 1);
+
+ /* Managed to do everything necessary? */
+ if (!blocks)
+ goto out;
+
+ /* All further extents will be NOT_RECORDED_NOT_ALLOCATED */
+ last_ext->extLocation.logicalBlockNum = 0;
+ last_ext->extLocation.partitionReferenceNum = 0;
+ add = (1 << (30-sb->s_blocksize_bits)) - 1;
+ last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
+ (add << sb->s_blocksize_bits);
+
+ /* Create enough extents to cover the whole hole */
+ while (blocks > add) {
+ blocks -= add;
+ err = udf_add_aext(inode, last_pos, &last_ext->extLocation,
+ last_ext->extLength, 1);
+ if (err)
+ return err;
+ count++;
+ }
+ if (blocks) {
+ last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
+ (blocks << sb->s_blocksize_bits);
+ err = udf_add_aext(inode, last_pos, &last_ext->extLocation,
+ last_ext->extLength, 1);
+ if (err)
+ return err;
+ count++;
+ }
+
+out:
+ /* Do we have some preallocated blocks saved? */
+ if (prealloc_len) {
+ err = udf_add_aext(inode, last_pos, &prealloc_loc,
+ prealloc_len, 1);
+ if (err)
+ return err;
+ last_ext->extLocation = prealloc_loc;
+ last_ext->extLength = prealloc_len;
+ count++;
+ }
+
+ /* last_pos should point to the last written extent... */
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+ last_pos->offset -= sizeof(struct short_ad);
+ else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+ last_pos->offset -= sizeof(struct long_ad);
+ else
+ return -EIO;
+
+ return count;
+}
+
+static int udf_extend_file(struct inode *inode, loff_t newsize)
{
- struct buffer_head *pbh = NULL, *cbh = NULL, *nbh = NULL, *result = NULL;
- kernel_long_ad laarr[EXTENT_MERGE_SIZE];
- uint32_t pextoffset = 0, cextoffset = 0, nextoffset = 0;
+
+ struct extent_position epos;
+ struct kernel_lb_addr eloc;
+ uint32_t elen;
+ int8_t etype;
+ struct super_block *sb = inode->i_sb;
+ sector_t first_block = newsize >> sb->s_blocksize_bits, offset;
+ int adsize;
+ struct udf_inode_info *iinfo = UDF_I(inode);
+ struct kernel_long_ad extent;
+ int err;
+
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+ adsize = sizeof(struct short_ad);
+ else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+ adsize = sizeof(struct long_ad);
+ else
+ BUG();
+
+ etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
+
+ /* File has extent covering the new size (could happen when extending
+ * inside a block)? */
+ if (etype != -1)
+ return 0;
+ if (newsize & (sb->s_blocksize - 1))
+ offset++;
+ /* Extended file just to the boundary of the last file block? */
+ if (offset == 0)
+ return 0;
+
+ /* Truncate is extending the file by 'offset' blocks */
+ if ((!epos.bh && epos.offset == udf_file_entry_alloc_offset(inode)) ||
+ (epos.bh && epos.offset == sizeof(struct allocExtDesc))) {
+ /* File has no extents at all or has empty last
+ * indirect extent! Create a fake extent... */
+ extent.extLocation.logicalBlockNum = 0;
+ extent.extLocation.partitionReferenceNum = 0;
+ extent.extLength = EXT_NOT_RECORDED_NOT_ALLOCATED;
+ } else {
+ epos.offset -= adsize;
+ etype = udf_next_aext(inode, &epos, &extent.extLocation,
+ &extent.extLength, 0);
+ extent.extLength |= etype << 30;
+ }
+ err = udf_do_extend_file(inode, &epos, &extent, offset);
+ if (err < 0)
+ goto out;
+ err = 0;
+ iinfo->i_lenExtents = newsize;
+out:
+ brelse(epos.bh);
+ return err;
+}
+
+static sector_t inode_getblk(struct inode *inode, sector_t block,
+ int *err, int *new)
+{
+ struct kernel_long_ad laarr[EXTENT_MERGE_SIZE];
+ struct extent_position prev_epos, cur_epos, next_epos;
int count = 0, startnum = 0, endnum = 0;
- uint32_t elen = 0;
- kernel_lb_addr eloc, pbloc, cbloc, nbloc;
+ uint32_t elen = 0, tmpelen;
+ struct kernel_lb_addr eloc, tmpeloc;
int c = 1;
- uint64_t lbcount = 0, b_off = 0;
- uint32_t newblocknum, newblock, offset = 0;
+ loff_t lbcount = 0, b_off = 0;
+ uint32_t newblocknum, newblock;
+ sector_t offset = 0;
int8_t etype;
- int goal = 0, pgoal = UDF_I_LOCATION(inode).logicalBlockNum;
- char lastblock = 0;
+ struct udf_inode_info *iinfo = UDF_I(inode);
+ int goal = 0, pgoal = iinfo->i_location.logicalBlockNum;
+ int lastblock = 0;
+ bool isBeyondEOF;
- pextoffset = cextoffset = nextoffset = udf_file_entry_alloc_offset(inode);
- b_off = (uint64_t)block << inode->i_sb->s_blocksize_bits;
- pbloc = cbloc = nbloc = UDF_I_LOCATION(inode);
+ *err = 0;
+ *new = 0;
+ prev_epos.offset = udf_file_entry_alloc_offset(inode);
+ prev_epos.block = iinfo->i_location;
+ prev_epos.bh = NULL;
+ cur_epos = next_epos = prev_epos;
+ b_off = (loff_t)block << inode->i_sb->s_blocksize_bits;
/* find the extent which contains the block we are looking for.
- alternate between laarr[0] and laarr[1] for locations of the
- current extent, and the previous extent */
- do
- {
- if (pbh != cbh)
- {
- udf_release_data(pbh);
- atomic_inc(&cbh->b_count);
- pbh = cbh;
+ alternate between laarr[0] and laarr[1] for locations of the
+ current extent, and the previous extent */
+ do {
+ if (prev_epos.bh != cur_epos.bh) {
+ brelse(prev_epos.bh);
+ get_bh(cur_epos.bh);
+ prev_epos.bh = cur_epos.bh;
}
- if (cbh != nbh)
- {
- udf_release_data(cbh);
- atomic_inc(&nbh->b_count);
- cbh = nbh;
+ if (cur_epos.bh != next_epos.bh) {
+ brelse(cur_epos.bh);
+ get_bh(next_epos.bh);
+ cur_epos.bh = next_epos.bh;
}
lbcount += elen;
- pbloc = cbloc;
- cbloc = nbloc;
+ prev_epos.block = cur_epos.block;
+ cur_epos.block = next_epos.block;
- pextoffset = cextoffset;
- cextoffset = nextoffset;
+ prev_epos.offset = cur_epos.offset;
+ cur_epos.offset = next_epos.offset;
- if ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) == -1)
+ etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 1);
+ if (etype == -1)
break;
c = !c;
@@ -418,428 +717,475 @@ static struct buffer_head * inode_getblk(struct inode * inode, long block,
if (etype != (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
pgoal = eloc.logicalBlockNum +
((elen + inode->i_sb->s_blocksize - 1) >>
- inode->i_sb->s_blocksize_bits);
+ inode->i_sb->s_blocksize_bits);
- count ++;
+ count++;
} while (lbcount + elen <= b_off);
b_off -= lbcount;
offset = b_off >> inode->i_sb->s_blocksize_bits;
+ /*
+ * Move prev_epos and cur_epos into indirect extent if we are at
+ * the pointer to it
+ */
+ udf_next_aext(inode, &prev_epos, &tmpeloc, &tmpelen, 0);
+ udf_next_aext(inode, &cur_epos, &tmpeloc, &tmpelen, 0);
/* if the extent is allocated and recorded, return the block
- if the extent is not a multiple of the blocksize, round up */
+ if the extent is not a multiple of the blocksize, round up */
- if (etype == (EXT_RECORDED_ALLOCATED >> 30))
- {
- if (elen & (inode->i_sb->s_blocksize - 1))
- {
+ if (etype == (EXT_RECORDED_ALLOCATED >> 30)) {
+ if (elen & (inode->i_sb->s_blocksize - 1)) {
elen = EXT_RECORDED_ALLOCATED |
((elen + inode->i_sb->s_blocksize - 1) &
- ~(inode->i_sb->s_blocksize - 1));
- etype = udf_write_aext(inode, nbloc, &cextoffset, eloc, elen, nbh, 1);
- }
- udf_release_data(pbh);
- udf_release_data(cbh);
- udf_release_data(nbh);
- newblock = udf_get_lb_pblock(inode->i_sb, eloc, offset);
- *phys = newblock;
- return NULL;
+ ~(inode->i_sb->s_blocksize - 1));
+ udf_write_aext(inode, &cur_epos, &eloc, elen, 1);
+ }
+ brelse(prev_epos.bh);
+ brelse(cur_epos.bh);
+ brelse(next_epos.bh);
+ newblock = udf_get_lb_pblock(inode->i_sb, &eloc, offset);
+ return newblock;
}
- if (etype == -1)
- {
- endnum = startnum = ((count > 1) ? 1 : count);
- if (laarr[c].extLength & (inode->i_sb->s_blocksize - 1))
- {
- laarr[c].extLength =
- (laarr[c].extLength & UDF_EXTENT_FLAG_MASK) |
- (((laarr[c].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) &
- ~(inode->i_sb->s_blocksize - 1));
- UDF_I_LENEXTENTS(inode) =
- (UDF_I_LENEXTENTS(inode) + inode->i_sb->s_blocksize - 1) &
- ~(inode->i_sb->s_blocksize - 1);
- }
- c = !c;
- laarr[c].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
- ((offset + 1) << inode->i_sb->s_blocksize_bits);
- memset(&laarr[c].extLocation, 0x00, sizeof(kernel_lb_addr));
- count ++;
- endnum ++;
+ /* Are we beyond EOF? */
+ if (etype == -1) {
+ int ret;
+ isBeyondEOF = 1;
+ if (count) {
+ if (c)
+ laarr[0] = laarr[1];
+ startnum = 1;
+ } else {
+ /* Create a fake extent when there's not one */
+ memset(&laarr[0].extLocation, 0x00,
+ sizeof(struct kernel_lb_addr));
+ laarr[0].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED;
+ /* Will udf_do_extend_file() create real extent from
+ a fake one? */
+ startnum = (offset > 0);
+ }
+ /* Create extents for the hole between EOF and offset */
+ ret = udf_do_extend_file(inode, &prev_epos, laarr, offset);
+ if (ret < 0) {
+ brelse(prev_epos.bh);
+ brelse(cur_epos.bh);
+ brelse(next_epos.bh);
+ *err = ret;
+ return 0;
+ }
+ c = 0;
+ offset = 0;
+ count += ret;
+ /* We are not covered by a preallocated extent? */
+ if ((laarr[0].extLength & UDF_EXTENT_FLAG_MASK) !=
+ EXT_NOT_RECORDED_ALLOCATED) {
+ /* Is there any real extent? - otherwise we overwrite
+ * the fake one... */
+ if (count)
+ c = !c;
+ laarr[c].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
+ inode->i_sb->s_blocksize;
+ memset(&laarr[c].extLocation, 0x00,
+ sizeof(struct kernel_lb_addr));
+ count++;
+ }
+ endnum = c + 1;
lastblock = 1;
- }
- else
+ } else {
+ isBeyondEOF = 0;
endnum = startnum = ((count > 2) ? 2 : count);
- /* if the current extent is in position 0, swap it with the previous */
- if (!c && count != 1)
- {
- laarr[2] = laarr[0];
- laarr[0] = laarr[1];
- laarr[1] = laarr[2];
- c = 1;
- }
-
- /* if the current block is located in a extent, read the next extent */
- if (etype != -1)
- {
- if ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 0)) != -1)
- {
- laarr[c+1].extLength = (etype << 30) | elen;
- laarr[c+1].extLocation = eloc;
- count ++;
- startnum ++;
- endnum ++;
- }
- else
+ /* if the current extent is in position 0,
+ swap it with the previous */
+ if (!c && count != 1) {
+ laarr[2] = laarr[0];
+ laarr[0] = laarr[1];
+ laarr[1] = laarr[2];
+ c = 1;
+ }
+
+ /* if the current block is located in an extent,
+ read the next extent */
+ etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 0);
+ if (etype != -1) {
+ laarr[c + 1].extLength = (etype << 30) | elen;
+ laarr[c + 1].extLocation = eloc;
+ count++;
+ startnum++;
+ endnum++;
+ } else
lastblock = 1;
}
- udf_release_data(cbh);
- udf_release_data(nbh);
/* if the current extent is not recorded but allocated, get the
- block in the extent corresponding to the requested block */
+ * block in the extent corresponding to the requested block */
if ((laarr[c].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30))
newblocknum = laarr[c].extLocation.logicalBlockNum + offset;
- else /* otherwise, allocate a new block */
- {
- if (UDF_I_NEXT_ALLOC_BLOCK(inode) == block)
- goal = UDF_I_NEXT_ALLOC_GOAL(inode);
-
- if (!goal)
- {
- if (!(goal = pgoal))
- goal = UDF_I_LOCATION(inode).logicalBlockNum + 1;
- }
-
- if (!(newblocknum = udf_new_block(inode->i_sb, inode,
- UDF_I_LOCATION(inode).partitionReferenceNum, goal, err)))
- {
- udf_release_data(pbh);
+ else { /* otherwise, allocate a new block */
+ if (iinfo->i_next_alloc_block == block)
+ goal = iinfo->i_next_alloc_goal;
+
+ if (!goal) {
+ if (!(goal = pgoal)) /* XXX: what was intended here? */
+ goal = iinfo->i_location.logicalBlockNum + 1;
+ }
+
+ newblocknum = udf_new_block(inode->i_sb, inode,
+ iinfo->i_location.partitionReferenceNum,
+ goal, err);
+ if (!newblocknum) {
+ brelse(prev_epos.bh);
+ brelse(cur_epos.bh);
+ brelse(next_epos.bh);
*err = -ENOSPC;
- return NULL;
+ return 0;
}
- UDF_I_LENEXTENTS(inode) += inode->i_sb->s_blocksize;
+ if (isBeyondEOF)
+ iinfo->i_lenExtents += inode->i_sb->s_blocksize;
}
- /* if the extent the requsted block is located in contains multiple blocks,
- split the extent into at most three extents. blocks prior to requested
- block, requested block, and blocks after requested block */
+ /* if the extent the requsted block is located in contains multiple
+ * blocks, split the extent into at most three extents. blocks prior
+ * to requested block, requested block, and blocks after requested
+ * block */
udf_split_extents(inode, &c, offset, newblocknum, laarr, &endnum);
#ifdef UDF_PREALLOCATE
- /* preallocate blocks */
- udf_prealloc_extents(inode, c, lastblock, laarr, &endnum);
+ /* We preallocate blocks only for regular files. It also makes sense
+ * for directories but there's a problem when to drop the
+ * preallocation. We might use some delayed work for that but I feel
+ * it's overengineering for a filesystem like UDF. */
+ if (S_ISREG(inode->i_mode))
+ udf_prealloc_extents(inode, c, lastblock, laarr, &endnum);
#endif
/* merge any continuous blocks in laarr */
udf_merge_extents(inode, laarr, &endnum);
/* write back the new extents, inserting new extents if the new number
- of extents is greater than the old number, and deleting extents if
- the new number of extents is less than the old number */
- udf_update_extents(inode, laarr, startnum, endnum, pbloc, pextoffset, &pbh);
-
- udf_release_data(pbh);
-
- if (!(newblock = udf_get_pblock(inode->i_sb, newblocknum,
- UDF_I_LOCATION(inode).partitionReferenceNum, 0)))
- {
- return NULL;
+ * of extents is greater than the old number, and deleting extents if
+ * the new number of extents is less than the old number */
+ udf_update_extents(inode, laarr, startnum, endnum, &prev_epos);
+
+ brelse(prev_epos.bh);
+ brelse(cur_epos.bh);
+ brelse(next_epos.bh);
+
+ newblock = udf_get_pblock(inode->i_sb, newblocknum,
+ iinfo->i_location.partitionReferenceNum, 0);
+ if (!newblock) {
+ *err = -EIO;
+ return 0;
}
- *phys = newblock;
- *err = 0;
*new = 1;
- UDF_I_NEXT_ALLOC_BLOCK(inode) = block;
- UDF_I_NEXT_ALLOC_GOAL(inode) = newblocknum;
+ iinfo->i_next_alloc_block = block;
+ iinfo->i_next_alloc_goal = newblocknum;
inode->i_ctime = current_fs_time(inode->i_sb);
if (IS_SYNC(inode))
udf_sync_inode(inode);
else
mark_inode_dirty(inode);
- return result;
+
+ return newblock;
}
-static void udf_split_extents(struct inode *inode, int *c, int offset, int newblocknum,
- kernel_long_ad laarr[EXTENT_MERGE_SIZE], int *endnum)
+static void udf_split_extents(struct inode *inode, int *c, int offset,
+ int newblocknum,
+ struct kernel_long_ad laarr[EXTENT_MERGE_SIZE],
+ int *endnum)
{
+ unsigned long blocksize = inode->i_sb->s_blocksize;
+ unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits;
+
if ((laarr[*c].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30) ||
- (laarr[*c].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
- {
+ (laarr[*c].extLength >> 30) ==
+ (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) {
int curr = *c;
int blen = ((laarr[curr].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
+ blocksize - 1) >> blocksize_bits;
int8_t etype = (laarr[curr].extLength >> 30);
if (blen == 1)
;
- else if (!offset || blen == offset + 1)
- {
- laarr[curr+2] = laarr[curr+1];
- laarr[curr+1] = laarr[curr];
- }
- else
- {
- laarr[curr+3] = laarr[curr+1];
- laarr[curr+2] = laarr[curr+1] = laarr[curr];
- }
-
- if (offset)
- {
- if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
- {
- udf_free_blocks(inode->i_sb, inode, laarr[curr].extLocation, 0, offset);
- laarr[curr].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
- (offset << inode->i_sb->s_blocksize_bits);
+ else if (!offset || blen == offset + 1) {
+ laarr[curr + 2] = laarr[curr + 1];
+ laarr[curr + 1] = laarr[curr];
+ } else {
+ laarr[curr + 3] = laarr[curr + 1];
+ laarr[curr + 2] = laarr[curr + 1] = laarr[curr];
+ }
+
+ if (offset) {
+ if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
+ udf_free_blocks(inode->i_sb, inode,
+ &laarr[curr].extLocation,
+ 0, offset);
+ laarr[curr].extLength =
+ EXT_NOT_RECORDED_NOT_ALLOCATED |
+ (offset << blocksize_bits);
laarr[curr].extLocation.logicalBlockNum = 0;
- laarr[curr].extLocation.partitionReferenceNum = 0;
- }
- else
+ laarr[curr].extLocation.
+ partitionReferenceNum = 0;
+ } else
laarr[curr].extLength = (etype << 30) |
- (offset << inode->i_sb->s_blocksize_bits);
- curr ++;
- (*c) ++;
- (*endnum) ++;
+ (offset << blocksize_bits);
+ curr++;
+ (*c)++;
+ (*endnum)++;
}
-
+
laarr[curr].extLocation.logicalBlockNum = newblocknum;
if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
laarr[curr].extLocation.partitionReferenceNum =
- UDF_I_LOCATION(inode).partitionReferenceNum;
+ UDF_I(inode)->i_location.partitionReferenceNum;
laarr[curr].extLength = EXT_RECORDED_ALLOCATED |
- inode->i_sb->s_blocksize;
- curr ++;
+ blocksize;
+ curr++;
- if (blen != offset + 1)
- {
+ if (blen != offset + 1) {
if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
- laarr[curr].extLocation.logicalBlockNum += (offset + 1);
+ laarr[curr].extLocation.logicalBlockNum +=
+ offset + 1;
laarr[curr].extLength = (etype << 30) |
- ((blen - (offset + 1)) << inode->i_sb->s_blocksize_bits);
- curr ++;
- (*endnum) ++;
+ ((blen - (offset + 1)) << blocksize_bits);
+ curr++;
+ (*endnum)++;
}
}
}
static void udf_prealloc_extents(struct inode *inode, int c, int lastblock,
- kernel_long_ad laarr[EXTENT_MERGE_SIZE], int *endnum)
+ struct kernel_long_ad laarr[EXTENT_MERGE_SIZE],
+ int *endnum)
{
int start, length = 0, currlength = 0, i;
- if (*endnum >= (c+1))
- {
+ if (*endnum >= (c + 1)) {
if (!lastblock)
return;
else
start = c;
- }
- else
- {
- if ((laarr[c+1].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30))
- {
- start = c+1;
- length = currlength = (((laarr[c+1].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
- }
- else
+ } else {
+ if ((laarr[c + 1].extLength >> 30) ==
+ (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
+ start = c + 1;
+ length = currlength =
+ (((laarr[c + 1].extLength &
+ UDF_EXTENT_LENGTH_MASK) +
+ inode->i_sb->s_blocksize - 1) >>
+ inode->i_sb->s_blocksize_bits);
+ } else
start = c;
}
- for (i=start+1; i<=*endnum; i++)
- {
- if (i == *endnum)
- {
+ for (i = start + 1; i <= *endnum; i++) {
+ if (i == *endnum) {
if (lastblock)
length += UDF_DEFAULT_PREALLOC_BLOCKS;
- }
- else if ((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
- length += (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
- else
+ } else if ((laarr[i].extLength >> 30) ==
+ (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) {
+ length += (((laarr[i].extLength &
+ UDF_EXTENT_LENGTH_MASK) +
+ inode->i_sb->s_blocksize - 1) >>
+ inode->i_sb->s_blocksize_bits);
+ } else
break;
}
- if (length)
- {
+ if (length) {
int next = laarr[start].extLocation.logicalBlockNum +
(((laarr[start].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+ inode->i_sb->s_blocksize - 1) >>
+ inode->i_sb->s_blocksize_bits);
int numalloc = udf_prealloc_blocks(inode->i_sb, inode,
- laarr[start].extLocation.partitionReferenceNum,
- next, (UDF_DEFAULT_PREALLOC_BLOCKS > length ? length :
- UDF_DEFAULT_PREALLOC_BLOCKS) - currlength);
-
- if (numalloc)
- {
- if (start == (c+1))
+ laarr[start].extLocation.partitionReferenceNum,
+ next, (UDF_DEFAULT_PREALLOC_BLOCKS > length ?
+ length : UDF_DEFAULT_PREALLOC_BLOCKS) -
+ currlength);
+ if (numalloc) {
+ if (start == (c + 1))
laarr[start].extLength +=
- (numalloc << inode->i_sb->s_blocksize_bits);
- else
- {
- memmove(&laarr[c+2], &laarr[c+1],
- sizeof(long_ad) * (*endnum - (c+1)));
- (*endnum) ++;
- laarr[c+1].extLocation.logicalBlockNum = next;
- laarr[c+1].extLocation.partitionReferenceNum =
- laarr[c].extLocation.partitionReferenceNum;
- laarr[c+1].extLength = EXT_NOT_RECORDED_ALLOCATED |
- (numalloc << inode->i_sb->s_blocksize_bits);
- start = c+1;
+ (numalloc <<
+ inode->i_sb->s_blocksize_bits);
+ else {
+ memmove(&laarr[c + 2], &laarr[c + 1],
+ sizeof(struct long_ad) * (*endnum - (c + 1)));
+ (*endnum)++;
+ laarr[c + 1].extLocation.logicalBlockNum = next;
+ laarr[c + 1].extLocation.partitionReferenceNum =
+ laarr[c].extLocation.
+ partitionReferenceNum;
+ laarr[c + 1].extLength =
+ EXT_NOT_RECORDED_ALLOCATED |
+ (numalloc <<
+ inode->i_sb->s_blocksize_bits);
+ start = c + 1;
}
- for (i=start+1; numalloc && i<*endnum; i++)
- {
- int elen = ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
+ for (i = start + 1; numalloc && i < *endnum; i++) {
+ int elen = ((laarr[i].extLength &
+ UDF_EXTENT_LENGTH_MASK) +
+ inode->i_sb->s_blocksize - 1) >>
+ inode->i_sb->s_blocksize_bits;
- if (elen > numalloc)
- {
+ if (elen > numalloc) {
laarr[i].extLength -=
- (numalloc << inode->i_sb->s_blocksize_bits);
+ (numalloc <<
+ inode->i_sb->s_blocksize_bits);
numalloc = 0;
- }
- else
- {
+ } else {
numalloc -= elen;
- if (*endnum > (i+1))
- memmove(&laarr[i], &laarr[i+1],
- sizeof(long_ad) * (*endnum - (i+1)));
- i --;
- (*endnum) --;
+ if (*endnum > (i + 1))
+ memmove(&laarr[i],
+ &laarr[i + 1],
+ sizeof(struct long_ad) *
+ (*endnum - (i + 1)));
+ i--;
+ (*endnum)--;
}
}
- UDF_I_LENEXTENTS(inode) += numalloc << inode->i_sb->s_blocksize_bits;
+ UDF_I(inode)->i_lenExtents +=
+ numalloc << inode->i_sb->s_blocksize_bits;
}
}
}
static void udf_merge_extents(struct inode *inode,
- kernel_long_ad laarr[EXTENT_MERGE_SIZE], int *endnum)
+ struct kernel_long_ad laarr[EXTENT_MERGE_SIZE],
+ int *endnum)
{
int i;
-
- for (i=0; i<(*endnum-1); i++)
- {
- if ((laarr[i].extLength >> 30) == (laarr[i+1].extLength >> 30))
- {
- if (((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) ||
- ((laarr[i+1].extLocation.logicalBlockNum - laarr[i].extLocation.logicalBlockNum) ==
- (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits)))
- {
- if (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
- (laarr[i+1].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) & ~UDF_EXTENT_LENGTH_MASK)
- {
- laarr[i+1].extLength = (laarr[i+1].extLength -
- (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
- UDF_EXTENT_LENGTH_MASK) & ~(inode->i_sb->s_blocksize-1);
- laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_FLAG_MASK) +
- (UDF_EXTENT_LENGTH_MASK + 1) - inode->i_sb->s_blocksize;
- laarr[i+1].extLocation.logicalBlockNum =
- laarr[i].extLocation.logicalBlockNum +
- ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) >>
- inode->i_sb->s_blocksize_bits);
- }
- else
- {
- laarr[i].extLength = laarr[i+1].extLength +
- (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) & ~(inode->i_sb->s_blocksize-1));
- if (*endnum > (i+2))
- memmove(&laarr[i+1], &laarr[i+2],
- sizeof(long_ad) * (*endnum - (i+2)));
- i --;
- (*endnum) --;
- }
- }
- }
- else if (((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) &&
- ((laarr[i+1].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)))
- {
- udf_free_blocks(inode->i_sb, inode, laarr[i].extLocation, 0,
- ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
- laarr[i].extLocation.logicalBlockNum = 0;
- laarr[i].extLocation.partitionReferenceNum = 0;
-
- if (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
- (laarr[i+1].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) & ~UDF_EXTENT_LENGTH_MASK)
- {
- laarr[i+1].extLength = (laarr[i+1].extLength -
- (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
- UDF_EXTENT_LENGTH_MASK) & ~(inode->i_sb->s_blocksize-1);
- laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_FLAG_MASK) +
- (UDF_EXTENT_LENGTH_MASK + 1) - inode->i_sb->s_blocksize;
+ unsigned long blocksize = inode->i_sb->s_blocksize;
+ unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits;
+
+ for (i = 0; i < (*endnum - 1); i++) {
+ struct kernel_long_ad *li /*l[i]*/ = &laarr[i];
+ struct kernel_long_ad *lip1 /*l[i plus 1]*/ = &laarr[i + 1];
+
+ if (((li->extLength >> 30) == (lip1->extLength >> 30)) &&
+ (((li->extLength >> 30) ==
+ (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) ||
+ ((lip1->extLocation.logicalBlockNum -
+ li->extLocation.logicalBlockNum) ==
+ (((li->extLength & UDF_EXTENT_LENGTH_MASK) +
+ blocksize - 1) >> blocksize_bits)))) {
+
+ if (((li->extLength & UDF_EXTENT_LENGTH_MASK) +
+ (lip1->extLength & UDF_EXTENT_LENGTH_MASK) +
+ blocksize - 1) & ~UDF_EXTENT_LENGTH_MASK) {
+ lip1->extLength = (lip1->extLength -
+ (li->extLength &
+ UDF_EXTENT_LENGTH_MASK) +
+ UDF_EXTENT_LENGTH_MASK) &
+ ~(blocksize - 1);
+ li->extLength = (li->extLength &
+ UDF_EXTENT_FLAG_MASK) +
+ (UDF_EXTENT_LENGTH_MASK + 1) -
+ blocksize;
+ lip1->extLocation.logicalBlockNum =
+ li->extLocation.logicalBlockNum +
+ ((li->extLength &
+ UDF_EXTENT_LENGTH_MASK) >>
+ blocksize_bits);
+ } else {
+ li->extLength = lip1->extLength +
+ (((li->extLength &
+ UDF_EXTENT_LENGTH_MASK) +
+ blocksize - 1) & ~(blocksize - 1));
+ if (*endnum > (i + 2))
+ memmove(&laarr[i + 1], &laarr[i + 2],
+ sizeof(struct long_ad) *
+ (*endnum - (i + 2)));
+ i--;
+ (*endnum)--;
}
- else
- {
- laarr[i].extLength = laarr[i+1].extLength +
- (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) & ~(inode->i_sb->s_blocksize-1));
- if (*endnum > (i+2))
- memmove(&laarr[i+1], &laarr[i+2],
- sizeof(long_ad) * (*endnum - (i+2)));
- i --;
- (*endnum) --;
+ } else if (((li->extLength >> 30) ==
+ (EXT_NOT_RECORDED_ALLOCATED >> 30)) &&
+ ((lip1->extLength >> 30) ==
+ (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))) {
+ udf_free_blocks(inode->i_sb, inode, &li->extLocation, 0,
+ ((li->extLength &
+ UDF_EXTENT_LENGTH_MASK) +
+ blocksize - 1) >> blocksize_bits);
+ li->extLocation.logicalBlockNum = 0;
+ li->extLocation.partitionReferenceNum = 0;
+
+ if (((li->extLength & UDF_EXTENT_LENGTH_MASK) +
+ (lip1->extLength & UDF_EXTENT_LENGTH_MASK) +
+ blocksize - 1) & ~UDF_EXTENT_LENGTH_MASK) {
+ lip1->extLength = (lip1->extLength -
+ (li->extLength &
+ UDF_EXTENT_LENGTH_MASK) +
+ UDF_EXTENT_LENGTH_MASK) &
+ ~(blocksize - 1);
+ li->extLength = (li->extLength &
+ UDF_EXTENT_FLAG_MASK) +
+ (UDF_EXTENT_LENGTH_MASK + 1) -
+ blocksize;
+ } else {
+ li->extLength = lip1->extLength +
+ (((li->extLength &
+ UDF_EXTENT_LENGTH_MASK) +
+ blocksize - 1) & ~(blocksize - 1));
+ if (*endnum > (i + 2))
+ memmove(&laarr[i + 1], &laarr[i + 2],
+ sizeof(struct long_ad) *
+ (*endnum - (i + 2)));
+ i--;
+ (*endnum)--;
}
- }
- else if ((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30))
- {
- udf_free_blocks(inode->i_sb, inode, laarr[i].extLocation, 0,
- ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
- laarr[i].extLocation.logicalBlockNum = 0;
- laarr[i].extLocation.partitionReferenceNum = 0;
- laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) |
- EXT_NOT_RECORDED_NOT_ALLOCATED;
+ } else if ((li->extLength >> 30) ==
+ (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
+ udf_free_blocks(inode->i_sb, inode,
+ &li->extLocation, 0,
+ ((li->extLength &
+ UDF_EXTENT_LENGTH_MASK) +
+ blocksize - 1) >> blocksize_bits);
+ li->extLocation.logicalBlockNum = 0;
+ li->extLocation.partitionReferenceNum = 0;
+ li->extLength = (li->extLength &
+ UDF_EXTENT_LENGTH_MASK) |
+ EXT_NOT_RECORDED_NOT_ALLOCATED;
}
}
}
static void udf_update_extents(struct inode *inode,
- kernel_long_ad laarr[EXTENT_MERGE_SIZE], int startnum, int endnum,
- kernel_lb_addr pbloc, uint32_t pextoffset, struct buffer_head **pbh)
+ struct kernel_long_ad laarr[EXTENT_MERGE_SIZE],
+ int startnum, int endnum,
+ struct extent_position *epos)
{
int start = 0, i;
- kernel_lb_addr tmploc;
+ struct kernel_lb_addr tmploc;
uint32_t tmplen;
- if (startnum > endnum)
- {
- for (i=0; i<(startnum-endnum); i++)
- {
- udf_delete_aext(inode, pbloc, pextoffset, laarr[i].extLocation,
- laarr[i].extLength, *pbh);
- }
- }
- else if (startnum < endnum)
- {
- for (i=0; i<(endnum-startnum); i++)
- {
- udf_insert_aext(inode, pbloc, pextoffset, laarr[i].extLocation,
- laarr[i].extLength, *pbh);
- udf_next_aext(inode, &pbloc, &pextoffset, &laarr[i].extLocation,
- &laarr[i].extLength, pbh, 1);
- start ++;
+ if (startnum > endnum) {
+ for (i = 0; i < (startnum - endnum); i++)
+ udf_delete_aext(inode, *epos, laarr[i].extLocation,
+ laarr[i].extLength);
+ } else if (startnum < endnum) {
+ for (i = 0; i < (endnum - startnum); i++) {
+ udf_insert_aext(inode, *epos, laarr[i].extLocation,
+ laarr[i].extLength);
+ udf_next_aext(inode, epos, &laarr[i].extLocation,
+ &laarr[i].extLength, 1);
+ start++;
}
}
- for (i=start; i<endnum; i++)
- {
- udf_next_aext(inode, &pbloc, &pextoffset, &tmploc, &tmplen, pbh, 0);
- udf_write_aext(inode, pbloc, &pextoffset, laarr[i].extLocation,
- laarr[i].extLength, *pbh, 1);
+ for (i = start; i < endnum; i++) {
+ udf_next_aext(inode, epos, &tmploc, &tmplen, 0);
+ udf_write_aext(inode, epos, &laarr[i].extLocation,
+ laarr[i].extLength, 1);
}
}
-struct buffer_head * udf_bread(struct inode * inode, int block,
- int create, int * err)
+struct buffer_head *udf_bread(struct inode *inode, int block,
+ int create, int *err)
{
- struct buffer_head * bh = NULL;
+ struct buffer_head *bh = NULL;
bh = udf_getblk(inode, block, create, err);
if (!bh)
@@ -847,69 +1193,90 @@ struct buffer_head * udf_bread(struct inode * inode, int block,
if (buffer_uptodate(bh))
return bh;
+
ll_rw_block(READ, 1, &bh);
+
wait_on_buffer(bh);
if (buffer_uptodate(bh))
return bh;
+
brelse(bh);
*err = -EIO;
return NULL;
}
-void udf_truncate(struct inode * inode)
+int udf_setsize(struct inode *inode, loff_t newsize)
{
- int offset;
int err;
+ struct udf_inode_info *iinfo;
+ int bsize = 1 << inode->i_blkbits;
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
- S_ISLNK(inode->i_mode)))
- return;
+ S_ISLNK(inode->i_mode)))
+ return -EINVAL;
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
- return;
-
- lock_kernel();
- if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
- {
- if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) +
- inode->i_size))
- {
- udf_expand_file_adinicb(inode, inode->i_size, &err);
- if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
- {
- inode->i_size = UDF_I_LENALLOC(inode);
- unlock_kernel();
- return;
+ return -EPERM;
+
+ iinfo = UDF_I(inode);
+ if (newsize > inode->i_size) {
+ down_write(&iinfo->i_data_sem);
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+ if (bsize <
+ (udf_file_entry_alloc_offset(inode) + newsize)) {
+ err = udf_expand_file_adinicb(inode);
+ if (err)
+ return err;
+ down_write(&iinfo->i_data_sem);
+ } else {
+ iinfo->i_lenAlloc = newsize;
+ goto set_size;
}
- else
- udf_truncate_extents(inode);
}
- else
- {
- offset = inode->i_size & (inode->i_sb->s_blocksize - 1);
- memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode) + offset, 0x00, inode->i_sb->s_blocksize - offset - udf_file_entry_alloc_offset(inode));
- UDF_I_LENALLOC(inode) = inode->i_size;
- }
- }
- else
- {
- block_truncate_page(inode->i_mapping, inode->i_size, udf_get_block);
+ err = udf_extend_file(inode, newsize);
+ if (err) {
+ up_write(&iinfo->i_data_sem);
+ return err;
+ }
+set_size:
+ truncate_setsize(inode, newsize);
+ up_write(&iinfo->i_data_sem);
+ } else {
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+ down_write(&iinfo->i_data_sem);
+ udf_clear_extent_cache(inode);
+ memset(iinfo->i_ext.i_data + iinfo->i_lenEAttr + newsize,
+ 0x00, bsize - newsize -
+ udf_file_entry_alloc_offset(inode));
+ iinfo->i_lenAlloc = newsize;
+ truncate_setsize(inode, newsize);
+ up_write(&iinfo->i_data_sem);
+ goto update_time;
+ }
+ err = block_truncate_page(inode->i_mapping, newsize,
+ udf_get_block);
+ if (err)
+ return err;
+ down_write(&iinfo->i_data_sem);
+ udf_clear_extent_cache(inode);
+ truncate_setsize(inode, newsize);
udf_truncate_extents(inode);
- }
-
+ up_write(&iinfo->i_data_sem);
+ }
+update_time:
inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb);
if (IS_SYNC(inode))
- udf_sync_inode (inode);
+ udf_sync_inode(inode);
else
mark_inode_dirty(inode);
- unlock_kernel();
+ return 0;
}
-static void
-__udf_read_inode(struct inode *inode)
+static void __udf_read_inode(struct inode *inode)
{
struct buffer_head *bh = NULL;
struct fileEntry *fe;
uint16_t ident;
+ struct udf_inode_info *iinfo = UDF_I(inode);
/*
* Set defaults, but the inode is still incomplete!
@@ -923,437 +1290,378 @@ __udf_read_inode(struct inode *inode)
* i_nlink = 1
* i_op = NULL;
*/
- inode->i_blksize = PAGE_SIZE;
-
- bh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 0, &ident);
-
- if (!bh)
- {
- printk(KERN_ERR "udf: udf_read_inode(ino %ld) failed !bh\n",
- inode->i_ino);
+ bh = udf_read_ptagged(inode->i_sb, &iinfo->i_location, 0, &ident);
+ if (!bh) {
+ udf_err(inode->i_sb, "(ino %ld) failed !bh\n", inode->i_ino);
make_bad_inode(inode);
return;
}
if (ident != TAG_IDENT_FE && ident != TAG_IDENT_EFE &&
- ident != TAG_IDENT_USE)
- {
- printk(KERN_ERR "udf: udf_read_inode(ino %ld) failed ident=%d\n",
+ ident != TAG_IDENT_USE) {
+ udf_err(inode->i_sb, "(ino %ld) failed ident=%d\n",
inode->i_ino, ident);
- udf_release_data(bh);
+ brelse(bh);
make_bad_inode(inode);
return;
}
fe = (struct fileEntry *)bh->b_data;
- if (le16_to_cpu(fe->icbTag.strategyType) == 4096)
- {
- struct buffer_head *ibh = NULL, *nbh = NULL;
- struct indirectEntry *ie;
-
- ibh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 1, &ident);
- if (ident == TAG_IDENT_IE)
- {
- if (ibh)
- {
- kernel_lb_addr loc;
- ie = (struct indirectEntry *)ibh->b_data;
-
- loc = lelb_to_cpu(ie->indirectICB.extLocation);
-
- if (ie->indirectICB.extLength &&
- (nbh = udf_read_ptagged(inode->i_sb, loc, 0, &ident)))
- {
- if (ident == TAG_IDENT_FE ||
- ident == TAG_IDENT_EFE)
- {
- memcpy(&UDF_I_LOCATION(inode), &loc, sizeof(kernel_lb_addr));
- udf_release_data(bh);
- udf_release_data(ibh);
- udf_release_data(nbh);
- __udf_read_inode(inode);
- return;
- }
- else
- {
- udf_release_data(nbh);
- udf_release_data(ibh);
- }
+ if (fe->icbTag.strategyType == cpu_to_le16(4096)) {
+ struct buffer_head *ibh;
+
+ ibh = udf_read_ptagged(inode->i_sb, &iinfo->i_location, 1,
+ &ident);
+ if (ident == TAG_IDENT_IE && ibh) {
+ struct buffer_head *nbh = NULL;
+ struct kernel_lb_addr loc;
+ struct indirectEntry *ie;
+
+ ie = (struct indirectEntry *)ibh->b_data;
+ loc = lelb_to_cpu(ie->indirectICB.extLocation);
+
+ if (ie->indirectICB.extLength &&
+ (nbh = udf_read_ptagged(inode->i_sb, &loc, 0,
+ &ident))) {
+ if (ident == TAG_IDENT_FE ||
+ ident == TAG_IDENT_EFE) {
+ memcpy(&iinfo->i_location,
+ &loc,
+ sizeof(struct kernel_lb_addr));
+ brelse(bh);
+ brelse(ibh);
+ brelse(nbh);
+ __udf_read_inode(inode);
+ return;
}
- else
- udf_release_data(ibh);
+ brelse(nbh);
}
}
- else
- udf_release_data(ibh);
- }
- else if (le16_to_cpu(fe->icbTag.strategyType) != 4)
- {
- printk(KERN_ERR "udf: unsupported strategy type: %d\n",
+ brelse(ibh);
+ } else if (fe->icbTag.strategyType != cpu_to_le16(4)) {
+ udf_err(inode->i_sb, "unsupported strategy type: %d\n",
le16_to_cpu(fe->icbTag.strategyType));
- udf_release_data(bh);
+ brelse(bh);
make_bad_inode(inode);
return;
}
udf_fill_inode(inode, bh);
- udf_release_data(bh);
+
+ brelse(bh);
}
static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
{
struct fileEntry *fe;
struct extendedFileEntry *efe;
- time_t convtime;
- long convtime_usec;
- int offset;
+ struct udf_sb_info *sbi = UDF_SB(inode->i_sb);
+ struct udf_inode_info *iinfo = UDF_I(inode);
+ unsigned int link_count;
fe = (struct fileEntry *)bh->b_data;
efe = (struct extendedFileEntry *)bh->b_data;
- if (le16_to_cpu(fe->icbTag.strategyType) == 4)
- UDF_I_STRAT4096(inode) = 0;
- else /* if (le16_to_cpu(fe->icbTag.strategyType) == 4096) */
- UDF_I_STRAT4096(inode) = 1;
-
- UDF_I_ALLOCTYPE(inode) = le16_to_cpu(fe->icbTag.flags) & ICBTAG_FLAG_AD_MASK;
- UDF_I_UNIQUE(inode) = 0;
- UDF_I_LENEATTR(inode) = 0;
- UDF_I_LENEXTENTS(inode) = 0;
- UDF_I_LENALLOC(inode) = 0;
- UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
- UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
- if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_EFE)
- {
- UDF_I_EFE(inode) = 1;
- UDF_I_USE(inode) = 0;
- UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry), GFP_KERNEL);
- memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct extendedFileEntry), inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry));
- }
- else if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_FE)
- {
- UDF_I_EFE(inode) = 0;
- UDF_I_USE(inode) = 0;
- UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct fileEntry), GFP_KERNEL);
- memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct fileEntry), inode->i_sb->s_blocksize - sizeof(struct fileEntry));
- }
- else if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_USE)
- {
- UDF_I_EFE(inode) = 0;
- UDF_I_USE(inode) = 1;
- UDF_I_LENALLOC(inode) =
- le32_to_cpu(
- ((struct unallocSpaceEntry *)bh->b_data)->lengthAllocDescs);
- UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry), GFP_KERNEL);
- memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct unallocSpaceEntry), inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry));
+ if (fe->icbTag.strategyType == cpu_to_le16(4))
+ iinfo->i_strat4096 = 0;
+ else /* if (fe->icbTag.strategyType == cpu_to_le16(4096)) */
+ iinfo->i_strat4096 = 1;
+
+ iinfo->i_alloc_type = le16_to_cpu(fe->icbTag.flags) &
+ ICBTAG_FLAG_AD_MASK;
+ iinfo->i_unique = 0;
+ iinfo->i_lenEAttr = 0;
+ iinfo->i_lenExtents = 0;
+ iinfo->i_lenAlloc = 0;
+ iinfo->i_next_alloc_block = 0;
+ iinfo->i_next_alloc_goal = 0;
+ if (fe->descTag.tagIdent == cpu_to_le16(TAG_IDENT_EFE)) {
+ iinfo->i_efe = 1;
+ iinfo->i_use = 0;
+ if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize -
+ sizeof(struct extendedFileEntry))) {
+ make_bad_inode(inode);
+ return;
+ }
+ memcpy(iinfo->i_ext.i_data,
+ bh->b_data + sizeof(struct extendedFileEntry),
+ inode->i_sb->s_blocksize -
+ sizeof(struct extendedFileEntry));
+ } else if (fe->descTag.tagIdent == cpu_to_le16(TAG_IDENT_FE)) {
+ iinfo->i_efe = 0;
+ iinfo->i_use = 0;
+ if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize -
+ sizeof(struct fileEntry))) {
+ make_bad_inode(inode);
+ return;
+ }
+ memcpy(iinfo->i_ext.i_data,
+ bh->b_data + sizeof(struct fileEntry),
+ inode->i_sb->s_blocksize - sizeof(struct fileEntry));
+ } else if (fe->descTag.tagIdent == cpu_to_le16(TAG_IDENT_USE)) {
+ iinfo->i_efe = 0;
+ iinfo->i_use = 1;
+ iinfo->i_lenAlloc = le32_to_cpu(
+ ((struct unallocSpaceEntry *)bh->b_data)->
+ lengthAllocDescs);
+ if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize -
+ sizeof(struct unallocSpaceEntry))) {
+ make_bad_inode(inode);
+ return;
+ }
+ memcpy(iinfo->i_ext.i_data,
+ bh->b_data + sizeof(struct unallocSpaceEntry),
+ inode->i_sb->s_blocksize -
+ sizeof(struct unallocSpaceEntry));
return;
}
- inode->i_uid = le32_to_cpu(fe->uid);
- if ( inode->i_uid == -1 ) inode->i_uid = UDF_SB(inode->i_sb)->s_uid;
+ read_lock(&sbi->s_cred_lock);
+ i_uid_write(inode, le32_to_cpu(fe->uid));
+ if (!uid_valid(inode->i_uid) ||
+ UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_IGNORE) ||
+ UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_SET))
+ inode->i_uid = UDF_SB(inode->i_sb)->s_uid;
+
+ i_gid_write(inode, le32_to_cpu(fe->gid));
+ if (!gid_valid(inode->i_gid) ||
+ UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_GID_IGNORE) ||
+ UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_GID_SET))
+ inode->i_gid = UDF_SB(inode->i_sb)->s_gid;
+
+ if (fe->icbTag.fileType != ICBTAG_FILE_TYPE_DIRECTORY &&
+ sbi->s_fmode != UDF_INVALID_MODE)
+ inode->i_mode = sbi->s_fmode;
+ else if (fe->icbTag.fileType == ICBTAG_FILE_TYPE_DIRECTORY &&
+ sbi->s_dmode != UDF_INVALID_MODE)
+ inode->i_mode = sbi->s_dmode;
+ else
+ inode->i_mode = udf_convert_permissions(fe);
+ inode->i_mode &= ~sbi->s_umask;
+ read_unlock(&sbi->s_cred_lock);
- inode->i_gid = le32_to_cpu(fe->gid);
- if ( inode->i_gid == -1 ) inode->i_gid = UDF_SB(inode->i_sb)->s_gid;
+ link_count = le16_to_cpu(fe->fileLinkCount);
+ if (!link_count)
+ link_count = 1;
+ set_nlink(inode, link_count);
- inode->i_nlink = le16_to_cpu(fe->fileLinkCount);
- if (!inode->i_nlink)
- inode->i_nlink = 1;
-
inode->i_size = le64_to_cpu(fe->informationLength);
- UDF_I_LENEXTENTS(inode) = inode->i_size;
-
- inode->i_mode = udf_convert_permissions(fe);
- inode->i_mode &= ~UDF_SB(inode->i_sb)->s_umask;
+ iinfo->i_lenExtents = inode->i_size;
- if (UDF_I_EFE(inode) == 0)
- {
+ if (iinfo->i_efe == 0) {
inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) <<
(inode->i_sb->s_blocksize_bits - 9);
- if ( udf_stamp_to_time(&convtime, &convtime_usec,
- lets_to_cpu(fe->accessTime)) )
- {
- inode->i_atime.tv_sec = convtime;
- inode->i_atime.tv_nsec = convtime_usec * 1000;
- }
- else
- {
- inode->i_atime = UDF_SB_RECORDTIME(inode->i_sb);
- }
+ if (!udf_disk_stamp_to_time(&inode->i_atime, fe->accessTime))
+ inode->i_atime = sbi->s_record_time;
- if ( udf_stamp_to_time(&convtime, &convtime_usec,
- lets_to_cpu(fe->modificationTime)) )
- {
- inode->i_mtime.tv_sec = convtime;
- inode->i_mtime.tv_nsec = convtime_usec * 1000;
- }
- else
- {
- inode->i_mtime = UDF_SB_RECORDTIME(inode->i_sb);
- }
+ if (!udf_disk_stamp_to_time(&inode->i_mtime,
+ fe->modificationTime))
+ inode->i_mtime = sbi->s_record_time;
- if ( udf_stamp_to_time(&convtime, &convtime_usec,
- lets_to_cpu(fe->attrTime)) )
- {
- inode->i_ctime.tv_sec = convtime;
- inode->i_ctime.tv_nsec = convtime_usec * 1000;
- }
- else
- {
- inode->i_ctime = UDF_SB_RECORDTIME(inode->i_sb);
- }
+ if (!udf_disk_stamp_to_time(&inode->i_ctime, fe->attrTime))
+ inode->i_ctime = sbi->s_record_time;
- UDF_I_UNIQUE(inode) = le64_to_cpu(fe->uniqueID);
- UDF_I_LENEATTR(inode) = le32_to_cpu(fe->lengthExtendedAttr);
- UDF_I_LENALLOC(inode) = le32_to_cpu(fe->lengthAllocDescs);
- offset = sizeof(struct fileEntry) + UDF_I_LENEATTR(inode);
- }
- else
- {
- inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) <<
- (inode->i_sb->s_blocksize_bits - 9);
+ iinfo->i_unique = le64_to_cpu(fe->uniqueID);
+ iinfo->i_lenEAttr = le32_to_cpu(fe->lengthExtendedAttr);
+ iinfo->i_lenAlloc = le32_to_cpu(fe->lengthAllocDescs);
+ iinfo->i_checkpoint = le32_to_cpu(fe->checkpoint);
+ } else {
+ inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) <<
+ (inode->i_sb->s_blocksize_bits - 9);
- if ( udf_stamp_to_time(&convtime, &convtime_usec,
- lets_to_cpu(efe->accessTime)) )
- {
- inode->i_atime.tv_sec = convtime;
- inode->i_atime.tv_nsec = convtime_usec * 1000;
- }
- else
- {
- inode->i_atime = UDF_SB_RECORDTIME(inode->i_sb);
- }
+ if (!udf_disk_stamp_to_time(&inode->i_atime, efe->accessTime))
+ inode->i_atime = sbi->s_record_time;
- if ( udf_stamp_to_time(&convtime, &convtime_usec,
- lets_to_cpu(efe->modificationTime)) )
- {
- inode->i_mtime.tv_sec = convtime;
- inode->i_mtime.tv_nsec = convtime_usec * 1000;
- }
- else
- {
- inode->i_mtime = UDF_SB_RECORDTIME(inode->i_sb);
- }
+ if (!udf_disk_stamp_to_time(&inode->i_mtime,
+ efe->modificationTime))
+ inode->i_mtime = sbi->s_record_time;
- if ( udf_stamp_to_time(&convtime, &convtime_usec,
- lets_to_cpu(efe->createTime)) )
- {
- UDF_I_CRTIME(inode).tv_sec = convtime;
- UDF_I_CRTIME(inode).tv_nsec = convtime_usec * 1000;
- }
- else
- {
- UDF_I_CRTIME(inode) = UDF_SB_RECORDTIME(inode->i_sb);
- }
+ if (!udf_disk_stamp_to_time(&iinfo->i_crtime, efe->createTime))
+ iinfo->i_crtime = sbi->s_record_time;
- if ( udf_stamp_to_time(&convtime, &convtime_usec,
- lets_to_cpu(efe->attrTime)) )
- {
- inode->i_ctime.tv_sec = convtime;
- inode->i_ctime.tv_nsec = convtime_usec * 1000;
- }
- else
- {
- inode->i_ctime = UDF_SB_RECORDTIME(inode->i_sb);
- }
+ if (!udf_disk_stamp_to_time(&inode->i_ctime, efe->attrTime))
+ inode->i_ctime = sbi->s_record_time;
- UDF_I_UNIQUE(inode) = le64_to_cpu(efe->uniqueID);
- UDF_I_LENEATTR(inode) = le32_to_cpu(efe->lengthExtendedAttr);
- UDF_I_LENALLOC(inode) = le32_to_cpu(efe->lengthAllocDescs);
- offset = sizeof(struct extendedFileEntry) + UDF_I_LENEATTR(inode);
+ iinfo->i_unique = le64_to_cpu(efe->uniqueID);
+ iinfo->i_lenEAttr = le32_to_cpu(efe->lengthExtendedAttr);
+ iinfo->i_lenAlloc = le32_to_cpu(efe->lengthAllocDescs);
+ iinfo->i_checkpoint = le32_to_cpu(efe->checkpoint);
}
- switch (fe->icbTag.fileType)
- {
- case ICBTAG_FILE_TYPE_DIRECTORY:
- {
- inode->i_op = &udf_dir_inode_operations;
- inode->i_fop = &udf_dir_operations;
- inode->i_mode |= S_IFDIR;
- inode->i_nlink ++;
- break;
- }
- case ICBTAG_FILE_TYPE_REALTIME:
- case ICBTAG_FILE_TYPE_REGULAR:
- case ICBTAG_FILE_TYPE_UNDEF:
- {
- if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
- inode->i_data.a_ops = &udf_adinicb_aops;
- else
- inode->i_data.a_ops = &udf_aops;
- inode->i_op = &udf_file_inode_operations;
- inode->i_fop = &udf_file_operations;
- inode->i_mode |= S_IFREG;
- break;
- }
- case ICBTAG_FILE_TYPE_BLOCK:
- {
- inode->i_mode |= S_IFBLK;
- break;
- }
- case ICBTAG_FILE_TYPE_CHAR:
- {
- inode->i_mode |= S_IFCHR;
- break;
- }
- case ICBTAG_FILE_TYPE_FIFO:
- {
- init_special_inode(inode, inode->i_mode | S_IFIFO, 0);
- break;
- }
- case ICBTAG_FILE_TYPE_SOCKET:
- {
- init_special_inode(inode, inode->i_mode | S_IFSOCK, 0);
- break;
- }
- case ICBTAG_FILE_TYPE_SYMLINK:
- {
- inode->i_data.a_ops = &udf_symlink_aops;
- inode->i_op = &page_symlink_inode_operations;
- inode->i_mode = S_IFLNK|S_IRWXUGO;
- break;
- }
- default:
- {
- printk(KERN_ERR "udf: udf_fill_inode(ino %ld) failed unknown file type=%d\n",
- inode->i_ino, fe->icbTag.fileType);
- make_bad_inode(inode);
- return;
- }
+ switch (fe->icbTag.fileType) {
+ case ICBTAG_FILE_TYPE_DIRECTORY:
+ inode->i_op = &udf_dir_inode_operations;
+ inode->i_fop = &udf_dir_operations;
+ inode->i_mode |= S_IFDIR;
+ inc_nlink(inode);
+ break;
+ case ICBTAG_FILE_TYPE_REALTIME:
+ case ICBTAG_FILE_TYPE_REGULAR:
+ case ICBTAG_FILE_TYPE_UNDEF:
+ case ICBTAG_FILE_TYPE_VAT20:
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
+ inode->i_data.a_ops = &udf_adinicb_aops;
+ else
+ inode->i_data.a_ops = &udf_aops;
+ inode->i_op = &udf_file_inode_operations;
+ inode->i_fop = &udf_file_operations;
+ inode->i_mode |= S_IFREG;
+ break;
+ case ICBTAG_FILE_TYPE_BLOCK:
+ inode->i_mode |= S_IFBLK;
+ break;
+ case ICBTAG_FILE_TYPE_CHAR:
+ inode->i_mode |= S_IFCHR;
+ break;
+ case ICBTAG_FILE_TYPE_FIFO:
+ init_special_inode(inode, inode->i_mode | S_IFIFO, 0);
+ break;
+ case ICBTAG_FILE_TYPE_SOCKET:
+ init_special_inode(inode, inode->i_mode | S_IFSOCK, 0);
+ break;
+ case ICBTAG_FILE_TYPE_SYMLINK:
+ inode->i_data.a_ops = &udf_symlink_aops;
+ inode->i_op = &udf_symlink_inode_operations;
+ inode->i_mode = S_IFLNK | S_IRWXUGO;
+ break;
+ case ICBTAG_FILE_TYPE_MAIN:
+ udf_debug("METADATA FILE-----\n");
+ break;
+ case ICBTAG_FILE_TYPE_MIRROR:
+ udf_debug("METADATA MIRROR FILE-----\n");
+ break;
+ case ICBTAG_FILE_TYPE_BITMAP:
+ udf_debug("METADATA BITMAP FILE-----\n");
+ break;
+ default:
+ udf_err(inode->i_sb, "(ino %ld) failed unknown file type=%d\n",
+ inode->i_ino, fe->icbTag.fileType);
+ make_bad_inode(inode);
+ return;
}
- if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
- {
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
struct deviceSpec *dsea =
- (struct deviceSpec *)
- udf_get_extendedattr(inode, 12, 1);
-
- if (dsea)
- {
- init_special_inode(inode, inode->i_mode, MKDEV(
- le32_to_cpu(dsea->majorDeviceIdent),
- le32_to_cpu(dsea->minorDeviceIdent)));
+ (struct deviceSpec *)udf_get_extendedattr(inode, 12, 1);
+ if (dsea) {
+ init_special_inode(inode, inode->i_mode,
+ MKDEV(le32_to_cpu(dsea->majorDeviceIdent),
+ le32_to_cpu(dsea->minorDeviceIdent)));
/* Developer ID ??? */
- }
- else
- {
+ } else
make_bad_inode(inode);
- }
}
}
-static mode_t
-udf_convert_permissions(struct fileEntry *fe)
+static int udf_alloc_i_data(struct inode *inode, size_t size)
{
- mode_t mode;
+ struct udf_inode_info *iinfo = UDF_I(inode);
+ iinfo->i_ext.i_data = kmalloc(size, GFP_KERNEL);
+
+ if (!iinfo->i_ext.i_data) {
+ udf_err(inode->i_sb, "(ino %ld) no free memory\n",
+ inode->i_ino);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static umode_t udf_convert_permissions(struct fileEntry *fe)
+{
+ umode_t mode;
uint32_t permissions;
uint32_t flags;
permissions = le32_to_cpu(fe->permissions);
flags = le16_to_cpu(fe->icbTag.flags);
- mode = (( permissions ) & S_IRWXO) |
- (( permissions >> 2 ) & S_IRWXG) |
- (( permissions >> 4 ) & S_IRWXU) |
- (( flags & ICBTAG_FLAG_SETUID) ? S_ISUID : 0) |
- (( flags & ICBTAG_FLAG_SETGID) ? S_ISGID : 0) |
- (( flags & ICBTAG_FLAG_STICKY) ? S_ISVTX : 0);
+ mode = ((permissions) & S_IRWXO) |
+ ((permissions >> 2) & S_IRWXG) |
+ ((permissions >> 4) & S_IRWXU) |
+ ((flags & ICBTAG_FLAG_SETUID) ? S_ISUID : 0) |
+ ((flags & ICBTAG_FLAG_SETGID) ? S_ISGID : 0) |
+ ((flags & ICBTAG_FLAG_STICKY) ? S_ISVTX : 0);
return mode;
}
-/*
- * udf_write_inode
- *
- * PURPOSE
- * Write out the specified inode.
- *
- * DESCRIPTION
- * This routine is called whenever an inode is synced.
- * Currently this routine is just a placeholder.
- *
- * HISTORY
- * July 1, 1997 - Andrew E. Mileski
- * Written, tested, and released.
- */
-
-int udf_write_inode(struct inode * inode, int sync)
+int udf_write_inode(struct inode *inode, struct writeback_control *wbc)
{
- int ret;
- lock_kernel();
- ret = udf_update_inode(inode, sync);
- unlock_kernel();
- return ret;
+ return udf_update_inode(inode, wbc->sync_mode == WB_SYNC_ALL);
}
-int udf_sync_inode(struct inode * inode)
+static int udf_sync_inode(struct inode *inode)
{
return udf_update_inode(inode, 1);
}
-static int
-udf_update_inode(struct inode *inode, int do_sync)
+static int udf_update_inode(struct inode *inode, int do_sync)
{
struct buffer_head *bh = NULL;
struct fileEntry *fe;
struct extendedFileEntry *efe;
+ uint64_t lb_recorded;
uint32_t udfperms;
uint16_t icbflags;
uint16_t crclen;
- int i;
- kernel_timestamp cpu_time;
int err = 0;
-
- bh = udf_tread(inode->i_sb,
- udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0));
-
- if (!bh)
- {
- udf_debug("bread failure\n");
- return -EIO;
+ struct udf_sb_info *sbi = UDF_SB(inode->i_sb);
+ unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits;
+ struct udf_inode_info *iinfo = UDF_I(inode);
+
+ bh = udf_tgetblk(inode->i_sb,
+ udf_get_lb_pblock(inode->i_sb, &iinfo->i_location, 0));
+ if (!bh) {
+ udf_debug("getblk failure\n");
+ return -ENOMEM;
}
- memset(bh->b_data, 0x00, inode->i_sb->s_blocksize);
-
+ lock_buffer(bh);
+ memset(bh->b_data, 0, inode->i_sb->s_blocksize);
fe = (struct fileEntry *)bh->b_data;
efe = (struct extendedFileEntry *)bh->b_data;
- if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_USE)
- {
+ if (iinfo->i_use) {
struct unallocSpaceEntry *use =
(struct unallocSpaceEntry *)bh->b_data;
- use->lengthAllocDescs = cpu_to_le32(UDF_I_LENALLOC(inode));
- memcpy(bh->b_data + sizeof(struct unallocSpaceEntry), UDF_I_DATA(inode), inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry));
- crclen = sizeof(struct unallocSpaceEntry) + UDF_I_LENALLOC(inode) -
- sizeof(tag);
- use->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum);
+ use->lengthAllocDescs = cpu_to_le32(iinfo->i_lenAlloc);
+ memcpy(bh->b_data + sizeof(struct unallocSpaceEntry),
+ iinfo->i_ext.i_data, inode->i_sb->s_blocksize -
+ sizeof(struct unallocSpaceEntry));
+ use->descTag.tagIdent = cpu_to_le16(TAG_IDENT_USE);
+ use->descTag.tagLocation =
+ cpu_to_le32(iinfo->i_location.logicalBlockNum);
+ crclen = sizeof(struct unallocSpaceEntry) +
+ iinfo->i_lenAlloc - sizeof(struct tag);
use->descTag.descCRCLength = cpu_to_le16(crclen);
- use->descTag.descCRC = cpu_to_le16(udf_crc((char *)use + sizeof(tag), crclen, 0));
-
- use->descTag.tagChecksum = 0;
- for (i=0; i<16; i++)
- if (i != 4)
- use->descTag.tagChecksum += ((uint8_t *)&(use->descTag))[i];
+ use->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)use +
+ sizeof(struct tag),
+ crclen));
+ use->descTag.tagChecksum = udf_tag_checksum(&use->descTag);
- mark_buffer_dirty(bh);
- udf_release_data(bh);
- return err;
+ goto out;
}
- if (inode->i_uid != UDF_SB(inode->i_sb)->s_uid)
- fe->uid = cpu_to_le32(inode->i_uid);
+ if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_FORGET))
+ fe->uid = cpu_to_le32(-1);
+ else
+ fe->uid = cpu_to_le32(i_uid_read(inode));
- if (inode->i_gid != UDF_SB(inode->i_sb)->s_gid)
- fe->gid = cpu_to_le32(inode->i_gid);
+ if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_GID_FORGET))
+ fe->gid = cpu_to_le32(-1);
+ else
+ fe->gid = cpu_to_le32(i_gid_read(inode));
- udfperms = ((inode->i_mode & S_IRWXO) ) |
- ((inode->i_mode & S_IRWXG) << 2) |
- ((inode->i_mode & S_IRWXU) << 4);
+ udfperms = ((inode->i_mode & S_IRWXO)) |
+ ((inode->i_mode & S_IRWXG) << 2) |
+ ((inode->i_mode & S_IRWXU) << 4);
- udfperms |= (le32_to_cpu(fe->permissions) &
- (FE_PERM_O_DELETE | FE_PERM_O_CHATTR |
- FE_PERM_G_DELETE | FE_PERM_G_CHATTR |
- FE_PERM_U_DELETE | FE_PERM_U_CHATTR));
+ udfperms |= (le32_to_cpu(fe->permissions) &
+ (FE_PERM_O_DELETE | FE_PERM_O_CHATTR |
+ FE_PERM_G_DELETE | FE_PERM_G_CHATTR |
+ FE_PERM_U_DELETE | FE_PERM_U_CHATTR));
fe->permissions = cpu_to_le32(udfperms);
if (S_ISDIR(inode->i_mode))
@@ -1363,27 +1671,24 @@ udf_update_inode(struct inode *inode, int do_sync)
fe->informationLength = cpu_to_le64(inode->i_size);
- if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
- {
- regid *eid;
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
+ struct regid *eid;
struct deviceSpec *dsea =
- (struct deviceSpec *)
- udf_get_extendedattr(inode, 12, 1);
-
- if (!dsea)
- {
+ (struct deviceSpec *)udf_get_extendedattr(inode, 12, 1);
+ if (!dsea) {
dsea = (struct deviceSpec *)
udf_add_extendedattr(inode,
- sizeof(struct deviceSpec) +
- sizeof(regid), 12, 0x3);
+ sizeof(struct deviceSpec) +
+ sizeof(struct regid), 12, 0x3);
dsea->attrType = cpu_to_le32(12);
dsea->attrSubtype = 1;
- dsea->attrLength = cpu_to_le32(sizeof(struct deviceSpec) +
- sizeof(regid));
- dsea->impUseLength = cpu_to_le32(sizeof(regid));
+ dsea->attrLength = cpu_to_le32(
+ sizeof(struct deviceSpec) +
+ sizeof(struct regid));
+ dsea->impUseLength = cpu_to_le32(sizeof(struct regid));
}
- eid = (regid *)dsea->impUse;
- memset(eid, 0, sizeof(regid));
+ eid = (struct regid *)dsea->impUse;
+ memset(eid, 0, sizeof(struct regid));
strcpy(eid->ident, UDF_ID_DEVELOPER);
eid->identSuffix[0] = UDF_OS_CLASS_UNIX;
eid->identSuffix[1] = UDF_OS_ID_LINUX;
@@ -1391,83 +1696,76 @@ udf_update_inode(struct inode *inode, int do_sync)
dsea->minorDeviceIdent = cpu_to_le32(iminor(inode));
}
- if (UDF_I_EFE(inode) == 0)
- {
- memcpy(bh->b_data + sizeof(struct fileEntry), UDF_I_DATA(inode), inode->i_sb->s_blocksize - sizeof(struct fileEntry));
- fe->logicalBlocksRecorded = cpu_to_le64(
- (inode->i_blocks + (1 << (inode->i_sb->s_blocksize_bits - 9)) - 1) >>
- (inode->i_sb->s_blocksize_bits - 9));
-
- if (udf_time_to_stamp(&cpu_time, inode->i_atime))
- fe->accessTime = cpu_to_lets(cpu_time);
- if (udf_time_to_stamp(&cpu_time, inode->i_mtime))
- fe->modificationTime = cpu_to_lets(cpu_time);
- if (udf_time_to_stamp(&cpu_time, inode->i_ctime))
- fe->attrTime = cpu_to_lets(cpu_time);
- memset(&(fe->impIdent), 0, sizeof(regid));
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
+ lb_recorded = 0; /* No extents => no blocks! */
+ else
+ lb_recorded =
+ (inode->i_blocks + (1 << (blocksize_bits - 9)) - 1) >>
+ (blocksize_bits - 9);
+
+ if (iinfo->i_efe == 0) {
+ memcpy(bh->b_data + sizeof(struct fileEntry),
+ iinfo->i_ext.i_data,
+ inode->i_sb->s_blocksize - sizeof(struct fileEntry));
+ fe->logicalBlocksRecorded = cpu_to_le64(lb_recorded);
+
+ udf_time_to_disk_stamp(&fe->accessTime, inode->i_atime);
+ udf_time_to_disk_stamp(&fe->modificationTime, inode->i_mtime);
+ udf_time_to_disk_stamp(&fe->attrTime, inode->i_ctime);
+ memset(&(fe->impIdent), 0, sizeof(struct regid));
strcpy(fe->impIdent.ident, UDF_ID_DEVELOPER);
fe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
fe->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
- fe->uniqueID = cpu_to_le64(UDF_I_UNIQUE(inode));
- fe->lengthExtendedAttr = cpu_to_le32(UDF_I_LENEATTR(inode));
- fe->lengthAllocDescs = cpu_to_le32(UDF_I_LENALLOC(inode));
+ fe->uniqueID = cpu_to_le64(iinfo->i_unique);
+ fe->lengthExtendedAttr = cpu_to_le32(iinfo->i_lenEAttr);
+ fe->lengthAllocDescs = cpu_to_le32(iinfo->i_lenAlloc);
+ fe->checkpoint = cpu_to_le32(iinfo->i_checkpoint);
fe->descTag.tagIdent = cpu_to_le16(TAG_IDENT_FE);
crclen = sizeof(struct fileEntry);
- }
- else
- {
- memcpy(bh->b_data + sizeof(struct extendedFileEntry), UDF_I_DATA(inode), inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry));
+ } else {
+ memcpy(bh->b_data + sizeof(struct extendedFileEntry),
+ iinfo->i_ext.i_data,
+ inode->i_sb->s_blocksize -
+ sizeof(struct extendedFileEntry));
efe->objectSize = cpu_to_le64(inode->i_size);
- efe->logicalBlocksRecorded = cpu_to_le64(
- (inode->i_blocks + (1 << (inode->i_sb->s_blocksize_bits - 9)) - 1) >>
- (inode->i_sb->s_blocksize_bits - 9));
-
- if (UDF_I_CRTIME(inode).tv_sec > inode->i_atime.tv_sec ||
- (UDF_I_CRTIME(inode).tv_sec == inode->i_atime.tv_sec &&
- UDF_I_CRTIME(inode).tv_nsec > inode->i_atime.tv_nsec))
- {
- UDF_I_CRTIME(inode) = inode->i_atime;
- }
- if (UDF_I_CRTIME(inode).tv_sec > inode->i_mtime.tv_sec ||
- (UDF_I_CRTIME(inode).tv_sec == inode->i_mtime.tv_sec &&
- UDF_I_CRTIME(inode).tv_nsec > inode->i_mtime.tv_nsec))
- {
- UDF_I_CRTIME(inode) = inode->i_mtime;
- }
- if (UDF_I_CRTIME(inode).tv_sec > inode->i_ctime.tv_sec ||
- (UDF_I_CRTIME(inode).tv_sec == inode->i_ctime.tv_sec &&
- UDF_I_CRTIME(inode).tv_nsec > inode->i_ctime.tv_nsec))
- {
- UDF_I_CRTIME(inode) = inode->i_ctime;
- }
+ efe->logicalBlocksRecorded = cpu_to_le64(lb_recorded);
+
+ if (iinfo->i_crtime.tv_sec > inode->i_atime.tv_sec ||
+ (iinfo->i_crtime.tv_sec == inode->i_atime.tv_sec &&
+ iinfo->i_crtime.tv_nsec > inode->i_atime.tv_nsec))
+ iinfo->i_crtime = inode->i_atime;
+
+ if (iinfo->i_crtime.tv_sec > inode->i_mtime.tv_sec ||
+ (iinfo->i_crtime.tv_sec == inode->i_mtime.tv_sec &&
+ iinfo->i_crtime.tv_nsec > inode->i_mtime.tv_nsec))
+ iinfo->i_crtime = inode->i_mtime;
- if (udf_time_to_stamp(&cpu_time, inode->i_atime))
- efe->accessTime = cpu_to_lets(cpu_time);
- if (udf_time_to_stamp(&cpu_time, inode->i_mtime))
- efe->modificationTime = cpu_to_lets(cpu_time);
- if (udf_time_to_stamp(&cpu_time, UDF_I_CRTIME(inode)))
- efe->createTime = cpu_to_lets(cpu_time);
- if (udf_time_to_stamp(&cpu_time, inode->i_ctime))
- efe->attrTime = cpu_to_lets(cpu_time);
+ if (iinfo->i_crtime.tv_sec > inode->i_ctime.tv_sec ||
+ (iinfo->i_crtime.tv_sec == inode->i_ctime.tv_sec &&
+ iinfo->i_crtime.tv_nsec > inode->i_ctime.tv_nsec))
+ iinfo->i_crtime = inode->i_ctime;
- memset(&(efe->impIdent), 0, sizeof(regid));
+ udf_time_to_disk_stamp(&efe->accessTime, inode->i_atime);
+ udf_time_to_disk_stamp(&efe->modificationTime, inode->i_mtime);
+ udf_time_to_disk_stamp(&efe->createTime, iinfo->i_crtime);
+ udf_time_to_disk_stamp(&efe->attrTime, inode->i_ctime);
+
+ memset(&(efe->impIdent), 0, sizeof(struct regid));
strcpy(efe->impIdent.ident, UDF_ID_DEVELOPER);
efe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
efe->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
- efe->uniqueID = cpu_to_le64(UDF_I_UNIQUE(inode));
- efe->lengthExtendedAttr = cpu_to_le32(UDF_I_LENEATTR(inode));
- efe->lengthAllocDescs = cpu_to_le32(UDF_I_LENALLOC(inode));
+ efe->uniqueID = cpu_to_le64(iinfo->i_unique);
+ efe->lengthExtendedAttr = cpu_to_le32(iinfo->i_lenEAttr);
+ efe->lengthAllocDescs = cpu_to_le32(iinfo->i_lenAlloc);
+ efe->checkpoint = cpu_to_le32(iinfo->i_checkpoint);
efe->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EFE);
crclen = sizeof(struct extendedFileEntry);
}
- if (UDF_I_STRAT4096(inode))
- {
+ if (iinfo->i_strat4096) {
fe->icbTag.strategyType = cpu_to_le16(4096);
fe->icbTag.strategyParameter = cpu_to_le16(1);
fe->icbTag.numEntries = cpu_to_le16(2);
- }
- else
- {
+ } else {
fe->icbTag.strategyType = cpu_to_le16(4);
fe->icbTag.numEntries = cpu_to_le16(1);
}
@@ -1487,7 +1785,7 @@ udf_update_inode(struct inode *inode, int do_sync)
else if (S_ISSOCK(inode->i_mode))
fe->icbTag.fileType = ICBTAG_FILE_TYPE_SOCKET;
- icbflags = UDF_I_ALLOCTYPE(inode) |
+ icbflags = iinfo->i_alloc_type |
((inode->i_mode & S_ISUID) ? ICBTAG_FLAG_SETUID : 0) |
((inode->i_mode & S_ISGID) ? ICBTAG_FLAG_SETGID : 0) |
((inode->i_mode & S_ISVTX) ? ICBTAG_FLAG_STICKY : 0) |
@@ -1496,39 +1794,39 @@ udf_update_inode(struct inode *inode, int do_sync)
ICBTAG_FLAG_SETGID | ICBTAG_FLAG_STICKY));
fe->icbTag.flags = cpu_to_le16(icbflags);
- if (UDF_SB_UDFREV(inode->i_sb) >= 0x0200)
+ if (sbi->s_udfrev >= 0x0200)
fe->descTag.descVersion = cpu_to_le16(3);
else
fe->descTag.descVersion = cpu_to_le16(2);
- fe->descTag.tagSerialNum = cpu_to_le16(UDF_SB_SERIALNUM(inode->i_sb));
- fe->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum);
- crclen += UDF_I_LENEATTR(inode) + UDF_I_LENALLOC(inode) - sizeof(tag);
+ fe->descTag.tagSerialNum = cpu_to_le16(sbi->s_serial_number);
+ fe->descTag.tagLocation = cpu_to_le32(
+ iinfo->i_location.logicalBlockNum);
+ crclen += iinfo->i_lenEAttr + iinfo->i_lenAlloc - sizeof(struct tag);
fe->descTag.descCRCLength = cpu_to_le16(crclen);
- fe->descTag.descCRC = cpu_to_le16(udf_crc((char *)fe + sizeof(tag), crclen, 0));
+ fe->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)fe + sizeof(struct tag),
+ crclen));
+ fe->descTag.tagChecksum = udf_tag_checksum(&fe->descTag);
- fe->descTag.tagChecksum = 0;
- for (i=0; i<16; i++)
- if (i != 4)
- fe->descTag.tagChecksum += ((uint8_t *)&(fe->descTag))[i];
+out:
+ set_buffer_uptodate(bh);
+ unlock_buffer(bh);
/* write the data blocks */
mark_buffer_dirty(bh);
- if (do_sync)
- {
+ if (do_sync) {
sync_dirty_buffer(bh);
- if (buffer_req(bh) && !buffer_uptodate(bh))
- {
- printk("IO error syncing udf inode [%s:%08lx]\n",
- inode->i_sb->s_id, inode->i_ino);
+ if (buffer_write_io_error(bh)) {
+ udf_warn(inode->i_sb, "IO error syncing udf inode [%08lx]\n",
+ inode->i_ino);
err = -EIO;
}
}
- udf_release_data(bh);
+ brelse(bh);
+
return err;
}
-struct inode *
-udf_iget(struct super_block *sb, kernel_lb_addr ino)
+struct inode *udf_iget(struct super_block *sb, struct kernel_lb_addr *ino)
{
unsigned long block = udf_get_lb_pblock(sb, ino, 0);
struct inode *inode = iget_locked(sb, block);
@@ -1537,7 +1835,7 @@ udf_iget(struct super_block *sb, kernel_lb_addr ino)
return NULL;
if (inode->i_state & I_NEW) {
- memcpy(&UDF_I_LOCATION(inode), &ino, sizeof(kernel_lb_addr));
+ memcpy(&UDF_I(inode)->i_location, ino, sizeof(struct kernel_lb_addr));
__udf_read_inode(inode);
unlock_new_inode(inode);
}
@@ -1545,9 +1843,10 @@ udf_iget(struct super_block *sb, kernel_lb_addr ino)
if (is_bad_inode(inode))
goto out_iput;
- if (ino.logicalBlockNum >= UDF_SB_PARTLEN(sb, ino.partitionReferenceNum)) {
+ if (ino->logicalBlockNum >= UDF_SB(sb)->
+ s_partmaps[ino->partitionReferenceNum].s_partition_len) {
udf_debug("block=%d, partition=%d out of range\n",
- ino.logicalBlockNum, ino.partitionReferenceNum);
+ ino->logicalBlockNum, ino->partitionReferenceNum);
make_bad_inode(inode);
goto out_iput;
}
@@ -1559,45 +1858,46 @@ udf_iget(struct super_block *sb, kernel_lb_addr ino)
return NULL;
}
-int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,
- kernel_lb_addr eloc, uint32_t elen, struct buffer_head **bh, int inc)
+int udf_add_aext(struct inode *inode, struct extent_position *epos,
+ struct kernel_lb_addr *eloc, uint32_t elen, int inc)
{
int adsize;
- short_ad *sad = NULL;
- long_ad *lad = NULL;
+ struct short_ad *sad = NULL;
+ struct long_ad *lad = NULL;
struct allocExtDesc *aed;
- int8_t etype;
uint8_t *ptr;
+ struct udf_inode_info *iinfo = UDF_I(inode);
- if (!*bh)
- ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
+ if (!epos->bh)
+ ptr = iinfo->i_ext.i_data + epos->offset -
+ udf_file_entry_alloc_offset(inode) +
+ iinfo->i_lenEAttr;
else
- ptr = (*bh)->b_data + *extoffset;
+ ptr = epos->bh->b_data + epos->offset;
- if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
- adsize = sizeof(short_ad);
- else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG)
- adsize = sizeof(long_ad);
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+ adsize = sizeof(struct short_ad);
+ else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+ adsize = sizeof(struct long_ad);
else
- return -1;
+ return -EIO;
- if (*extoffset + (2 * adsize) > inode->i_sb->s_blocksize)
- {
- char *sptr, *dptr;
+ if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize) {
+ unsigned char *sptr, *dptr;
struct buffer_head *nbh;
int err, loffset;
- kernel_lb_addr obloc = *bloc;
-
- if (!(bloc->logicalBlockNum = udf_new_block(inode->i_sb, NULL,
- obloc.partitionReferenceNum, obloc.logicalBlockNum, &err)))
- {
- return -1;
- }
- if (!(nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb,
- *bloc, 0))))
- {
- return -1;
- }
+ struct kernel_lb_addr obloc = epos->block;
+
+ epos->block.logicalBlockNum = udf_new_block(inode->i_sb, NULL,
+ obloc.partitionReferenceNum,
+ obloc.logicalBlockNum, &err);
+ if (!epos->block.logicalBlockNum)
+ return -ENOSPC;
+ nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb,
+ &epos->block,
+ 0));
+ if (!nbh)
+ return -EIO;
lock_buffer(nbh);
memset(nbh->b_data, 0x00, inode->i_sb->s_blocksize);
set_buffer_uptodate(nbh);
@@ -1606,170 +1906,154 @@ int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,
aed = (struct allocExtDesc *)(nbh->b_data);
if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))
- aed->previousAllocExtLocation = cpu_to_le32(obloc.logicalBlockNum);
- if (*extoffset + adsize > inode->i_sb->s_blocksize)
- {
- loffset = *extoffset;
+ aed->previousAllocExtLocation =
+ cpu_to_le32(obloc.logicalBlockNum);
+ if (epos->offset + adsize > inode->i_sb->s_blocksize) {
+ loffset = epos->offset;
aed->lengthAllocDescs = cpu_to_le32(adsize);
sptr = ptr - adsize;
dptr = nbh->b_data + sizeof(struct allocExtDesc);
memcpy(dptr, sptr, adsize);
- *extoffset = sizeof(struct allocExtDesc) + adsize;
- }
- else
- {
- loffset = *extoffset + adsize;
+ epos->offset = sizeof(struct allocExtDesc) + adsize;
+ } else {
+ loffset = epos->offset + adsize;
aed->lengthAllocDescs = cpu_to_le32(0);
sptr = ptr;
- *extoffset = sizeof(struct allocExtDesc);
+ epos->offset = sizeof(struct allocExtDesc);
- if (*bh)
- {
- aed = (struct allocExtDesc *)(*bh)->b_data;
- aed->lengthAllocDescs =
- cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
- }
- else
- {
- UDF_I_LENALLOC(inode) += adsize;
+ if (epos->bh) {
+ aed = (struct allocExtDesc *)epos->bh->b_data;
+ le32_add_cpu(&aed->lengthAllocDescs, adsize);
+ } else {
+ iinfo->i_lenAlloc += adsize;
mark_inode_dirty(inode);
}
}
- if (UDF_SB_UDFREV(inode->i_sb) >= 0x0200)
+ if (UDF_SB(inode->i_sb)->s_udfrev >= 0x0200)
udf_new_tag(nbh->b_data, TAG_IDENT_AED, 3, 1,
- bloc->logicalBlockNum, sizeof(tag));
+ epos->block.logicalBlockNum, sizeof(struct tag));
else
udf_new_tag(nbh->b_data, TAG_IDENT_AED, 2, 1,
- bloc->logicalBlockNum, sizeof(tag));
- switch (UDF_I_ALLOCTYPE(inode))
- {
- case ICBTAG_FLAG_AD_SHORT:
- {
- sad = (short_ad *)sptr;
- sad->extLength = cpu_to_le32(
- EXT_NEXT_EXTENT_ALLOCDECS |
- inode->i_sb->s_blocksize);
- sad->extPosition = cpu_to_le32(bloc->logicalBlockNum);
- break;
- }
- case ICBTAG_FLAG_AD_LONG:
- {
- lad = (long_ad *)sptr;
- lad->extLength = cpu_to_le32(
- EXT_NEXT_EXTENT_ALLOCDECS |
- inode->i_sb->s_blocksize);
- lad->extLocation = cpu_to_lelb(*bloc);
- memset(lad->impUse, 0x00, sizeof(lad->impUse));
- break;
- }
+ epos->block.logicalBlockNum, sizeof(struct tag));
+ switch (iinfo->i_alloc_type) {
+ case ICBTAG_FLAG_AD_SHORT:
+ sad = (struct short_ad *)sptr;
+ sad->extLength = cpu_to_le32(EXT_NEXT_EXTENT_ALLOCDECS |
+ inode->i_sb->s_blocksize);
+ sad->extPosition =
+ cpu_to_le32(epos->block.logicalBlockNum);
+ break;
+ case ICBTAG_FLAG_AD_LONG:
+ lad = (struct long_ad *)sptr;
+ lad->extLength = cpu_to_le32(EXT_NEXT_EXTENT_ALLOCDECS |
+ inode->i_sb->s_blocksize);
+ lad->extLocation = cpu_to_lelb(epos->block);
+ memset(lad->impUse, 0x00, sizeof(lad->impUse));
+ break;
}
- if (*bh)
- {
- if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
- udf_update_tag((*bh)->b_data, loffset);
+ if (epos->bh) {
+ if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
+ UDF_SB(inode->i_sb)->s_udfrev >= 0x0201)
+ udf_update_tag(epos->bh->b_data, loffset);
else
- udf_update_tag((*bh)->b_data, sizeof(struct allocExtDesc));
- mark_buffer_dirty_inode(*bh, inode);
- udf_release_data(*bh);
- }
- else
+ udf_update_tag(epos->bh->b_data,
+ sizeof(struct allocExtDesc));
+ mark_buffer_dirty_inode(epos->bh, inode);
+ brelse(epos->bh);
+ } else {
mark_inode_dirty(inode);
- *bh = nbh;
+ }
+ epos->bh = nbh;
}
- etype = udf_write_aext(inode, *bloc, extoffset, eloc, elen, *bh, inc);
+ udf_write_aext(inode, epos, eloc, elen, inc);
- if (!*bh)
- {
- UDF_I_LENALLOC(inode) += adsize;
+ if (!epos->bh) {
+ iinfo->i_lenAlloc += adsize;
mark_inode_dirty(inode);
- }
- else
- {
- aed = (struct allocExtDesc *)(*bh)->b_data;
- aed->lengthAllocDescs =
- cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
- if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
- udf_update_tag((*bh)->b_data, *extoffset + (inc ? 0 : adsize));
+ } else {
+ aed = (struct allocExtDesc *)epos->bh->b_data;
+ le32_add_cpu(&aed->lengthAllocDescs, adsize);
+ if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
+ UDF_SB(inode->i_sb)->s_udfrev >= 0x0201)
+ udf_update_tag(epos->bh->b_data,
+ epos->offset + (inc ? 0 : adsize));
else
- udf_update_tag((*bh)->b_data, sizeof(struct allocExtDesc));
- mark_buffer_dirty_inode(*bh, inode);
+ udf_update_tag(epos->bh->b_data,
+ sizeof(struct allocExtDesc));
+ mark_buffer_dirty_inode(epos->bh, inode);
}
- return etype;
+ return 0;
}
-int8_t udf_write_aext(struct inode *inode, kernel_lb_addr bloc, int *extoffset,
- kernel_lb_addr eloc, uint32_t elen, struct buffer_head *bh, int inc)
+void udf_write_aext(struct inode *inode, struct extent_position *epos,
+ struct kernel_lb_addr *eloc, uint32_t elen, int inc)
{
int adsize;
uint8_t *ptr;
-
- if (!bh)
- ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
+ struct short_ad *sad;
+ struct long_ad *lad;
+ struct udf_inode_info *iinfo = UDF_I(inode);
+
+ if (!epos->bh)
+ ptr = iinfo->i_ext.i_data + epos->offset -
+ udf_file_entry_alloc_offset(inode) +
+ iinfo->i_lenEAttr;
else
- {
- ptr = bh->b_data + *extoffset;
- atomic_inc(&bh->b_count);
- }
-
- switch (UDF_I_ALLOCTYPE(inode))
- {
- case ICBTAG_FLAG_AD_SHORT:
- {
- short_ad *sad = (short_ad *)ptr;
- sad->extLength = cpu_to_le32(elen);
- sad->extPosition = cpu_to_le32(eloc.logicalBlockNum);
- adsize = sizeof(short_ad);
- break;
- }
- case ICBTAG_FLAG_AD_LONG:
- {
- long_ad *lad = (long_ad *)ptr;
- lad->extLength = cpu_to_le32(elen);
- lad->extLocation = cpu_to_lelb(eloc);
- memset(lad->impUse, 0x00, sizeof(lad->impUse));
- adsize = sizeof(long_ad);
- break;
- }
- default:
- return -1;
+ ptr = epos->bh->b_data + epos->offset;
+
+ switch (iinfo->i_alloc_type) {
+ case ICBTAG_FLAG_AD_SHORT:
+ sad = (struct short_ad *)ptr;
+ sad->extLength = cpu_to_le32(elen);
+ sad->extPosition = cpu_to_le32(eloc->logicalBlockNum);
+ adsize = sizeof(struct short_ad);
+ break;
+ case ICBTAG_FLAG_AD_LONG:
+ lad = (struct long_ad *)ptr;
+ lad->extLength = cpu_to_le32(elen);
+ lad->extLocation = cpu_to_lelb(*eloc);
+ memset(lad->impUse, 0x00, sizeof(lad->impUse));
+ adsize = sizeof(struct long_ad);
+ break;
+ default:
+ return;
}
- if (bh)
- {
- if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
- {
- struct allocExtDesc *aed = (struct allocExtDesc *)(bh)->b_data;
- udf_update_tag((bh)->b_data,
- le32_to_cpu(aed->lengthAllocDescs) + sizeof(struct allocExtDesc));
- }
- mark_buffer_dirty_inode(bh, inode);
- udf_release_data(bh);
- }
- else
+ if (epos->bh) {
+ if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
+ UDF_SB(inode->i_sb)->s_udfrev >= 0x0201) {
+ struct allocExtDesc *aed =
+ (struct allocExtDesc *)epos->bh->b_data;
+ udf_update_tag(epos->bh->b_data,
+ le32_to_cpu(aed->lengthAllocDescs) +
+ sizeof(struct allocExtDesc));
+ }
+ mark_buffer_dirty_inode(epos->bh, inode);
+ } else {
mark_inode_dirty(inode);
+ }
if (inc)
- *extoffset += adsize;
- return (elen >> 30);
+ epos->offset += adsize;
}
-int8_t udf_next_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,
- kernel_lb_addr *eloc, uint32_t *elen, struct buffer_head **bh, int inc)
+int8_t udf_next_aext(struct inode *inode, struct extent_position *epos,
+ struct kernel_lb_addr *eloc, uint32_t *elen, int inc)
{
int8_t etype;
- while ((etype = udf_current_aext(inode, bloc, extoffset, eloc, elen, bh, inc)) ==
- (EXT_NEXT_EXTENT_ALLOCDECS >> 30))
- {
- *bloc = *eloc;
- *extoffset = sizeof(struct allocExtDesc);
- udf_release_data(*bh);
- if (!(*bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, *bloc, 0))))
- {
- udf_debug("reading block %d failed!\n",
- udf_get_lb_pblock(inode->i_sb, *bloc, 0));
+ while ((etype = udf_current_aext(inode, epos, eloc, elen, inc)) ==
+ (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) {
+ int block;
+ epos->block = *eloc;
+ epos->offset = sizeof(struct allocExtDesc);
+ brelse(epos->bh);
+ block = udf_get_lb_pblock(inode->i_sb, &epos->block, 0);
+ epos->bh = udf_tread(inode->i_sb, block);
+ if (!epos->bh) {
+ udf_debug("reading block %d failed!\n", block);
return -1;
}
}
@@ -1777,233 +2061,215 @@ int8_t udf_next_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,
return etype;
}
-int8_t udf_current_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,
- kernel_lb_addr *eloc, uint32_t *elen, struct buffer_head **bh, int inc)
+int8_t udf_current_aext(struct inode *inode, struct extent_position *epos,
+ struct kernel_lb_addr *eloc, uint32_t *elen, int inc)
{
int alen;
int8_t etype;
uint8_t *ptr;
-
- if (!*bh)
- {
- if (!(*extoffset))
- *extoffset = udf_file_entry_alloc_offset(inode);
- ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
- alen = udf_file_entry_alloc_offset(inode) + UDF_I_LENALLOC(inode);
+ struct short_ad *sad;
+ struct long_ad *lad;
+ struct udf_inode_info *iinfo = UDF_I(inode);
+
+ if (!epos->bh) {
+ if (!epos->offset)
+ epos->offset = udf_file_entry_alloc_offset(inode);
+ ptr = iinfo->i_ext.i_data + epos->offset -
+ udf_file_entry_alloc_offset(inode) +
+ iinfo->i_lenEAttr;
+ alen = udf_file_entry_alloc_offset(inode) +
+ iinfo->i_lenAlloc;
+ } else {
+ if (!epos->offset)
+ epos->offset = sizeof(struct allocExtDesc);
+ ptr = epos->bh->b_data + epos->offset;
+ alen = sizeof(struct allocExtDesc) +
+ le32_to_cpu(((struct allocExtDesc *)epos->bh->b_data)->
+ lengthAllocDescs);
}
- else
- {
- if (!(*extoffset))
- *extoffset = sizeof(struct allocExtDesc);
- ptr = (*bh)->b_data + *extoffset;
- alen = sizeof(struct allocExtDesc) + le32_to_cpu(((struct allocExtDesc *)(*bh)->b_data)->lengthAllocDescs);
- }
-
- switch (UDF_I_ALLOCTYPE(inode))
- {
- case ICBTAG_FLAG_AD_SHORT:
- {
- short_ad *sad;
- if (!(sad = udf_get_fileshortad(ptr, alen, extoffset, inc)))
- return -1;
-
- etype = le32_to_cpu(sad->extLength) >> 30;
- eloc->logicalBlockNum = le32_to_cpu(sad->extPosition);
- eloc->partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
- *elen = le32_to_cpu(sad->extLength) & UDF_EXTENT_LENGTH_MASK;
- break;
- }
- case ICBTAG_FLAG_AD_LONG:
- {
- long_ad *lad;
-
- if (!(lad = udf_get_filelongad(ptr, alen, extoffset, inc)))
- return -1;
-
- etype = le32_to_cpu(lad->extLength) >> 30;
- *eloc = lelb_to_cpu(lad->extLocation);
- *elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK;
- break;
- }
- default:
- {
- udf_debug("alloc_type = %d unsupported\n", UDF_I_ALLOCTYPE(inode));
+ switch (iinfo->i_alloc_type) {
+ case ICBTAG_FLAG_AD_SHORT:
+ sad = udf_get_fileshortad(ptr, alen, &epos->offset, inc);
+ if (!sad)
return -1;
- }
+ etype = le32_to_cpu(sad->extLength) >> 30;
+ eloc->logicalBlockNum = le32_to_cpu(sad->extPosition);
+ eloc->partitionReferenceNum =
+ iinfo->i_location.partitionReferenceNum;
+ *elen = le32_to_cpu(sad->extLength) & UDF_EXTENT_LENGTH_MASK;
+ break;
+ case ICBTAG_FLAG_AD_LONG:
+ lad = udf_get_filelongad(ptr, alen, &epos->offset, inc);
+ if (!lad)
+ return -1;
+ etype = le32_to_cpu(lad->extLength) >> 30;
+ *eloc = lelb_to_cpu(lad->extLocation);
+ *elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK;
+ break;
+ default:
+ udf_debug("alloc_type = %d unsupported\n", iinfo->i_alloc_type);
+ return -1;
}
return etype;
}
-static int8_t
-udf_insert_aext(struct inode *inode, kernel_lb_addr bloc, int extoffset,
- kernel_lb_addr neloc, uint32_t nelen, struct buffer_head *bh)
+static int8_t udf_insert_aext(struct inode *inode, struct extent_position epos,
+ struct kernel_lb_addr neloc, uint32_t nelen)
{
- kernel_lb_addr oeloc;
+ struct kernel_lb_addr oeloc;
uint32_t oelen;
int8_t etype;
- if (bh)
- atomic_inc(&bh->b_count);
-
- while ((etype = udf_next_aext(inode, &bloc, &extoffset, &oeloc, &oelen, &bh, 0)) != -1)
- {
- udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1);
+ if (epos.bh)
+ get_bh(epos.bh);
+ while ((etype = udf_next_aext(inode, &epos, &oeloc, &oelen, 0)) != -1) {
+ udf_write_aext(inode, &epos, &neloc, nelen, 1);
neloc = oeloc;
nelen = (etype << 30) | oelen;
}
- udf_add_aext(inode, &bloc, &extoffset, neloc, nelen, &bh, 1);
- udf_release_data(bh);
+ udf_add_aext(inode, &epos, &neloc, nelen, 1);
+ brelse(epos.bh);
+
return (nelen >> 30);
}
-int8_t udf_delete_aext(struct inode *inode, kernel_lb_addr nbloc, int nextoffset,
- kernel_lb_addr eloc, uint32_t elen, struct buffer_head *nbh)
+int8_t udf_delete_aext(struct inode *inode, struct extent_position epos,
+ struct kernel_lb_addr eloc, uint32_t elen)
{
- struct buffer_head *obh;
- kernel_lb_addr obloc;
- int oextoffset, adsize;
+ struct extent_position oepos;
+ int adsize;
int8_t etype;
struct allocExtDesc *aed;
+ struct udf_inode_info *iinfo;
- if (nbh)
- {
- atomic_inc(&nbh->b_count);
- atomic_inc(&nbh->b_count);
+ if (epos.bh) {
+ get_bh(epos.bh);
+ get_bh(epos.bh);
}
- if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
- adsize = sizeof(short_ad);
- else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG)
- adsize = sizeof(long_ad);
+ iinfo = UDF_I(inode);
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+ adsize = sizeof(struct short_ad);
+ else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+ adsize = sizeof(struct long_ad);
else
adsize = 0;
- obh = nbh;
- obloc = nbloc;
- oextoffset = nextoffset;
-
- if (udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1) == -1)
+ oepos = epos;
+ if (udf_next_aext(inode, &epos, &eloc, &elen, 1) == -1)
return -1;
- while ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) != -1)
- {
- udf_write_aext(inode, obloc, &oextoffset, eloc, (etype << 30) | elen, obh, 1);
- if (obh != nbh)
- {
- obloc = nbloc;
- udf_release_data(obh);
- atomic_inc(&nbh->b_count);
- obh = nbh;
- oextoffset = nextoffset - adsize;
+ while ((etype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) {
+ udf_write_aext(inode, &oepos, &eloc, (etype << 30) | elen, 1);
+ if (oepos.bh != epos.bh) {
+ oepos.block = epos.block;
+ brelse(oepos.bh);
+ get_bh(epos.bh);
+ oepos.bh = epos.bh;
+ oepos.offset = epos.offset - adsize;
}
}
- memset(&eloc, 0x00, sizeof(kernel_lb_addr));
+ memset(&eloc, 0x00, sizeof(struct kernel_lb_addr));
elen = 0;
- if (nbh != obh)
- {
- udf_free_blocks(inode->i_sb, inode, nbloc, 0, 1);
- udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1);
- udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1);
- if (!obh)
- {
- UDF_I_LENALLOC(inode) -= (adsize * 2);
+ if (epos.bh != oepos.bh) {
+ udf_free_blocks(inode->i_sb, inode, &epos.block, 0, 1);
+ udf_write_aext(inode, &oepos, &eloc, elen, 1);
+ udf_write_aext(inode, &oepos, &eloc, elen, 1);
+ if (!oepos.bh) {
+ iinfo->i_lenAlloc -= (adsize * 2);
mark_inode_dirty(inode);
- }
- else
- {
- aed = (struct allocExtDesc *)(obh)->b_data;
- aed->lengthAllocDescs =
- cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - (2*adsize));
- if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
- udf_update_tag((obh)->b_data, oextoffset - (2*adsize));
+ } else {
+ aed = (struct allocExtDesc *)oepos.bh->b_data;
+ le32_add_cpu(&aed->lengthAllocDescs, -(2 * adsize));
+ if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
+ UDF_SB(inode->i_sb)->s_udfrev >= 0x0201)
+ udf_update_tag(oepos.bh->b_data,
+ oepos.offset - (2 * adsize));
else
- udf_update_tag((obh)->b_data, sizeof(struct allocExtDesc));
- mark_buffer_dirty_inode(obh, inode);
- }
- }
- else
- {
- udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1);
- if (!obh)
- {
- UDF_I_LENALLOC(inode) -= adsize;
+ udf_update_tag(oepos.bh->b_data,
+ sizeof(struct allocExtDesc));
+ mark_buffer_dirty_inode(oepos.bh, inode);
+ }
+ } else {
+ udf_write_aext(inode, &oepos, &eloc, elen, 1);
+ if (!oepos.bh) {
+ iinfo->i_lenAlloc -= adsize;
mark_inode_dirty(inode);
- }
- else
- {
- aed = (struct allocExtDesc *)(obh)->b_data;
- aed->lengthAllocDescs =
- cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - adsize);
- if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
- udf_update_tag((obh)->b_data, oextoffset - adsize);
+ } else {
+ aed = (struct allocExtDesc *)oepos.bh->b_data;
+ le32_add_cpu(&aed->lengthAllocDescs, -adsize);
+ if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
+ UDF_SB(inode->i_sb)->s_udfrev >= 0x0201)
+ udf_update_tag(oepos.bh->b_data,
+ epos.offset - adsize);
else
- udf_update_tag((obh)->b_data, sizeof(struct allocExtDesc));
- mark_buffer_dirty_inode(obh, inode);
+ udf_update_tag(oepos.bh->b_data,
+ sizeof(struct allocExtDesc));
+ mark_buffer_dirty_inode(oepos.bh, inode);
}
}
-
- udf_release_data(nbh);
- udf_release_data(obh);
+
+ brelse(epos.bh);
+ brelse(oepos.bh);
+
return (elen >> 30);
}
-int8_t inode_bmap(struct inode *inode, int block, kernel_lb_addr *bloc, uint32_t *extoffset,
- kernel_lb_addr *eloc, uint32_t *elen, uint32_t *offset, struct buffer_head **bh)
+int8_t inode_bmap(struct inode *inode, sector_t block,
+ struct extent_position *pos, struct kernel_lb_addr *eloc,
+ uint32_t *elen, sector_t *offset)
{
- uint64_t lbcount = 0, bcount = (uint64_t)block << inode->i_sb->s_blocksize_bits;
+ unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits;
+ loff_t lbcount = 0, bcount =
+ (loff_t) block << blocksize_bits;
int8_t etype;
+ struct udf_inode_info *iinfo;
- if (block < 0)
- {
- printk(KERN_ERR "udf: inode_bmap: block < 0\n");
- return -1;
+ iinfo = UDF_I(inode);
+ if (!udf_read_extent_cache(inode, bcount, &lbcount, pos)) {
+ pos->offset = 0;
+ pos->block = iinfo->i_location;
+ pos->bh = NULL;
}
- if (!inode)
- {
- printk(KERN_ERR "udf: inode_bmap: NULL inode\n");
- return -1;
- }
-
- *extoffset = 0;
*elen = 0;
- *bloc = UDF_I_LOCATION(inode);
-
- do
- {
- if ((etype = udf_next_aext(inode, bloc, extoffset, eloc, elen, bh, 1)) == -1)
- {
- *offset = bcount - lbcount;
- UDF_I_LENEXTENTS(inode) = lbcount;
+ do {
+ etype = udf_next_aext(inode, pos, eloc, elen, 1);
+ if (etype == -1) {
+ *offset = (bcount - lbcount) >> blocksize_bits;
+ iinfo->i_lenExtents = lbcount;
return -1;
}
lbcount += *elen;
} while (lbcount <= bcount);
-
- *offset = bcount + *elen - lbcount;
+ /* update extent cache */
+ udf_update_extent_cache(inode, lbcount - *elen, pos, 1);
+ *offset = (bcount + *elen - lbcount) >> blocksize_bits;
return etype;
}
-long udf_block_map(struct inode *inode, long block)
+long udf_block_map(struct inode *inode, sector_t block)
{
- kernel_lb_addr eloc, bloc;
- uint32_t offset, extoffset, elen;
- struct buffer_head *bh = NULL;
+ struct kernel_lb_addr eloc;
+ uint32_t elen;
+ sector_t offset;
+ struct extent_position epos = {};
int ret;
- lock_kernel();
+ down_read(&UDF_I(inode)->i_data_sem);
- if (inode_bmap(inode, block, &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30))
- ret = udf_get_lb_pblock(inode->i_sb, eloc, offset >> inode->i_sb->s_blocksize_bits);
+ if (inode_bmap(inode, block, &epos, &eloc, &elen, &offset) ==
+ (EXT_RECORDED_ALLOCATED >> 30))
+ ret = udf_get_lb_pblock(inode->i_sb, &eloc, offset);
else
ret = 0;
- unlock_kernel();
- udf_release_data(bh);
+ up_read(&UDF_I(inode)->i_data_sem);
+ brelse(epos.bh);
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_VARCONV))
return udf_fixed_to_variable(ret);
diff --git a/fs/udf/lowlevel.c b/fs/udf/lowlevel.c
index 2da5087dfe0..6583fe9b064 100644
--- a/fs/udf/lowlevel.c
+++ b/fs/udf/lowlevel.c
@@ -4,11 +4,6 @@
* PURPOSE
* Low Level Device Routines for the UDF filesystem
*
- * CONTACTS
- * E-mail regarding any portion of the Linux UDF file system should be
- * directed to the development team mailing list (run by majordomo):
- * linux_udf@hpesjro.fc.hp.com
- *
* COPYRIGHT
* This file is distributed under the terms of the GNU General Public
* License (GPL). Copies of the GPL can be obtained from:
@@ -28,46 +23,41 @@
#include <linux/cdrom.h>
#include <asm/uaccess.h>
-#include <linux/udf_fs.h>
#include "udf_sb.h"
-unsigned int
-udf_get_last_session(struct super_block *sb)
+unsigned int udf_get_last_session(struct super_block *sb)
{
struct cdrom_multisession ms_info;
unsigned int vol_desc_start;
struct block_device *bdev = sb->s_bdev;
int i;
- vol_desc_start=0;
- ms_info.addr_format=CDROM_LBA;
- i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info);
-
-#define WE_OBEY_THE_WRITTEN_STANDARDS 1
+ vol_desc_start = 0;
+ ms_info.addr_format = CDROM_LBA;
+ i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long)&ms_info);
- if (i == 0)
- {
+ if (i == 0) {
udf_debug("XA disk: %s, vol_desc_start=%d\n",
- (ms_info.xa_flag ? "yes" : "no"), ms_info.addr.lba);
-#if WE_OBEY_THE_WRITTEN_STANDARDS
+ ms_info.xa_flag ? "yes" : "no", ms_info.addr.lba);
if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
-#endif
vol_desc_start = ms_info.addr.lba;
- }
- else
- {
+ } else {
udf_debug("CDROMMULTISESSION not supported: rc=%d\n", i);
}
return vol_desc_start;
}
-unsigned long
-udf_get_last_block(struct super_block *sb)
+unsigned long udf_get_last_block(struct super_block *sb)
{
struct block_device *bdev = sb->s_bdev;
unsigned long lblock = 0;
- if (ioctl_by_bdev(bdev, CDROM_LAST_WRITTEN, (unsigned long) &lblock))
+ /*
+ * ioctl failed or returned obviously bogus value?
+ * Try using the device size...
+ */
+ if (ioctl_by_bdev(bdev, CDROM_LAST_WRITTEN, (unsigned long) &lblock) ||
+ lblock == 0)
lblock = bdev->bd_inode->i_size >> sb->s_blocksize_bits;
if (lblock)
diff --git a/fs/udf/misc.c b/fs/udf/misc.c
index fd321f9ace8..c175b4dabc1 100644
--- a/fs/udf/misc.c
+++ b/fs/udf/misc.c
@@ -4,11 +4,6 @@
* PURPOSE
* Miscellaneous routines for the OSTA-UDF(tm) filesystem.
*
- * CONTACTS
- * E-mail regarding any portion of the Linux UDF file system should be
- * directed to the development team mailing list (run by majordomo):
- * linux_udf@hpesjro.fc.hp.com
- *
* COPYRIGHT
* This file is distributed under the terms of the GNU General Public
* License (GPL). Copies of the GPL can be obtained from:
@@ -28,14 +23,13 @@
#include <linux/fs.h>
#include <linux/string.h>
-#include <linux/udf_fs.h>
#include <linux/buffer_head.h>
+#include <linux/crc-itu-t.h>
#include "udf_i.h"
#include "udf_sb.h"
-struct buffer_head *
-udf_tgetblk(struct super_block *sb, int block)
+struct buffer_head *udf_tgetblk(struct super_block *sb, int block)
{
if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
return sb_getblk(sb, udf_fixed_to_variable(block));
@@ -43,8 +37,7 @@ udf_tgetblk(struct super_block *sb, int block)
return sb_getblk(sb, block);
}
-struct buffer_head *
-udf_tread(struct super_block *sb, int block)
+struct buffer_head *udf_tread(struct super_block *sb, int block)
{
if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
return sb_bread(sb, udf_fixed_to_variable(block));
@@ -52,132 +45,130 @@ udf_tread(struct super_block *sb, int block)
return sb_bread(sb, block);
}
-struct genericFormat *
-udf_add_extendedattr(struct inode * inode, uint32_t size, uint32_t type,
- uint8_t loc)
+struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size,
+ uint32_t type, uint8_t loc)
{
uint8_t *ea = NULL, *ad = NULL;
int offset;
uint16_t crclen;
- int i;
+ struct udf_inode_info *iinfo = UDF_I(inode);
- ea = UDF_I_DATA(inode);
- if (UDF_I_LENEATTR(inode))
- ad = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode);
- else
- {
+ ea = iinfo->i_ext.i_data;
+ if (iinfo->i_lenEAttr) {
+ ad = iinfo->i_ext.i_data + iinfo->i_lenEAttr;
+ } else {
ad = ea;
size += sizeof(struct extendedAttrHeaderDesc);
}
offset = inode->i_sb->s_blocksize - udf_file_entry_alloc_offset(inode) -
- UDF_I_LENALLOC(inode);
+ iinfo->i_lenAlloc;
/* TODO - Check for FreeEASpace */
- if (loc & 0x01 && offset >= size)
- {
+ if (loc & 0x01 && offset >= size) {
struct extendedAttrHeaderDesc *eahd;
eahd = (struct extendedAttrHeaderDesc *)ea;
- if (UDF_I_LENALLOC(inode))
- {
- memmove(&ad[size], ad, UDF_I_LENALLOC(inode));
- }
+ if (iinfo->i_lenAlloc)
+ memmove(&ad[size], ad, iinfo->i_lenAlloc);
- if (UDF_I_LENEATTR(inode))
- {
+ if (iinfo->i_lenEAttr) {
/* check checksum/crc */
- if (le16_to_cpu(eahd->descTag.tagIdent) != TAG_IDENT_EAHD ||
- le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
- {
+ if (eahd->descTag.tagIdent !=
+ cpu_to_le16(TAG_IDENT_EAHD) ||
+ le32_to_cpu(eahd->descTag.tagLocation) !=
+ iinfo->i_location.logicalBlockNum)
return NULL;
- }
- }
- else
- {
+ } else {
+ struct udf_sb_info *sbi = UDF_SB(inode->i_sb);
+
size -= sizeof(struct extendedAttrHeaderDesc);
- UDF_I_LENEATTR(inode) += sizeof(struct extendedAttrHeaderDesc);
+ iinfo->i_lenEAttr +=
+ sizeof(struct extendedAttrHeaderDesc);
eahd->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EAHD);
- if (UDF_SB_UDFREV(inode->i_sb) >= 0x0200)
+ if (sbi->s_udfrev >= 0x0200)
eahd->descTag.descVersion = cpu_to_le16(3);
else
eahd->descTag.descVersion = cpu_to_le16(2);
- eahd->descTag.tagSerialNum = cpu_to_le16(UDF_SB_SERIALNUM(inode->i_sb));
- eahd->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum);
+ eahd->descTag.tagSerialNum =
+ cpu_to_le16(sbi->s_serial_number);
+ eahd->descTag.tagLocation = cpu_to_le32(
+ iinfo->i_location.logicalBlockNum);
eahd->impAttrLocation = cpu_to_le32(0xFFFFFFFF);
eahd->appAttrLocation = cpu_to_le32(0xFFFFFFFF);
}
- offset = UDF_I_LENEATTR(inode);
- if (type < 2048)
- {
- if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
- {
- uint32_t aal = le32_to_cpu(eahd->appAttrLocation);
+ offset = iinfo->i_lenEAttr;
+ if (type < 2048) {
+ if (le32_to_cpu(eahd->appAttrLocation) <
+ iinfo->i_lenEAttr) {
+ uint32_t aal =
+ le32_to_cpu(eahd->appAttrLocation);
memmove(&ea[offset - aal + size],
&ea[aal], offset - aal);
offset -= aal;
- eahd->appAttrLocation = cpu_to_le32(aal + size);
+ eahd->appAttrLocation =
+ cpu_to_le32(aal + size);
}
- if (le32_to_cpu(eahd->impAttrLocation) < UDF_I_LENEATTR(inode))
- {
- uint32_t ial = le32_to_cpu(eahd->impAttrLocation);
+ if (le32_to_cpu(eahd->impAttrLocation) <
+ iinfo->i_lenEAttr) {
+ uint32_t ial =
+ le32_to_cpu(eahd->impAttrLocation);
memmove(&ea[offset - ial + size],
&ea[ial], offset - ial);
offset -= ial;
- eahd->impAttrLocation = cpu_to_le32(ial + size);
+ eahd->impAttrLocation =
+ cpu_to_le32(ial + size);
}
- }
- else if (type < 65536)
- {
- if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
- {
- uint32_t aal = le32_to_cpu(eahd->appAttrLocation);
+ } else if (type < 65536) {
+ if (le32_to_cpu(eahd->appAttrLocation) <
+ iinfo->i_lenEAttr) {
+ uint32_t aal =
+ le32_to_cpu(eahd->appAttrLocation);
memmove(&ea[offset - aal + size],
&ea[aal], offset - aal);
offset -= aal;
- eahd->appAttrLocation = cpu_to_le32(aal + size);
+ eahd->appAttrLocation =
+ cpu_to_le32(aal + size);
}
}
/* rewrite CRC + checksum of eahd */
- crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(tag);
+ crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(struct tag);
eahd->descTag.descCRCLength = cpu_to_le16(crclen);
- eahd->descTag.descCRC = cpu_to_le16(udf_crc((char *)eahd + sizeof(tag), crclen, 0));
- eahd->descTag.tagChecksum = 0;
- for (i=0; i<16; i++)
- if (i != 4)
- eahd->descTag.tagChecksum += ((uint8_t *)&(eahd->descTag))[i];
- UDF_I_LENEATTR(inode) += size;
+ eahd->descTag.descCRC = cpu_to_le16(crc_itu_t(0, (char *)eahd +
+ sizeof(struct tag), crclen));
+ eahd->descTag.tagChecksum = udf_tag_checksum(&eahd->descTag);
+ iinfo->i_lenEAttr += size;
return (struct genericFormat *)&ea[offset];
}
if (loc & 0x02)
- {
- }
+ ;
+
return NULL;
}
-struct genericFormat *
-udf_get_extendedattr(struct inode *inode, uint32_t type, uint8_t subtype)
+struct genericFormat *udf_get_extendedattr(struct inode *inode, uint32_t type,
+ uint8_t subtype)
{
struct genericFormat *gaf;
uint8_t *ea = NULL;
uint32_t offset;
+ struct udf_inode_info *iinfo = UDF_I(inode);
- ea = UDF_I_DATA(inode);
+ ea = iinfo->i_ext.i_data;
- if (UDF_I_LENEATTR(inode))
- {
+ if (iinfo->i_lenEAttr) {
struct extendedAttrHeaderDesc *eahd;
eahd = (struct extendedAttrHeaderDesc *)ea;
/* check checksum/crc */
- if (le16_to_cpu(eahd->descTag.tagIdent) != TAG_IDENT_EAHD ||
- le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
- {
+ if (eahd->descTag.tagIdent !=
+ cpu_to_le16(TAG_IDENT_EAHD) ||
+ le32_to_cpu(eahd->descTag.tagLocation) !=
+ iinfo->i_location.logicalBlockNum)
return NULL;
- }
-
+
if (type < 2048)
offset = sizeof(struct extendedAttrHeaderDesc);
else if (type < 65536)
@@ -185,15 +176,16 @@ udf_get_extendedattr(struct inode *inode, uint32_t type, uint8_t subtype)
else
offset = le32_to_cpu(eahd->appAttrLocation);
- while (offset < UDF_I_LENEATTR(inode))
- {
+ while (offset < iinfo->i_lenEAttr) {
gaf = (struct genericFormat *)&ea[offset];
- if (le32_to_cpu(gaf->attrType) == type && gaf->attrSubtype == subtype)
+ if (le32_to_cpu(gaf->attrType) == type &&
+ gaf->attrSubtype == subtype)
return gaf;
else
offset += le32_to_cpu(gaf->attrLength);
}
}
+
return NULL;
}
@@ -207,107 +199,101 @@ udf_get_extendedattr(struct inode *inode, uint32_t type, uint8_t subtype)
* July 1, 1997 - Andrew E. Mileski
* Written, tested, and released.
*/
-struct buffer_head *
-udf_read_tagged(struct super_block *sb, uint32_t block, uint32_t location, uint16_t *ident)
+struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block,
+ uint32_t location, uint16_t *ident)
{
- tag *tag_p;
+ struct tag *tag_p;
struct buffer_head *bh = NULL;
- register uint8_t checksum;
- register int i;
+ u8 checksum;
/* Read the block */
if (block == 0xFFFFFFFF)
return NULL;
- bh = udf_tread(sb, block + UDF_SB_SESSION(sb));
- if (!bh)
- {
- udf_debug("block=%d, location=%d: read failed\n", block + UDF_SB_SESSION(sb), location);
+ bh = udf_tread(sb, block);
+ if (!bh) {
+ udf_err(sb, "read failed, block=%u, location=%d\n",
+ block, location);
return NULL;
}
- tag_p = (tag *)(bh->b_data);
+ tag_p = (struct tag *)(bh->b_data);
*ident = le16_to_cpu(tag_p->tagIdent);
- if ( location != le32_to_cpu(tag_p->tagLocation) )
- {
+ if (location != le32_to_cpu(tag_p->tagLocation)) {
udf_debug("location mismatch block %u, tag %u != %u\n",
- block + UDF_SB_SESSION(sb), le32_to_cpu(tag_p->tagLocation), location);
+ block, le32_to_cpu(tag_p->tagLocation), location);
goto error_out;
}
-
+
/* Verify the tag checksum */
- checksum = 0U;
- for (i = 0; i < 4; i++)
- checksum += (uint8_t)(bh->b_data[i]);
- for (i = 5; i < 16; i++)
- checksum += (uint8_t)(bh->b_data[i]);
+ checksum = udf_tag_checksum(tag_p);
if (checksum != tag_p->tagChecksum) {
- printk(KERN_ERR "udf: tag checksum failed block %d\n", block);
+ udf_err(sb, "tag checksum failed, block %u: 0x%02x != 0x%02x\n",
+ block, checksum, tag_p->tagChecksum);
goto error_out;
}
/* Verify the tag version */
- if (le16_to_cpu(tag_p->descVersion) != 0x0002U &&
- le16_to_cpu(tag_p->descVersion) != 0x0003U)
- {
- udf_debug("tag version 0x%04x != 0x0002 || 0x0003 block %d\n",
+ if (tag_p->descVersion != cpu_to_le16(0x0002U) &&
+ tag_p->descVersion != cpu_to_le16(0x0003U)) {
+ udf_err(sb, "tag version 0x%04x != 0x0002 || 0x0003, block %u\n",
le16_to_cpu(tag_p->descVersion), block);
goto error_out;
}
/* Verify the descriptor CRC */
- if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize ||
- le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag),
- le16_to_cpu(tag_p->descCRCLength), 0))
- {
+ if (le16_to_cpu(tag_p->descCRCLength) + sizeof(struct tag) > sb->s_blocksize ||
+ le16_to_cpu(tag_p->descCRC) == crc_itu_t(0,
+ bh->b_data + sizeof(struct tag),
+ le16_to_cpu(tag_p->descCRCLength)))
return bh;
- }
- udf_debug("Crc failure block %d: crc = %d, crclen = %d\n",
- block + UDF_SB_SESSION(sb), le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength));
+ udf_debug("Crc failure block %d: crc = %d, crclen = %d\n", block,
+ le16_to_cpu(tag_p->descCRC),
+ le16_to_cpu(tag_p->descCRCLength));
error_out:
brelse(bh);
return NULL;
}
-struct buffer_head *
-udf_read_ptagged(struct super_block *sb, kernel_lb_addr loc, uint32_t offset, uint16_t *ident)
+struct buffer_head *udf_read_ptagged(struct super_block *sb,
+ struct kernel_lb_addr *loc,
+ uint32_t offset, uint16_t *ident)
{
return udf_read_tagged(sb, udf_get_lb_pblock(sb, loc, offset),
- loc.logicalBlockNum + offset, ident);
-}
-
-void udf_release_data(struct buffer_head *bh)
-{
- if (bh)
- brelse(bh);
+ loc->logicalBlockNum + offset, ident);
}
void udf_update_tag(char *data, int length)
{
- tag *tptr = (tag *)data;
- int i;
-
- length -= sizeof(tag);
+ struct tag *tptr = (struct tag *)data;
+ length -= sizeof(struct tag);
- tptr->tagChecksum = 0;
tptr->descCRCLength = cpu_to_le16(length);
- tptr->descCRC = cpu_to_le16(udf_crc(data + sizeof(tag), length, 0));
-
- for (i=0; i<16; i++)
- if (i != 4)
- tptr->tagChecksum += (uint8_t)(data[i]);
+ tptr->descCRC = cpu_to_le16(crc_itu_t(0, data + sizeof(struct tag), length));
+ tptr->tagChecksum = udf_tag_checksum(tptr);
}
void udf_new_tag(char *data, uint16_t ident, uint16_t version, uint16_t snum,
- uint32_t loc, int length)
+ uint32_t loc, int length)
{
- tag *tptr = (tag *)data;
+ struct tag *tptr = (struct tag *)data;
tptr->tagIdent = cpu_to_le16(ident);
tptr->descVersion = cpu_to_le16(version);
tptr->tagSerialNum = cpu_to_le16(snum);
tptr->tagLocation = cpu_to_le32(loc);
udf_update_tag(data, length);
}
+
+u8 udf_tag_checksum(const struct tag *t)
+{
+ u8 *data = (u8 *)t;
+ u8 checksum = 0;
+ int i;
+ for (i = 0; i < sizeof(struct tag); ++i)
+ if (i != 4) /* position of checksum */
+ checksum += data[i];
+ return checksum;
+}
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index ac191ed7df0..9737cba1357 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -4,11 +4,6 @@
* PURPOSE
* Inode name handling routines for the OSTA-UDF(tm) filesystem.
*
- * CONTACTS
- * E-mail regarding any portion of the Linux UDF file system should be
- * directed to the development team mailing list (run by majordomo):
- * linux_udf@hpesjro.fc.hp.com
- *
* COPYRIGHT
* This file is distributed under the terms of the GNU General Public
* License (GPL). Copies of the GPL can be obtained from:
@@ -32,25 +27,26 @@
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/slab.h>
-#include <linux/quotaops.h>
-#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
+#include <linux/sched.h>
+#include <linux/crc-itu-t.h>
+#include <linux/exportfs.h>
-static inline int udf_match(int len1, const char *name1, int len2, const char *name2)
+static inline int udf_match(int len1, const unsigned char *name1, int len2,
+ const unsigned char *name2)
{
if (len1 != len2)
return 0;
+
return !memcmp(name1, name2, len1);
}
int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
- struct fileIdentDesc *sfi, struct udf_fileident_bh *fibh,
- uint8_t *impuse, uint8_t *fileident)
+ struct fileIdentDesc *sfi, struct udf_fileident_bh *fibh,
+ uint8_t *impuse, uint8_t *fileident)
{
- uint16_t crclen = fibh->eoffset - fibh->soffset - sizeof(tag);
+ uint16_t crclen = fibh->eoffset - fibh->soffset - sizeof(struct tag);
uint16_t crc;
- uint8_t checksum = 0;
- int i;
int offset;
uint16_t liu = le16_to_cpu(cfi->lengthOfImpUse);
uint8_t lfi = cfi->lengthFileIdent;
@@ -58,88 +54,84 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
sizeof(struct fileIdentDesc);
int adinicb = 0;
- if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
+ if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
adinicb = 1;
offset = fibh->soffset + sizeof(struct fileIdentDesc);
- if (impuse)
- {
- if (adinicb || (offset + liu < 0))
+ if (impuse) {
+ if (adinicb || (offset + liu < 0)) {
memcpy((uint8_t *)sfi->impUse, impuse, liu);
- else if (offset >= 0)
+ } else if (offset >= 0) {
memcpy(fibh->ebh->b_data + offset, impuse, liu);
- else
- {
+ } else {
memcpy((uint8_t *)sfi->impUse, impuse, -offset);
- memcpy(fibh->ebh->b_data, impuse - offset, liu + offset);
+ memcpy(fibh->ebh->b_data, impuse - offset,
+ liu + offset);
}
}
offset += liu;
- if (fileident)
- {
- if (adinicb || (offset + lfi < 0))
+ if (fileident) {
+ if (adinicb || (offset + lfi < 0)) {
memcpy((uint8_t *)sfi->fileIdent + liu, fileident, lfi);
- else if (offset >= 0)
+ } else if (offset >= 0) {
memcpy(fibh->ebh->b_data + offset, fileident, lfi);
- else
- {
- memcpy((uint8_t *)sfi->fileIdent + liu, fileident, -offset);
- memcpy(fibh->ebh->b_data, fileident - offset, lfi + offset);
+ } else {
+ memcpy((uint8_t *)sfi->fileIdent + liu, fileident,
+ -offset);
+ memcpy(fibh->ebh->b_data, fileident - offset,
+ lfi + offset);
}
}
offset += lfi;
- if (adinicb || (offset + padlen < 0))
+ if (adinicb || (offset + padlen < 0)) {
memset((uint8_t *)sfi->padding + liu + lfi, 0x00, padlen);
- else if (offset >= 0)
+ } else if (offset >= 0) {
memset(fibh->ebh->b_data + offset, 0x00, padlen);
- else
- {
+ } else {
memset((uint8_t *)sfi->padding + liu + lfi, 0x00, -offset);
memset(fibh->ebh->b_data, 0x00, padlen + offset);
}
- crc = udf_crc((uint8_t *)cfi + sizeof(tag), sizeof(struct fileIdentDesc) -
- sizeof(tag), 0);
-
- if (fibh->sbh == fibh->ebh)
- crc = udf_crc((uint8_t *)sfi->impUse,
- crclen + sizeof(tag) - sizeof(struct fileIdentDesc), crc);
- else if (sizeof(struct fileIdentDesc) >= -fibh->soffset)
- crc = udf_crc(fibh->ebh->b_data + sizeof(struct fileIdentDesc) + fibh->soffset,
- crclen + sizeof(tag) - sizeof(struct fileIdentDesc), crc);
- else
- {
- crc = udf_crc((uint8_t *)sfi->impUse,
- -fibh->soffset - sizeof(struct fileIdentDesc), crc);
- crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc);
+ crc = crc_itu_t(0, (uint8_t *)cfi + sizeof(struct tag),
+ sizeof(struct fileIdentDesc) - sizeof(struct tag));
+
+ if (fibh->sbh == fibh->ebh) {
+ crc = crc_itu_t(crc, (uint8_t *)sfi->impUse,
+ crclen + sizeof(struct tag) -
+ sizeof(struct fileIdentDesc));
+ } else if (sizeof(struct fileIdentDesc) >= -fibh->soffset) {
+ crc = crc_itu_t(crc, fibh->ebh->b_data +
+ sizeof(struct fileIdentDesc) +
+ fibh->soffset,
+ crclen + sizeof(struct tag) -
+ sizeof(struct fileIdentDesc));
+ } else {
+ crc = crc_itu_t(crc, (uint8_t *)sfi->impUse,
+ -fibh->soffset - sizeof(struct fileIdentDesc));
+ crc = crc_itu_t(crc, fibh->ebh->b_data, fibh->eoffset);
}
cfi->descTag.descCRC = cpu_to_le16(crc);
cfi->descTag.descCRCLength = cpu_to_le16(crclen);
+ cfi->descTag.tagChecksum = udf_tag_checksum(&cfi->descTag);
- for (i=0; i<16; i++)
- if (i != 4)
- checksum += ((uint8_t *)&cfi->descTag)[i];
-
- cfi->descTag.tagChecksum = checksum;
- if (adinicb || (sizeof(struct fileIdentDesc) <= -fibh->soffset))
- memcpy((uint8_t *)sfi, (uint8_t *)cfi, sizeof(struct fileIdentDesc));
- else
- {
+ if (adinicb || (sizeof(struct fileIdentDesc) <= -fibh->soffset)) {
+ memcpy((uint8_t *)sfi, (uint8_t *)cfi,
+ sizeof(struct fileIdentDesc));
+ } else {
memcpy((uint8_t *)sfi, (uint8_t *)cfi, -fibh->soffset);
memcpy(fibh->ebh->b_data, (uint8_t *)cfi - fibh->soffset,
- sizeof(struct fileIdentDesc) + fibh->soffset);
+ sizeof(struct fileIdentDesc) + fibh->soffset);
}
- if (adinicb)
+ if (adinicb) {
mark_inode_dirty(inode);
- else
- {
+ } else {
if (fibh->sbh != fibh->ebh)
mark_buffer_dirty_inode(fibh->ebh, inode);
mark_buffer_dirty_inode(fibh->sbh, inode);
@@ -147,635 +139,584 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
return 0;
}
-static struct fileIdentDesc *
-udf_find_entry(struct inode *dir, struct dentry *dentry,
- struct udf_fileident_bh *fibh,
- struct fileIdentDesc *cfi)
+static struct fileIdentDesc *udf_find_entry(struct inode *dir,
+ const struct qstr *child,
+ struct udf_fileident_bh *fibh,
+ struct fileIdentDesc *cfi)
{
- struct fileIdentDesc *fi=NULL;
+ struct fileIdentDesc *fi = NULL;
loff_t f_pos;
int block, flen;
- char fname[UDF_NAME_LEN];
- char *nameptr;
+ unsigned char *fname = NULL;
+ unsigned char *nameptr;
uint8_t lfi;
uint16_t liu;
loff_t size;
- kernel_lb_addr bloc, eloc;
- uint32_t extoffset, elen, offset;
- struct buffer_head *bh = NULL;
-
- size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
- f_pos = (udf_ext0_offset(dir) >> 2);
-
- fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
- fibh->sbh = fibh->ebh = NULL;
- else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
- &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30))
- {
- offset >>= dir->i_sb->s_blocksize_bits;
- block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
- if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
- {
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
- extoffset -= sizeof(short_ad);
- else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
- extoffset -= sizeof(long_ad);
- }
- else
+ struct kernel_lb_addr eloc;
+ uint32_t elen;
+ sector_t offset;
+ struct extent_position epos = {};
+ struct udf_inode_info *dinfo = UDF_I(dir);
+ int isdotdot = child->len == 2 &&
+ child->name[0] == '.' && child->name[1] == '.';
+
+ size = udf_ext0_offset(dir) + dir->i_size;
+ f_pos = udf_ext0_offset(dir);
+
+ fibh->sbh = fibh->ebh = NULL;
+ fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1);
+ if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+ if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos,
+ &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30))
+ goto out_err;
+ block = udf_get_lb_pblock(dir->i_sb, &eloc, offset);
+ if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
+ if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+ epos.offset -= sizeof(struct short_ad);
+ else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+ epos.offset -= sizeof(struct long_ad);
+ } else
offset = 0;
- if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
- {
- udf_release_data(bh);
- return NULL;
- }
- }
- else
- {
- udf_release_data(bh);
- return NULL;
+ fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
+ if (!fibh->sbh)
+ goto out_err;
}
- while ( (f_pos < size) )
- {
- fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
+ fname = kmalloc(UDF_NAME_LEN, GFP_NOFS);
+ if (!fname)
+ goto out_err;
+ while (f_pos < size) {
+ fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc,
+ &elen, &offset);
if (!fi)
- {
- if (fibh->sbh != fibh->ebh)
- udf_release_data(fibh->ebh);
- udf_release_data(fibh->sbh);
- udf_release_data(bh);
- return NULL;
- }
+ goto out_err;
liu = le16_to_cpu(cfi->lengthOfImpUse);
lfi = cfi->lengthFileIdent;
- if (fibh->sbh == fibh->ebh)
- {
+ if (fibh->sbh == fibh->ebh) {
nameptr = fi->fileIdent + liu;
- }
- else
- {
+ } else {
int poffset; /* Unpaded ending offset */
- poffset = fibh->soffset + sizeof(struct fileIdentDesc) + liu + lfi;
+ poffset = fibh->soffset + sizeof(struct fileIdentDesc) +
+ liu + lfi;
if (poffset >= lfi)
- nameptr = (uint8_t *)(fibh->ebh->b_data + poffset - lfi);
- else
- {
+ nameptr = (uint8_t *)(fibh->ebh->b_data +
+ poffset - lfi);
+ else {
nameptr = fname;
- memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
- memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset);
+ memcpy(nameptr, fi->fileIdent + liu,
+ lfi - poffset);
+ memcpy(nameptr + lfi - poffset,
+ fibh->ebh->b_data, poffset);
}
}
- if ( (cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0 )
- {
- if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE) )
+ if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
+ if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE))
continue;
}
-
- if ( (cfi->fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0 )
- {
- if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE) )
+
+ if ((cfi->fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) {
+ if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE))
continue;
}
+ if ((cfi->fileCharacteristics & FID_FILE_CHAR_PARENT) &&
+ isdotdot)
+ goto out_ok;
+
if (!lfi)
continue;
- if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)))
- {
- if (udf_match(flen, fname, dentry->d_name.len, dentry->d_name.name))
- {
- udf_release_data(bh);
- return fi;
- }
- }
+ flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi);
+ if (flen && udf_match(flen, fname, child->len, child->name))
+ goto out_ok;
}
+
+out_err:
+ fi = NULL;
if (fibh->sbh != fibh->ebh)
- udf_release_data(fibh->ebh);
- udf_release_data(fibh->sbh);
- udf_release_data(bh);
- return NULL;
-}
+ brelse(fibh->ebh);
+ brelse(fibh->sbh);
+out_ok:
+ brelse(epos.bh);
+ kfree(fname);
-/*
- * udf_lookup
- *
- * PURPOSE
- * Look-up the inode for a given name.
- *
- * DESCRIPTION
- * Required - lookup_dentry() will return -ENOTDIR if this routine is not
- * available for a directory. The filesystem is useless if this routine is
- * not available for at least the filesystem's root directory.
- *
- * This routine is passed an incomplete dentry - it must be completed by
- * calling d_add(dentry, inode). If the name does not exist, then the
- * specified inode must be set to null. An error should only be returned
- * when the lookup fails for a reason other than the name not existing.
- * Note that the directory inode semaphore is held during the call.
- *
- * Refer to lookup_dentry() in fs/namei.c
- * lookup_dentry() -> lookup() -> real_lookup() -> .
- *
- * PRE-CONDITIONS
- * dir Pointer to inode of parent directory.
- * dentry Pointer to dentry to complete.
- * nd Pointer to lookup nameidata
- *
- * POST-CONDITIONS
- * <return> Zero on success.
- *
- * HISTORY
- * July 1, 1997 - Andrew E. Mileski
- * Written, tested, and released.
- */
+ return fi;
+}
-static struct dentry *
-udf_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
+ unsigned int flags)
{
struct inode *inode = NULL;
- struct fileIdentDesc cfi, *fi;
+ struct fileIdentDesc cfi;
struct udf_fileident_bh fibh;
- if (dentry->d_name.len > UDF_NAME_LEN-2)
+ if (dentry->d_name.len > UDF_NAME_LEN - 2)
return ERR_PTR(-ENAMETOOLONG);
- lock_kernel();
#ifdef UDF_RECOVERY
/* temporary shorthand for specifying files by inode number */
- if (!strncmp(dentry->d_name.name, ".B=", 3) )
- {
- kernel_lb_addr lb = { 0, simple_strtoul(dentry->d_name.name+3, NULL, 0) };
+ if (!strncmp(dentry->d_name.name, ".B=", 3)) {
+ struct kernel_lb_addr lb = {
+ .logicalBlockNum = 0,
+ .partitionReferenceNum =
+ simple_strtoul(dentry->d_name.name + 3,
+ NULL, 0),
+ };
inode = udf_iget(dir->i_sb, lb);
- if (!inode)
- {
- unlock_kernel();
+ if (!inode) {
return ERR_PTR(-EACCES);
}
- }
- else
+ } else
#endif /* UDF_RECOVERY */
- if ((fi = udf_find_entry(dir, dentry, &fibh, &cfi)))
- {
+ if (udf_find_entry(dir, &dentry->d_name, &fibh, &cfi)) {
+ struct kernel_lb_addr loc;
+
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
- inode = udf_iget(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation));
- if ( !inode )
- {
- unlock_kernel();
+ loc = lelb_to_cpu(cfi.icb.extLocation);
+ inode = udf_iget(dir->i_sb, &loc);
+ if (!inode) {
return ERR_PTR(-EACCES);
}
}
- unlock_kernel();
- d_add(dentry, inode);
- return NULL;
+
+ return d_splice_alias(inode, dentry);
}
-static struct fileIdentDesc *
-udf_add_entry(struct inode *dir, struct dentry *dentry,
- struct udf_fileident_bh *fibh,
- struct fileIdentDesc *cfi, int *err)
+static struct fileIdentDesc *udf_add_entry(struct inode *dir,
+ struct dentry *dentry,
+ struct udf_fileident_bh *fibh,
+ struct fileIdentDesc *cfi, int *err)
{
- struct super_block *sb;
- struct fileIdentDesc *fi=NULL;
- char name[UDF_NAME_LEN], fname[UDF_NAME_LEN];
+ struct super_block *sb = dir->i_sb;
+ struct fileIdentDesc *fi = NULL;
+ unsigned char *name = NULL;
int namelen;
loff_t f_pos;
- int flen;
- char *nameptr;
- loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
+ loff_t size = udf_ext0_offset(dir) + dir->i_size;
int nfidlen;
uint8_t lfi;
uint16_t liu;
int block;
- kernel_lb_addr bloc, eloc;
- uint32_t extoffset, elen, offset;
- struct buffer_head *bh = NULL;
-
- sb = dir->i_sb;
+ struct kernel_lb_addr eloc;
+ uint32_t elen = 0;
+ sector_t offset;
+ struct extent_position epos = {};
+ struct udf_inode_info *dinfo;
+
+ fibh->sbh = fibh->ebh = NULL;
+ name = kmalloc(UDF_NAME_LEN, GFP_NOFS);
+ if (!name) {
+ *err = -ENOMEM;
+ goto out_err;
+ }
- if (dentry)
- {
- if (!dentry->d_name.len)
- {
+ if (dentry) {
+ if (!dentry->d_name.len) {
*err = -EINVAL;
- return NULL;
+ goto out_err;
}
-
- if ( !(namelen = udf_put_filename(sb, dentry->d_name.name, name, dentry->d_name.len)))
- {
+ namelen = udf_put_filename(sb, dentry->d_name.name, name,
+ dentry->d_name.len);
+ if (!namelen) {
*err = -ENAMETOOLONG;
- return NULL;
+ goto out_err;
}
- }
- else
+ } else {
namelen = 0;
+ }
nfidlen = (sizeof(struct fileIdentDesc) + namelen + 3) & ~3;
- f_pos = (udf_ext0_offset(dir) >> 2);
-
- fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
- fibh->sbh = fibh->ebh = NULL;
- else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
- &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30))
- {
- offset >>= dir->i_sb->s_blocksize_bits;
- block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
- if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
- {
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
- extoffset -= sizeof(short_ad);
- else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
- extoffset -= sizeof(long_ad);
+ f_pos = udf_ext0_offset(dir);
+
+ fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1);
+ dinfo = UDF_I(dir);
+ if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+ if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos,
+ &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) {
+ block = udf_get_lb_pblock(dir->i_sb,
+ &dinfo->i_location, 0);
+ fibh->soffset = fibh->eoffset = sb->s_blocksize;
+ goto add;
}
- else
+ block = udf_get_lb_pblock(dir->i_sb, &eloc, offset);
+ if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
+ if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+ epos.offset -= sizeof(struct short_ad);
+ else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+ epos.offset -= sizeof(struct long_ad);
+ } else
offset = 0;
- if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
- {
- udf_release_data(bh);
+ fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
+ if (!fibh->sbh) {
*err = -EIO;
- return NULL;
+ goto out_err;
}
- block = UDF_I_LOCATION(dir).logicalBlockNum;
-
- }
- else
- {
- block = udf_get_lb_pblock(dir->i_sb, UDF_I_LOCATION(dir), 0);
- fibh->sbh = fibh->ebh = NULL;
- fibh->soffset = fibh->eoffset = sb->s_blocksize;
- goto add;
+ block = dinfo->i_location.logicalBlockNum;
}
- while ( (f_pos < size) )
- {
- fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
+ while (f_pos < size) {
+ fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc,
+ &elen, &offset);
- if (!fi)
- {
- if (fibh->sbh != fibh->ebh)
- udf_release_data(fibh->ebh);
- udf_release_data(fibh->sbh);
- udf_release_data(bh);
+ if (!fi) {
*err = -EIO;
- return NULL;
+ goto out_err;
}
liu = le16_to_cpu(cfi->lengthOfImpUse);
lfi = cfi->lengthFileIdent;
- if (fibh->sbh == fibh->ebh)
- nameptr = fi->fileIdent + liu;
- else
- {
- int poffset; /* Unpaded ending offset */
-
- poffset = fibh->soffset + sizeof(struct fileIdentDesc) + liu + lfi;
-
- if (poffset >= lfi)
- nameptr = (char *)(fibh->ebh->b_data + poffset - lfi);
- else
- {
- nameptr = fname;
- memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
- memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset);
- }
- }
-
- if ( (cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0 )
- {
- if (((sizeof(struct fileIdentDesc) + liu + lfi + 3) & ~3) == nfidlen)
- {
- udf_release_data(bh);
+ if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
+ if (((sizeof(struct fileIdentDesc) +
+ liu + lfi + 3) & ~3) == nfidlen) {
cfi->descTag.tagSerialNum = cpu_to_le16(1);
cfi->fileVersionNum = cpu_to_le16(1);
cfi->fileCharacteristics = 0;
cfi->lengthFileIdent = namelen;
cfi->lengthOfImpUse = cpu_to_le16(0);
- if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name))
- return fi;
- else
- {
+ if (!udf_write_fi(dir, cfi, fi, fibh, NULL,
+ name))
+ goto out_ok;
+ else {
*err = -EIO;
- return NULL;
+ goto out_err;
}
}
}
-
- if (!lfi || !dentry)
- continue;
-
- if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)) &&
- udf_match(flen, fname, dentry->d_name.len, dentry->d_name.name))
- {
- if (fibh->sbh != fibh->ebh)
- udf_release_data(fibh->ebh);
- udf_release_data(fibh->sbh);
- udf_release_data(bh);
- *err = -EEXIST;
- return NULL;
- }
}
add:
f_pos += nfidlen;
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB &&
- sb->s_blocksize - fibh->eoffset < nfidlen)
- {
- udf_release_data(bh);
- bh = NULL;
+ if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB &&
+ sb->s_blocksize - fibh->eoffset < nfidlen) {
+ brelse(epos.bh);
+ epos.bh = NULL;
fibh->soffset -= udf_ext0_offset(dir);
fibh->eoffset -= udf_ext0_offset(dir);
- f_pos -= (udf_ext0_offset(dir) >> 2);
+ f_pos -= udf_ext0_offset(dir);
if (fibh->sbh != fibh->ebh)
- udf_release_data(fibh->ebh);
- udf_release_data(fibh->sbh);
- if (!(fibh->sbh = fibh->ebh = udf_expand_dir_adinicb(dir, &block, err)))
- return NULL;
- bloc = UDF_I_LOCATION(dir);
- eloc.logicalBlockNum = block;
- eloc.partitionReferenceNum = UDF_I_LOCATION(dir).partitionReferenceNum;
- elen = dir->i_sb->s_blocksize;
- extoffset = udf_file_entry_alloc_offset(dir);
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
- extoffset += sizeof(short_ad);
- else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
- extoffset += sizeof(long_ad);
+ brelse(fibh->ebh);
+ brelse(fibh->sbh);
+ fibh->sbh = fibh->ebh =
+ udf_expand_dir_adinicb(dir, &block, err);
+ if (!fibh->sbh)
+ goto out_err;
+ epos.block = dinfo->i_location;
+ epos.offset = udf_file_entry_alloc_offset(dir);
+ /* Load extent udf_expand_dir_adinicb() has created */
+ udf_current_aext(dir, &epos, &eloc, &elen, 1);
}
- if (sb->s_blocksize - fibh->eoffset >= nfidlen)
- {
+ /* Entry fits into current block? */
+ if (sb->s_blocksize - fibh->eoffset >= nfidlen) {
fibh->soffset = fibh->eoffset;
fibh->eoffset += nfidlen;
- if (fibh->sbh != fibh->ebh)
- {
- udf_release_data(fibh->sbh);
+ if (fibh->sbh != fibh->ebh) {
+ brelse(fibh->sbh);
fibh->sbh = fibh->ebh;
}
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
- {
- block = UDF_I_LOCATION(dir).logicalBlockNum;
- fi = (struct fileIdentDesc *)(UDF_I_DATA(dir) + fibh->soffset - udf_ext0_offset(dir) + UDF_I_LENEATTR(dir));
- }
- else
- {
- block = eloc.logicalBlockNum + ((elen - 1) >>
- dir->i_sb->s_blocksize_bits);
- fi = (struct fileIdentDesc *)(fibh->sbh->b_data + fibh->soffset);
+ if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+ block = dinfo->i_location.logicalBlockNum;
+ fi = (struct fileIdentDesc *)
+ (dinfo->i_ext.i_data +
+ fibh->soffset -
+ udf_ext0_offset(dir) +
+ dinfo->i_lenEAttr);
+ } else {
+ block = eloc.logicalBlockNum +
+ ((elen - 1) >>
+ dir->i_sb->s_blocksize_bits);
+ fi = (struct fileIdentDesc *)
+ (fibh->sbh->b_data + fibh->soffset);
}
- }
- else
- {
+ } else {
+ /* Round up last extent in the file */
+ elen = (elen + sb->s_blocksize - 1) & ~(sb->s_blocksize - 1);
+ if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+ epos.offset -= sizeof(struct short_ad);
+ else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+ epos.offset -= sizeof(struct long_ad);
+ udf_write_aext(dir, &epos, &eloc, elen, 1);
+ dinfo->i_lenExtents = (dinfo->i_lenExtents + sb->s_blocksize
+ - 1) & ~(sb->s_blocksize - 1);
+
fibh->soffset = fibh->eoffset - sb->s_blocksize;
fibh->eoffset += nfidlen - sb->s_blocksize;
- if (fibh->sbh != fibh->ebh)
- {
- udf_release_data(fibh->sbh);
+ if (fibh->sbh != fibh->ebh) {
+ brelse(fibh->sbh);
fibh->sbh = fibh->ebh;
}
block = eloc.logicalBlockNum + ((elen - 1) >>
- dir->i_sb->s_blocksize_bits);
-
- if (!(fibh->ebh = udf_bread(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), 1, err)))
- {
- udf_release_data(bh);
- udf_release_data(fibh->sbh);
- return NULL;
- }
-
- if (!(fibh->soffset))
- {
- if (udf_next_aext(dir, &bloc, &extoffset, &eloc, &elen, &bh, 1) ==
+ dir->i_sb->s_blocksize_bits);
+ fibh->ebh = udf_bread(dir,
+ f_pos >> dir->i_sb->s_blocksize_bits, 1, err);
+ if (!fibh->ebh)
+ goto out_err;
+ /* Extents could have been merged, invalidate our position */
+ brelse(epos.bh);
+ epos.bh = NULL;
+ epos.block = dinfo->i_location;
+ epos.offset = udf_file_entry_alloc_offset(dir);
+
+ if (!fibh->soffset) {
+ /* Find the freshly allocated block */
+ while (udf_next_aext(dir, &epos, &eloc, &elen, 1) ==
(EXT_RECORDED_ALLOCATED >> 30))
- {
- block = eloc.logicalBlockNum + ((elen - 1) >>
+ ;
+ block = eloc.logicalBlockNum + ((elen - 1) >>
dir->i_sb->s_blocksize_bits);
- }
- else
- block ++;
-
- udf_release_data(fibh->sbh);
+ brelse(fibh->sbh);
fibh->sbh = fibh->ebh;
fi = (struct fileIdentDesc *)(fibh->sbh->b_data);
- }
- else
- {
+ } else {
fi = (struct fileIdentDesc *)
- (fibh->sbh->b_data + sb->s_blocksize + fibh->soffset);
+ (fibh->sbh->b_data + sb->s_blocksize +
+ fibh->soffset);
}
}
memset(cfi, 0, sizeof(struct fileIdentDesc));
- if (UDF_SB_UDFREV(sb) >= 0x0200)
- udf_new_tag((char *)cfi, TAG_IDENT_FID, 3, 1, block, sizeof(tag));
+ if (UDF_SB(sb)->s_udfrev >= 0x0200)
+ udf_new_tag((char *)cfi, TAG_IDENT_FID, 3, 1, block,
+ sizeof(struct tag));
else
- udf_new_tag((char *)cfi, TAG_IDENT_FID, 2, 1, block, sizeof(tag));
+ udf_new_tag((char *)cfi, TAG_IDENT_FID, 2, 1, block,
+ sizeof(struct tag));
cfi->fileVersionNum = cpu_to_le16(1);
cfi->lengthFileIdent = namelen;
cfi->lengthOfImpUse = cpu_to_le16(0);
- if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name))
- {
- udf_release_data(bh);
+ if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) {
dir->i_size += nfidlen;
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
- UDF_I_LENALLOC(dir) += nfidlen;
+ if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
+ dinfo->i_lenAlloc += nfidlen;
+ else {
+ /* Find the last extent and truncate it to proper size */
+ while (udf_next_aext(dir, &epos, &eloc, &elen, 1) ==
+ (EXT_RECORDED_ALLOCATED >> 30))
+ ;
+ elen -= dinfo->i_lenExtents - dir->i_size;
+ if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+ epos.offset -= sizeof(struct short_ad);
+ else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+ epos.offset -= sizeof(struct long_ad);
+ udf_write_aext(dir, &epos, &eloc, elen, 1);
+ dinfo->i_lenExtents = dir->i_size;
+ }
+
mark_inode_dirty(dir);
- return fi;
- }
- else
- {
- udf_release_data(bh);
- if (fibh->sbh != fibh->ebh)
- udf_release_data(fibh->ebh);
- udf_release_data(fibh->sbh);
+ goto out_ok;
+ } else {
*err = -EIO;
- return NULL;
+ goto out_err;
}
+
+out_err:
+ fi = NULL;
+ if (fibh->sbh != fibh->ebh)
+ brelse(fibh->ebh);
+ brelse(fibh->sbh);
+out_ok:
+ brelse(epos.bh);
+ kfree(name);
+ return fi;
}
static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi,
- struct udf_fileident_bh *fibh, struct fileIdentDesc *cfi)
+ struct udf_fileident_bh *fibh,
+ struct fileIdentDesc *cfi)
{
cfi->fileCharacteristics |= FID_FILE_CHAR_DELETED;
+
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))
- memset(&(cfi->icb), 0x00, sizeof(long_ad));
+ memset(&(cfi->icb), 0x00, sizeof(struct long_ad));
+
return udf_write_fi(inode, cfi, fi, fibh, NULL, NULL);
}
-static int udf_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd)
+static int udf_create(struct inode *dir, struct dentry *dentry, umode_t mode,
+ bool excl)
{
struct udf_fileident_bh fibh;
struct inode *inode;
struct fileIdentDesc cfi, *fi;
int err;
+ struct udf_inode_info *iinfo;
- lock_kernel();
inode = udf_new_inode(dir, mode, &err);
- if (!inode)
- {
- unlock_kernel();
+ if (!inode) {
return err;
}
- if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
+ iinfo = UDF_I(inode);
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
inode->i_data.a_ops = &udf_adinicb_aops;
else
inode->i_data.a_ops = &udf_aops;
inode->i_op = &udf_file_inode_operations;
inode->i_fop = &udf_file_operations;
- inode->i_mode = mode;
mark_inode_dirty(inode);
- if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
- {
- inode->i_nlink --;
- mark_inode_dirty(inode);
+ fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
+ if (!fi) {
+ inode_dec_link_count(inode);
iput(inode);
- unlock_kernel();
return err;
}
cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
- cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
+ cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
- cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
+ cpu_to_le32(iinfo->i_unique & 0x00000000FFFFFFFFUL);
udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
- {
+ if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
mark_inode_dirty(dir);
- }
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
- unlock_kernel();
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
d_instantiate(dentry, inode);
+
return 0;
}
-static int udf_mknod(struct inode * dir, struct dentry * dentry, int mode, dev_t rdev)
+static int udf_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
{
- struct inode * inode;
+ struct inode *inode;
+ struct udf_inode_info *iinfo;
+ int err;
+
+ inode = udf_new_inode(dir, mode, &err);
+ if (!inode)
+ return err;
+
+ iinfo = UDF_I(inode);
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
+ inode->i_data.a_ops = &udf_adinicb_aops;
+ else
+ inode->i_data.a_ops = &udf_aops;
+ inode->i_op = &udf_file_inode_operations;
+ inode->i_fop = &udf_file_operations;
+ mark_inode_dirty(inode);
+
+ d_tmpfile(dentry, inode);
+ return 0;
+}
+
+static int udf_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
+ dev_t rdev)
+{
+ struct inode *inode;
struct udf_fileident_bh fibh;
struct fileIdentDesc cfi, *fi;
int err;
+ struct udf_inode_info *iinfo;
if (!old_valid_dev(rdev))
return -EINVAL;
- lock_kernel();
err = -EIO;
inode = udf_new_inode(dir, mode, &err);
if (!inode)
goto out;
- inode->i_uid = current->fsuid;
+ iinfo = UDF_I(inode);
init_special_inode(inode, mode, rdev);
- if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
- {
- inode->i_nlink --;
- mark_inode_dirty(inode);
+ fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
+ if (!fi) {
+ inode_dec_link_count(inode);
iput(inode);
- unlock_kernel();
return err;
}
cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
- cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
+ cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
- cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
+ cpu_to_le32(iinfo->i_unique & 0x00000000FFFFFFFFUL);
udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
- {
+ if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
mark_inode_dirty(dir);
- }
mark_inode_dirty(inode);
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
d_instantiate(dentry, inode);
err = 0;
+
out:
- unlock_kernel();
return err;
}
-static int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+static int udf_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{
- struct inode * inode;
+ struct inode *inode;
struct udf_fileident_bh fibh;
struct fileIdentDesc cfi, *fi;
int err;
-
- lock_kernel();
- err = -EMLINK;
- if (dir->i_nlink >= (256<<sizeof(dir->i_nlink))-1)
- goto out;
+ struct udf_inode_info *dinfo = UDF_I(dir);
+ struct udf_inode_info *iinfo;
err = -EIO;
- inode = udf_new_inode(dir, S_IFDIR, &err);
+ inode = udf_new_inode(dir, S_IFDIR | mode, &err);
if (!inode)
goto out;
+ iinfo = UDF_I(inode);
inode->i_op = &udf_dir_inode_operations;
inode->i_fop = &udf_dir_operations;
- if (!(fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err)))
- {
- inode->i_nlink--;
- mark_inode_dirty(inode);
+ fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err);
+ if (!fi) {
+ inode_dec_link_count(inode);
iput(inode);
goto out;
}
- inode->i_nlink = 2;
+ set_nlink(inode, 2);
cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
- cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(dir));
+ cfi.icb.extLocation = cpu_to_lelb(dinfo->i_location);
*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
- cpu_to_le32(UDF_I_UNIQUE(dir) & 0x00000000FFFFFFFFUL);
- cfi.fileCharacteristics = FID_FILE_CHAR_DIRECTORY | FID_FILE_CHAR_PARENT;
+ cpu_to_le32(dinfo->i_unique & 0x00000000FFFFFFFFUL);
+ cfi.fileCharacteristics =
+ FID_FILE_CHAR_DIRECTORY | FID_FILE_CHAR_PARENT;
udf_write_fi(inode, &cfi, fi, &fibh, NULL, NULL);
- udf_release_data(fibh.sbh);
- inode->i_mode = S_IFDIR | mode;
- if (dir->i_mode & S_ISGID)
- inode->i_mode |= S_ISGID;
+ brelse(fibh.sbh);
mark_inode_dirty(inode);
- if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
- {
- inode->i_nlink = 0;
+ fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
+ if (!fi) {
+ clear_nlink(inode);
mark_inode_dirty(inode);
iput(inode);
goto out;
}
cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
- cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
+ cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
- cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
+ cpu_to_le32(iinfo->i_unique & 0x00000000FFFFFFFFUL);
cfi.fileCharacteristics |= FID_FILE_CHAR_DIRECTORY;
udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
- dir->i_nlink++;
+ inc_nlink(dir);
mark_inode_dirty(dir);
d_instantiate(dentry, inode);
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
err = 0;
+
out:
- unlock_kernel();
return err;
}
@@ -784,92 +725,86 @@ static int empty_dir(struct inode *dir)
struct fileIdentDesc *fi, cfi;
struct udf_fileident_bh fibh;
loff_t f_pos;
- loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
+ loff_t size = udf_ext0_offset(dir) + dir->i_size;
int block;
- kernel_lb_addr bloc, eloc;
- uint32_t extoffset, elen, offset;
- struct buffer_head *bh = NULL;
-
- f_pos = (udf_ext0_offset(dir) >> 2);
+ struct kernel_lb_addr eloc;
+ uint32_t elen;
+ sector_t offset;
+ struct extent_position epos = {};
+ struct udf_inode_info *dinfo = UDF_I(dir);
- fibh.soffset = fibh.eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
+ f_pos = udf_ext0_offset(dir);
+ fibh.soffset = fibh.eoffset = f_pos & (dir->i_sb->s_blocksize - 1);
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
+ if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
fibh.sbh = fibh.ebh = NULL;
- else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
- &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30))
- {
- offset >>= dir->i_sb->s_blocksize_bits;
- block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
- if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
- {
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
- extoffset -= sizeof(short_ad);
- else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
- extoffset -= sizeof(long_ad);
- }
- else
+ else if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits,
+ &epos, &eloc, &elen, &offset) ==
+ (EXT_RECORDED_ALLOCATED >> 30)) {
+ block = udf_get_lb_pblock(dir->i_sb, &eloc, offset);
+ if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
+ if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+ epos.offset -= sizeof(struct short_ad);
+ else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+ epos.offset -= sizeof(struct long_ad);
+ } else
offset = 0;
- if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block)))
- {
- udf_release_data(bh);
+ fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block);
+ if (!fibh.sbh) {
+ brelse(epos.bh);
return 0;
}
- }
- else
- {
- udf_release_data(bh);
+ } else {
+ brelse(epos.bh);
return 0;
}
-
- while ( (f_pos < size) )
- {
- fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
-
- if (!fi)
- {
+ while (f_pos < size) {
+ fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &epos, &eloc,
+ &elen, &offset);
+ if (!fi) {
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
- udf_release_data(bh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
+ brelse(epos.bh);
return 0;
}
- if (cfi.lengthFileIdent && (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) == 0)
- {
+ if (cfi.lengthFileIdent &&
+ (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) == 0) {
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
- udf_release_data(bh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
+ brelse(epos.bh);
return 0;
}
}
+
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
- udf_release_data(bh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
+ brelse(epos.bh);
+
return 1;
}
-static int udf_rmdir(struct inode * dir, struct dentry * dentry)
+static int udf_rmdir(struct inode *dir, struct dentry *dentry)
{
int retval;
- struct inode * inode = dentry->d_inode;
+ struct inode *inode = dentry->d_inode;
struct udf_fileident_bh fibh;
struct fileIdentDesc *fi, cfi;
- kernel_lb_addr tloc;
+ struct kernel_lb_addr tloc;
retval = -ENOENT;
- lock_kernel();
- fi = udf_find_entry(dir, dentry, &fibh, &cfi);
+ fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);
if (!fi)
goto out;
retval = -EIO;
tloc = lelb_to_cpu(cfi.icb.extLocation);
- if (udf_get_lb_pblock(dir->i_sb, tloc, 0) != inode->i_ino)
+ if (udf_get_lb_pblock(dir->i_sb, &tloc, 0) != inode->i_ino)
goto end_rmdir;
retval = -ENOTEMPTY;
if (!empty_dir(inode))
@@ -878,177 +813,180 @@ static int udf_rmdir(struct inode * dir, struct dentry * dentry)
if (retval)
goto end_rmdir;
if (inode->i_nlink != 2)
- udf_warning(inode->i_sb, "udf_rmdir",
- "empty directory has nlink != 2 (%d)",
- inode->i_nlink);
- inode->i_nlink = 0;
+ udf_warn(inode->i_sb, "empty directory has nlink != 2 (%d)\n",
+ inode->i_nlink);
+ clear_nlink(inode);
inode->i_size = 0;
- mark_inode_dirty(inode);
- dir->i_nlink --;
- inode->i_ctime = dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb);
+ inode_dec_link_count(dir);
+ inode->i_ctime = dir->i_ctime = dir->i_mtime =
+ current_fs_time(dir->i_sb);
mark_inode_dirty(dir);
end_rmdir:
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
+
out:
- unlock_kernel();
return retval;
}
-static int udf_unlink(struct inode * dir, struct dentry * dentry)
+static int udf_unlink(struct inode *dir, struct dentry *dentry)
{
int retval;
- struct inode * inode = dentry->d_inode;
+ struct inode *inode = dentry->d_inode;
struct udf_fileident_bh fibh;
struct fileIdentDesc *fi;
struct fileIdentDesc cfi;
- kernel_lb_addr tloc;
+ struct kernel_lb_addr tloc;
retval = -ENOENT;
- lock_kernel();
- fi = udf_find_entry(dir, dentry, &fibh, &cfi);
+ fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);
if (!fi)
goto out;
retval = -EIO;
tloc = lelb_to_cpu(cfi.icb.extLocation);
- if (udf_get_lb_pblock(dir->i_sb, tloc, 0) != inode->i_ino)
+ if (udf_get_lb_pblock(dir->i_sb, &tloc, 0) != inode->i_ino)
goto end_unlink;
- if (!inode->i_nlink)
- {
+ if (!inode->i_nlink) {
udf_debug("Deleting nonexistent file (%lu), %d\n",
- inode->i_ino, inode->i_nlink);
- inode->i_nlink = 1;
+ inode->i_ino, inode->i_nlink);
+ set_nlink(inode, 1);
}
retval = udf_delete_entry(dir, fi, &fibh, &cfi);
if (retval)
goto end_unlink;
dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb);
mark_inode_dirty(dir);
- inode->i_nlink--;
- mark_inode_dirty(inode);
+ inode_dec_link_count(inode);
inode->i_ctime = dir->i_ctime;
retval = 0;
end_unlink:
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
+
out:
- unlock_kernel();
return retval;
}
-static int udf_symlink(struct inode * dir, struct dentry * dentry, const char * symname)
+static int udf_symlink(struct inode *dir, struct dentry *dentry,
+ const char *symname)
{
- struct inode * inode;
+ struct inode *inode;
struct pathComponent *pc;
- char *compstart;
+ const char *compstart;
struct udf_fileident_bh fibh;
- struct buffer_head *bh = NULL;
+ struct extent_position epos = {};
int eoffset, elen = 0;
struct fileIdentDesc *fi;
struct fileIdentDesc cfi;
- char *ea;
+ uint8_t *ea;
int err;
int block;
- char name[UDF_NAME_LEN];
+ unsigned char *name = NULL;
int namelen;
+ struct udf_inode_info *iinfo;
+ struct super_block *sb = dir->i_sb;
- lock_kernel();
- if (!(inode = udf_new_inode(dir, S_IFLNK, &err)))
+ inode = udf_new_inode(dir, S_IFLNK | S_IRWXUGO, &err);
+ if (!inode)
goto out;
- inode->i_mode = S_IFLNK | S_IRWXUGO;
+ iinfo = UDF_I(inode);
+ down_write(&iinfo->i_data_sem);
+ name = kmalloc(UDF_NAME_LEN, GFP_NOFS);
+ if (!name) {
+ err = -ENOMEM;
+ goto out_no_entry;
+ }
+
inode->i_data.a_ops = &udf_symlink_aops;
- inode->i_op = &page_symlink_inode_operations;
+ inode->i_op = &udf_symlink_inode_operations;
- if (UDF_I_ALLOCTYPE(inode) != ICBTAG_FLAG_AD_IN_ICB)
- {
- struct buffer_head *bh = NULL;
- kernel_lb_addr bloc, eloc;
- uint32_t elen, extoffset;
+ if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+ struct kernel_lb_addr eloc;
+ uint32_t bsize;
- block = udf_new_block(inode->i_sb, inode,
- UDF_I_LOCATION(inode).partitionReferenceNum,
- UDF_I_LOCATION(inode).logicalBlockNum, &err);
+ block = udf_new_block(sb, inode,
+ iinfo->i_location.partitionReferenceNum,
+ iinfo->i_location.logicalBlockNum, &err);
if (!block)
goto out_no_entry;
- bloc = UDF_I_LOCATION(inode);
+ epos.block = iinfo->i_location;
+ epos.offset = udf_file_entry_alloc_offset(inode);
+ epos.bh = NULL;
eloc.logicalBlockNum = block;
- eloc.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
- elen = inode->i_sb->s_blocksize;
- UDF_I_LENEXTENTS(inode) = elen;
- extoffset = udf_file_entry_alloc_offset(inode);
- udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 0);
- udf_release_data(bh);
-
- block = udf_get_pblock(inode->i_sb, block,
- UDF_I_LOCATION(inode).partitionReferenceNum, 0);
- bh = udf_tread(inode->i_sb, block);
- lock_buffer(bh);
- memset(bh->b_data, 0x00, inode->i_sb->s_blocksize);
- set_buffer_uptodate(bh);
- unlock_buffer(bh);
- mark_buffer_dirty_inode(bh, inode);
- ea = bh->b_data + udf_ext0_offset(inode);
- }
- else
- ea = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode);
-
- eoffset = inode->i_sb->s_blocksize - udf_ext0_offset(inode);
+ eloc.partitionReferenceNum =
+ iinfo->i_location.partitionReferenceNum;
+ bsize = sb->s_blocksize;
+ iinfo->i_lenExtents = bsize;
+ udf_add_aext(inode, &epos, &eloc, bsize, 0);
+ brelse(epos.bh);
+
+ block = udf_get_pblock(sb, block,
+ iinfo->i_location.partitionReferenceNum,
+ 0);
+ epos.bh = udf_tgetblk(sb, block);
+ lock_buffer(epos.bh);
+ memset(epos.bh->b_data, 0x00, bsize);
+ set_buffer_uptodate(epos.bh);
+ unlock_buffer(epos.bh);
+ mark_buffer_dirty_inode(epos.bh, inode);
+ ea = epos.bh->b_data + udf_ext0_offset(inode);
+ } else
+ ea = iinfo->i_ext.i_data + iinfo->i_lenEAttr;
+
+ eoffset = sb->s_blocksize - udf_ext0_offset(inode);
pc = (struct pathComponent *)ea;
- if (*symname == '/')
- {
- do
- {
+ if (*symname == '/') {
+ do {
symname++;
} while (*symname == '/');
pc->componentType = 1;
pc->lengthComponentIdent = 0;
pc->componentFileVersionNum = 0;
- pc += sizeof(struct pathComponent);
elen += sizeof(struct pathComponent);
}
err = -ENAMETOOLONG;
- while (*symname)
- {
+ while (*symname) {
if (elen + sizeof(struct pathComponent) > eoffset)
goto out_no_entry;
pc = (struct pathComponent *)(ea + elen);
- compstart = (char *)symname;
+ compstart = symname;
- do
- {
+ do {
symname++;
} while (*symname && *symname != '/');
pc->componentType = 5;
pc->lengthComponentIdent = 0;
pc->componentFileVersionNum = 0;
- if (compstart[0] == '.')
- {
- if ((symname-compstart) == 1)
+ if (compstart[0] == '.') {
+ if ((symname - compstart) == 1)
pc->componentType = 4;
- else if ((symname-compstart) == 2 && compstart[1] == '.')
+ else if ((symname - compstart) == 2 &&
+ compstart[1] == '.')
pc->componentType = 3;
}
- if (pc->componentType == 5)
- {
- if ( !(namelen = udf_put_filename(inode->i_sb, compstart, name, symname-compstart)))
+ if (pc->componentType == 5) {
+ namelen = udf_put_filename(sb, compstart, name,
+ symname - compstart);
+ if (!namelen)
goto out_no_entry;
- if (elen + sizeof(struct pathComponent) + namelen > eoffset)
+ if (elen + sizeof(struct pathComponent) + namelen >
+ eoffset)
goto out_no_entry;
else
pc->lengthComponentIdent = namelen;
@@ -1058,189 +996,154 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
elen += sizeof(struct pathComponent) + pc->lengthComponentIdent;
- if (*symname)
- {
- do
- {
+ if (*symname) {
+ do {
symname++;
} while (*symname == '/');
}
}
- udf_release_data(bh);
+ brelse(epos.bh);
inode->i_size = elen;
- if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
- UDF_I_LENALLOC(inode) = inode->i_size;
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
+ iinfo->i_lenAlloc = inode->i_size;
+ else
+ udf_truncate_tail_extent(inode);
mark_inode_dirty(inode);
+ up_write(&iinfo->i_data_sem);
- if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
+ fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
+ if (!fi)
goto out_no_entry;
- cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
- cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
- if (UDF_SB_LVIDBH(inode->i_sb))
- {
- struct logicalVolHeaderDesc *lvhd;
- uint64_t uniqueID;
- lvhd = (struct logicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->logicalVolContentsUse);
- uniqueID = le64_to_cpu(lvhd->uniqueID);
+ cfi.icb.extLength = cpu_to_le32(sb->s_blocksize);
+ cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
+ if (UDF_SB(inode->i_sb)->s_lvid_bh) {
*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
- cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL);
- if (!(++uniqueID & 0x00000000FFFFFFFFUL))
- uniqueID += 16;
- lvhd->uniqueID = cpu_to_le64(uniqueID);
- mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb));
+ cpu_to_le32(lvid_get_unique_id(sb));
}
udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
- {
+ if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
mark_inode_dirty(dir);
- }
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
d_instantiate(dentry, inode);
err = 0;
out:
- unlock_kernel();
+ kfree(name);
return err;
out_no_entry:
- inode->i_nlink--;
- mark_inode_dirty(inode);
+ up_write(&iinfo->i_data_sem);
+ inode_dec_link_count(inode);
iput(inode);
goto out;
}
-static int udf_link(struct dentry * old_dentry, struct inode * dir,
- struct dentry *dentry)
+static int udf_link(struct dentry *old_dentry, struct inode *dir,
+ struct dentry *dentry)
{
struct inode *inode = old_dentry->d_inode;
struct udf_fileident_bh fibh;
struct fileIdentDesc cfi, *fi;
int err;
- lock_kernel();
- if (inode->i_nlink >= (256<<sizeof(inode->i_nlink))-1)
- {
- unlock_kernel();
- return -EMLINK;
- }
-
- if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
- {
- unlock_kernel();
+ fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
+ if (!fi) {
return err;
}
cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
- cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
- if (UDF_SB_LVIDBH(inode->i_sb))
- {
- struct logicalVolHeaderDesc *lvhd;
- uint64_t uniqueID;
- lvhd = (struct logicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->logicalVolContentsUse);
- uniqueID = le64_to_cpu(lvhd->uniqueID);
+ cfi.icb.extLocation = cpu_to_lelb(UDF_I(inode)->i_location);
+ if (UDF_SB(inode->i_sb)->s_lvid_bh) {
*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
- cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL);
- if (!(++uniqueID & 0x00000000FFFFFFFFUL))
- uniqueID += 16;
- lvhd->uniqueID = cpu_to_le64(uniqueID);
- mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb));
+ cpu_to_le32(lvid_get_unique_id(inode->i_sb));
}
udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
- {
+ if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
mark_inode_dirty(dir);
- }
+
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
- inode->i_nlink ++;
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
+ inc_nlink(inode);
inode->i_ctime = current_fs_time(inode->i_sb);
mark_inode_dirty(inode);
- atomic_inc(&inode->i_count);
+ ihold(inode);
d_instantiate(dentry, inode);
- unlock_kernel();
+
return 0;
}
/* Anybody can rename anything with this: the permission checks are left to the
* higher-level routines.
*/
-static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
- struct inode * new_dir, struct dentry * new_dentry)
+static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
{
- struct inode * old_inode = old_dentry->d_inode;
- struct inode * new_inode = new_dentry->d_inode;
+ struct inode *old_inode = old_dentry->d_inode;
+ struct inode *new_inode = new_dentry->d_inode;
struct udf_fileident_bh ofibh, nfibh;
- struct fileIdentDesc *ofi = NULL, *nfi = NULL, *dir_fi = NULL, ocfi, ncfi;
+ struct fileIdentDesc *ofi = NULL, *nfi = NULL, *dir_fi = NULL;
+ struct fileIdentDesc ocfi, ncfi;
struct buffer_head *dir_bh = NULL;
int retval = -ENOENT;
- kernel_lb_addr tloc;
+ struct kernel_lb_addr tloc;
+ struct udf_inode_info *old_iinfo = UDF_I(old_inode);
- lock_kernel();
- if ((ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi)))
- {
+ ofi = udf_find_entry(old_dir, &old_dentry->d_name, &ofibh, &ocfi);
+ if (ofi) {
if (ofibh.sbh != ofibh.ebh)
- udf_release_data(ofibh.ebh);
- udf_release_data(ofibh.sbh);
+ brelse(ofibh.ebh);
+ brelse(ofibh.sbh);
}
tloc = lelb_to_cpu(ocfi.icb.extLocation);
- if (!ofi || udf_get_lb_pblock(old_dir->i_sb, tloc, 0)
- != old_inode->i_ino)
+ if (!ofi || udf_get_lb_pblock(old_dir->i_sb, &tloc, 0)
+ != old_inode->i_ino)
goto end_rename;
- nfi = udf_find_entry(new_dir, new_dentry, &nfibh, &ncfi);
- if (nfi)
- {
- if (!new_inode)
- {
+ nfi = udf_find_entry(new_dir, &new_dentry->d_name, &nfibh, &ncfi);
+ if (nfi) {
+ if (!new_inode) {
if (nfibh.sbh != nfibh.ebh)
- udf_release_data(nfibh.ebh);
- udf_release_data(nfibh.sbh);
+ brelse(nfibh.ebh);
+ brelse(nfibh.sbh);
nfi = NULL;
}
}
- if (S_ISDIR(old_inode->i_mode))
- {
- uint32_t offset = udf_ext0_offset(old_inode);
+ if (S_ISDIR(old_inode->i_mode)) {
+ int offset = udf_ext0_offset(old_inode);
- if (new_inode)
- {
+ if (new_inode) {
retval = -ENOTEMPTY;
if (!empty_dir(new_inode))
goto end_rename;
}
retval = -EIO;
- if (UDF_I_ALLOCTYPE(old_inode) == ICBTAG_FLAG_AD_IN_ICB)
- {
- dir_fi = udf_get_fileident(UDF_I_DATA(old_inode) -
- (UDF_I_EFE(old_inode) ?
- sizeof(struct extendedFileEntry) :
- sizeof(struct fileEntry)),
- old_inode->i_sb->s_blocksize, &offset);
- }
- else
- {
+ if (old_iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+ dir_fi = udf_get_fileident(
+ old_iinfo->i_ext.i_data -
+ (old_iinfo->i_efe ?
+ sizeof(struct extendedFileEntry) :
+ sizeof(struct fileEntry)),
+ old_inode->i_sb->s_blocksize, &offset);
+ } else {
dir_bh = udf_bread(old_inode, 0, 0, &retval);
if (!dir_bh)
goto end_rename;
- dir_fi = udf_get_fileident(dir_bh->b_data, old_inode->i_sb->s_blocksize, &offset);
+ dir_fi = udf_get_fileident(dir_bh->b_data,
+ old_inode->i_sb->s_blocksize, &offset);
}
if (!dir_fi)
goto end_rename;
tloc = lelb_to_cpu(dir_fi->icb.extLocation);
- if (udf_get_lb_pblock(old_inode->i_sb, tloc, 0)
- != old_dir->i_ino)
- goto end_rename;
-
- retval = -EMLINK;
- if (!new_inode && new_dir->i_nlink >= (256<<sizeof(new_dir->i_nlink))-1)
+ if (udf_get_lb_pblock(old_inode->i_sb, &tloc, 0) !=
+ old_dir->i_ino)
goto end_rename;
}
- if (!nfi)
- {
- nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi, &retval);
+ if (!nfi) {
+ nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi,
+ &retval);
if (!nfi)
goto end_rename;
}
@@ -1257,69 +1160,171 @@ static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
*/
ncfi.fileVersionNum = ocfi.fileVersionNum;
ncfi.fileCharacteristics = ocfi.fileCharacteristics;
- memcpy(&(ncfi.icb), &(ocfi.icb), sizeof(long_ad));
+ memcpy(&(ncfi.icb), &(ocfi.icb), sizeof(struct long_ad));
udf_write_fi(new_dir, &ncfi, nfi, &nfibh, NULL, NULL);
/* The old fid may have moved - find it again */
- ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi);
+ ofi = udf_find_entry(old_dir, &old_dentry->d_name, &ofibh, &ocfi);
udf_delete_entry(old_dir, ofi, &ofibh, &ocfi);
- if (new_inode)
- {
- new_inode->i_nlink--;
+ if (new_inode) {
new_inode->i_ctime = current_fs_time(new_inode->i_sb);
- mark_inode_dirty(new_inode);
+ inode_dec_link_count(new_inode);
}
old_dir->i_ctime = old_dir->i_mtime = current_fs_time(old_dir->i_sb);
mark_inode_dirty(old_dir);
- if (dir_fi)
- {
- dir_fi->icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(new_dir));
- udf_update_tag((char *)dir_fi, (sizeof(struct fileIdentDesc) +
- le16_to_cpu(dir_fi->lengthOfImpUse) + 3) & ~3);
- if (UDF_I_ALLOCTYPE(old_inode) == ICBTAG_FLAG_AD_IN_ICB)
- {
+ if (dir_fi) {
+ dir_fi->icb.extLocation = cpu_to_lelb(UDF_I(new_dir)->i_location);
+ udf_update_tag((char *)dir_fi,
+ (sizeof(struct fileIdentDesc) +
+ le16_to_cpu(dir_fi->lengthOfImpUse) + 3) & ~3);
+ if (old_iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
mark_inode_dirty(old_inode);
- }
else
mark_buffer_dirty_inode(dir_bh, old_inode);
- old_dir->i_nlink --;
- mark_inode_dirty(old_dir);
+
+ inode_dec_link_count(old_dir);
if (new_inode)
- {
- new_inode->i_nlink --;
- mark_inode_dirty(new_inode);
- }
- else
- {
- new_dir->i_nlink ++;
+ inode_dec_link_count(new_inode);
+ else {
+ inc_nlink(new_dir);
mark_inode_dirty(new_dir);
}
}
- if (ofi)
- {
+ if (ofi) {
if (ofibh.sbh != ofibh.ebh)
- udf_release_data(ofibh.ebh);
- udf_release_data(ofibh.sbh);
+ brelse(ofibh.ebh);
+ brelse(ofibh.sbh);
}
retval = 0;
end_rename:
- udf_release_data(dir_bh);
- if (nfi)
- {
+ brelse(dir_bh);
+ if (nfi) {
if (nfibh.sbh != nfibh.ebh)
- udf_release_data(nfibh.ebh);
- udf_release_data(nfibh.sbh);
+ brelse(nfibh.ebh);
+ brelse(nfibh.sbh);
}
- unlock_kernel();
+
return retval;
}
-struct inode_operations udf_dir_inode_operations = {
+static struct dentry *udf_get_parent(struct dentry *child)
+{
+ struct kernel_lb_addr tloc;
+ struct inode *inode = NULL;
+ struct qstr dotdot = QSTR_INIT("..", 2);
+ struct fileIdentDesc cfi;
+ struct udf_fileident_bh fibh;
+
+ if (!udf_find_entry(child->d_inode, &dotdot, &fibh, &cfi))
+ goto out_unlock;
+
+ if (fibh.sbh != fibh.ebh)
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
+
+ tloc = lelb_to_cpu(cfi.icb.extLocation);
+ inode = udf_iget(child->d_inode->i_sb, &tloc);
+ if (!inode)
+ goto out_unlock;
+
+ return d_obtain_alias(inode);
+out_unlock:
+ return ERR_PTR(-EACCES);
+}
+
+
+static struct dentry *udf_nfs_get_inode(struct super_block *sb, u32 block,
+ u16 partref, __u32 generation)
+{
+ struct inode *inode;
+ struct kernel_lb_addr loc;
+
+ if (block == 0)
+ return ERR_PTR(-ESTALE);
+
+ loc.logicalBlockNum = block;
+ loc.partitionReferenceNum = partref;
+ inode = udf_iget(sb, &loc);
+
+ if (inode == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ if (generation && inode->i_generation != generation) {
+ iput(inode);
+ return ERR_PTR(-ESTALE);
+ }
+ return d_obtain_alias(inode);
+}
+
+static struct dentry *udf_fh_to_dentry(struct super_block *sb,
+ struct fid *fid, int fh_len, int fh_type)
+{
+ if ((fh_len != 3 && fh_len != 5) ||
+ (fh_type != FILEID_UDF_WITH_PARENT &&
+ fh_type != FILEID_UDF_WITHOUT_PARENT))
+ return NULL;
+
+ return udf_nfs_get_inode(sb, fid->udf.block, fid->udf.partref,
+ fid->udf.generation);
+}
+
+static struct dentry *udf_fh_to_parent(struct super_block *sb,
+ struct fid *fid, int fh_len, int fh_type)
+{
+ if (fh_len != 5 || fh_type != FILEID_UDF_WITH_PARENT)
+ return NULL;
+
+ return udf_nfs_get_inode(sb, fid->udf.parent_block,
+ fid->udf.parent_partref,
+ fid->udf.parent_generation);
+}
+static int udf_encode_fh(struct inode *inode, __u32 *fh, int *lenp,
+ struct inode *parent)
+{
+ int len = *lenp;
+ struct kernel_lb_addr location = UDF_I(inode)->i_location;
+ struct fid *fid = (struct fid *)fh;
+ int type = FILEID_UDF_WITHOUT_PARENT;
+
+ if (parent && (len < 5)) {
+ *lenp = 5;
+ return FILEID_INVALID;
+ } else if (len < 3) {
+ *lenp = 3;
+ return FILEID_INVALID;
+ }
+
+ *lenp = 3;
+ fid->udf.block = location.logicalBlockNum;
+ fid->udf.partref = location.partitionReferenceNum;
+ fid->udf.parent_partref = 0;
+ fid->udf.generation = inode->i_generation;
+
+ if (parent) {
+ location = UDF_I(parent)->i_location;
+ fid->udf.parent_block = location.logicalBlockNum;
+ fid->udf.parent_partref = location.partitionReferenceNum;
+ fid->udf.parent_generation = inode->i_generation;
+ *lenp = 5;
+ type = FILEID_UDF_WITH_PARENT;
+ }
+
+ return type;
+}
+
+const struct export_operations udf_export_ops = {
+ .encode_fh = udf_encode_fh,
+ .fh_to_dentry = udf_fh_to_dentry,
+ .fh_to_parent = udf_fh_to_parent,
+ .get_parent = udf_get_parent,
+};
+
+const struct inode_operations udf_dir_inode_operations = {
.lookup = udf_lookup,
.create = udf_create,
.link = udf_link,
@@ -1329,4 +1334,10 @@ struct inode_operations udf_dir_inode_operations = {
.rmdir = udf_rmdir,
.mknod = udf_mknod,
.rename = udf_rename,
+ .tmpfile = udf_tmpfile,
+};
+const struct inode_operations udf_symlink_inode_operations = {
+ .readlink = generic_readlink,
+ .follow_link = page_follow_link_light,
+ .put_link = page_put_link,
};
diff --git a/fs/udf/osta_udf.h b/fs/udf/osta_udf.h
index e82aae65269..fbff74654df 100644
--- a/fs/udf/osta_udf.h
+++ b/fs/udf/osta_udf.h
@@ -65,31 +65,27 @@
#define IS_DF_HARD_WRITE_PROTECT 0x01
#define IS_DF_SOFT_WRITE_PROTECT 0x02
-struct UDFIdentSuffix
-{
+struct UDFIdentSuffix {
__le16 UDFRevision;
uint8_t OSClass;
uint8_t OSIdentifier;
uint8_t reserved[4];
} __attribute__ ((packed));
-struct impIdentSuffix
-{
+struct impIdentSuffix {
uint8_t OSClass;
uint8_t OSIdentifier;
uint8_t reserved[6];
} __attribute__ ((packed));
-struct appIdentSuffix
-{
+struct appIdentSuffix {
uint8_t impUse[8];
} __attribute__ ((packed));
/* Logical Volume Integrity Descriptor (UDF 2.50 2.2.6) */
/* Implementation Use (UDF 2.50 2.2.6.4) */
-struct logicalVolIntegrityDescImpUse
-{
- regid impIdent;
+struct logicalVolIntegrityDescImpUse {
+ struct regid impIdent;
__le32 numFiles;
__le32 numDirs;
__le16 minUDFReadRev;
@@ -100,62 +96,57 @@ struct logicalVolIntegrityDescImpUse
/* Implementation Use Volume Descriptor (UDF 2.50 2.2.7) */
/* Implementation Use (UDF 2.50 2.2.7.2) */
-struct impUseVolDescImpUse
-{
- charspec LVICharset;
+struct impUseVolDescImpUse {
+ struct charspec LVICharset;
dstring logicalVolIdent[128];
dstring LVInfo1[36];
dstring LVInfo2[36];
dstring LVInfo3[36];
- regid impIdent;
+ struct regid impIdent;
uint8_t impUse[128];
} __attribute__ ((packed));
-struct udfPartitionMap2
-{
+struct udfPartitionMap2 {
uint8_t partitionMapType;
uint8_t partitionMapLength;
uint8_t reserved1[2];
- regid partIdent;
+ struct regid partIdent;
__le16 volSeqNum;
__le16 partitionNum;
} __attribute__ ((packed));
/* Virtual Partition Map (UDF 2.50 2.2.8) */
-struct virtualPartitionMap
-{
+struct virtualPartitionMap {
uint8_t partitionMapType;
uint8_t partitionMapLength;
uint8_t reserved1[2];
- regid partIdent;
+ struct regid partIdent;
__le16 volSeqNum;
__le16 partitionNum;
uint8_t reserved2[24];
} __attribute__ ((packed));
/* Sparable Partition Map (UDF 2.50 2.2.9) */
-struct sparablePartitionMap
-{
- uint8_t partitionMapType;
- uint8_t partitionMapLength;
- uint8_t reserved1[2];
- regid partIdent;
- __le16 volSeqNum;
- __le16 partitionNum;
- __le16 packetLength;
- uint8_t numSparingTables;
- uint8_t reserved2[1];
- __le32 sizeSparingTable;
- __le32 locSparingTable[4];
+struct sparablePartitionMap {
+ uint8_t partitionMapType;
+ uint8_t partitionMapLength;
+ uint8_t reserved1[2];
+ struct regid partIdent;
+ __le16 volSeqNum;
+ __le16 partitionNum;
+ __le16 packetLength;
+ uint8_t numSparingTables;
+ uint8_t reserved2[1];
+ __le32 sizeSparingTable;
+ __le32 locSparingTable[4];
} __attribute__ ((packed));
/* Metadata Partition Map (UDF 2.4.0 2.2.10) */
-struct metadataPartitionMap
-{
+struct metadataPartitionMap {
uint8_t partitionMapType;
uint8_t partitionMapLength;
uint8_t reserved1[2];
- regid partIdent;
+ struct regid partIdent;
__le16 volSeqNum;
__le16 partitionNum;
__le32 metadataFileLoc;
@@ -168,18 +159,16 @@ struct metadataPartitionMap
} __attribute__ ((packed));
/* Virtual Allocation Table (UDF 1.5 2.2.10) */
-struct virtualAllocationTable15
-{
+struct virtualAllocationTable15 {
__le32 VirtualSector[0];
- regid vatIdent;
+ struct regid vatIdent;
__le32 previousVATICBLoc;
-} __attribute__ ((packed));
+} __attribute__ ((packed));
#define ICBTAG_FILE_TYPE_VAT15 0x00U
/* Virtual Allocation Table (UDF 2.50 2.2.11) */
-struct virtualAllocationTable20
-{
+struct virtualAllocationTable20 {
__le16 lengthHeader;
__le16 lengthImpUse;
dstring logicalVolIdent[128];
@@ -197,16 +186,14 @@ struct virtualAllocationTable20
#define ICBTAG_FILE_TYPE_VAT20 0xF8U
/* Sparing Table (UDF 2.50 2.2.12) */
-struct sparingEntry
-{
+struct sparingEntry {
__le32 origLocation;
__le32 mappedLocation;
} __attribute__ ((packed));
-struct sparingTable
-{
- tag descTag;
- regid sparingIdent;
+struct sparingTable {
+ struct tag descTag;
+ struct regid sparingIdent;
__le16 reallocationTableLen;
__le16 reserved;
__le32 sequenceNum;
@@ -219,9 +206,8 @@ struct sparingTable
#define ICBTAG_FILE_TYPE_MIRROR 0xFB
#define ICBTAG_FILE_TYPE_BITMAP 0xFC
-/* struct long_ad ICB - ADImpUse (UDF 2.50 2.2.4.3) */
-struct allocDescImpUse
-{
+/* struct struct long_ad ICB - ADImpUse (UDF 2.50 2.2.4.3) */
+struct allocDescImpUse {
__le16 flags;
uint8_t impUse[4];
} __attribute__ ((packed));
@@ -233,15 +219,13 @@ struct allocDescImpUse
/* Implementation Use Extended Attribute (UDF 2.50 3.3.4.5) */
/* FreeEASpace (UDF 2.50 3.3.4.5.1.1) */
-struct freeEaSpace
-{
+struct freeEaSpace {
__le16 headerChecksum;
uint8_t freeEASpace[0];
} __attribute__ ((packed));
/* DVD Copyright Management Information (UDF 2.50 3.3.4.5.1.2) */
-struct DVDCopyrightImpUse
-{
+struct DVDCopyrightImpUse {
__le16 headerChecksum;
uint8_t CGMSInfo;
uint8_t dataType;
@@ -250,8 +234,7 @@ struct DVDCopyrightImpUse
/* Application Use Extended Attribute (UDF 2.50 3.3.4.6) */
/* FreeAppEASpace (UDF 2.50 3.3.4.6.1) */
-struct freeAppEASpace
-{
+struct freeAppEASpace {
__le16 headerChecksum;
uint8_t freeEASpace[0];
} __attribute__ ((packed));
diff --git a/fs/udf/partition.c b/fs/udf/partition.c
index 4d36f264be0..d6caf01a209 100644
--- a/fs/udf/partition.c
+++ b/fs/udf/partition.c
@@ -4,11 +4,6 @@
* PURPOSE
* Partition handling routines for the OSTA-UDF(tm) filesystem.
*
- * CONTACTS
- * E-mail regarding any portion of the Linux UDF file system should be
- * directed to the development team mailing list (run by majordomo):
- * linux_udf@hpesjro.fc.hp.com
- *
* COPYRIGHT
* This file is distributed under the terms of the GNU General Public
* License (GPL). Copies of the GPL can be obtained from:
@@ -19,7 +14,7 @@
*
* HISTORY
*
- * 12/06/98 blf Created file.
+ * 12/06/98 blf Created file.
*
*/
@@ -29,110 +24,130 @@
#include <linux/fs.h>
#include <linux/string.h>
-#include <linux/udf_fs.h>
-#include <linux/slab.h>
#include <linux/buffer_head.h>
+#include <linux/mutex.h>
-inline uint32_t udf_get_pblock(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
+uint32_t udf_get_pblock(struct super_block *sb, uint32_t block,
+ uint16_t partition, uint32_t offset)
{
- if (partition >= UDF_SB_NUMPARTS(sb))
- {
+ struct udf_sb_info *sbi = UDF_SB(sb);
+ struct udf_part_map *map;
+ if (partition >= sbi->s_partitions) {
udf_debug("block=%d, partition=%d, offset=%d: invalid partition\n",
- block, partition, offset);
+ block, partition, offset);
return 0xFFFFFFFF;
}
- if (UDF_SB_PARTFUNC(sb, partition))
- return UDF_SB_PARTFUNC(sb, partition)(sb, block, partition, offset);
+ map = &sbi->s_partmaps[partition];
+ if (map->s_partition_func)
+ return map->s_partition_func(sb, block, partition, offset);
else
- return UDF_SB_PARTROOT(sb, partition) + block + offset;
+ return map->s_partition_root + block + offset;
}
-uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
+uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
+ uint16_t partition, uint32_t offset)
{
struct buffer_head *bh = NULL;
uint32_t newblock;
uint32_t index;
uint32_t loc;
+ struct udf_sb_info *sbi = UDF_SB(sb);
+ struct udf_part_map *map;
+ struct udf_virtual_data *vdata;
+ struct udf_inode_info *iinfo = UDF_I(sbi->s_vat_inode);
- index = (sb->s_blocksize - UDF_SB_TYPEVIRT(sb,partition).s_start_offset) / sizeof(uint32_t);
+ map = &sbi->s_partmaps[partition];
+ vdata = &map->s_type_specific.s_virtual;
- if (block > UDF_SB_TYPEVIRT(sb,partition).s_num_entries)
- {
+ if (block > vdata->s_num_entries) {
udf_debug("Trying to access block beyond end of VAT (%d max %d)\n",
- block, UDF_SB_TYPEVIRT(sb,partition).s_num_entries);
+ block, vdata->s_num_entries);
return 0xFFFFFFFF;
}
- if (block >= index)
- {
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+ loc = le32_to_cpu(((__le32 *)(iinfo->i_ext.i_data +
+ vdata->s_start_offset))[block]);
+ goto translate;
+ }
+ index = (sb->s_blocksize - vdata->s_start_offset) / sizeof(uint32_t);
+ if (block >= index) {
block -= index;
newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t)));
index = block % (sb->s_blocksize / sizeof(uint32_t));
- }
- else
- {
+ } else {
newblock = 0;
- index = UDF_SB_TYPEVIRT(sb,partition).s_start_offset / sizeof(uint32_t) + block;
+ index = vdata->s_start_offset / sizeof(uint32_t) + block;
}
- loc = udf_block_map(UDF_SB_VAT(sb), newblock);
+ loc = udf_block_map(sbi->s_vat_inode, newblock);
- if (!(bh = sb_bread(sb, loc)))
- {
+ bh = sb_bread(sb, loc);
+ if (!bh) {
udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d]\n",
- sb, block, partition, loc, index);
+ sb, block, partition, loc, index);
return 0xFFFFFFFF;
}
loc = le32_to_cpu(((__le32 *)bh->b_data)[index]);
- udf_release_data(bh);
+ brelse(bh);
- if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition)
- {
+translate:
+ if (iinfo->i_location.partitionReferenceNum == partition) {
udf_debug("recursive call to udf_get_pblock!\n");
return 0xFFFFFFFF;
}
- return udf_get_pblock(sb, loc, UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum, offset);
+ return udf_get_pblock(sb, loc,
+ iinfo->i_location.partitionReferenceNum,
+ offset);
}
-inline uint32_t udf_get_pblock_virt20(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
+inline uint32_t udf_get_pblock_virt20(struct super_block *sb, uint32_t block,
+ uint16_t partition, uint32_t offset)
{
return udf_get_pblock_virt15(sb, block, partition, offset);
}
-uint32_t udf_get_pblock_spar15(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
+uint32_t udf_get_pblock_spar15(struct super_block *sb, uint32_t block,
+ uint16_t partition, uint32_t offset)
{
int i;
struct sparingTable *st = NULL;
- uint32_t packet = (block + offset) & ~(UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1);
+ struct udf_sb_info *sbi = UDF_SB(sb);
+ struct udf_part_map *map;
+ uint32_t packet;
+ struct udf_sparing_data *sdata;
+
+ map = &sbi->s_partmaps[partition];
+ sdata = &map->s_type_specific.s_sparing;
+ packet = (block + offset) & ~(sdata->s_packet_len - 1);
- for (i=0; i<4; i++)
- {
- if (UDF_SB_TYPESPAR(sb,partition).s_spar_map[i] != NULL)
- {
- st = (struct sparingTable *)UDF_SB_TYPESPAR(sb,partition).s_spar_map[i]->b_data;
+ for (i = 0; i < 4; i++) {
+ if (sdata->s_spar_map[i] != NULL) {
+ st = (struct sparingTable *)
+ sdata->s_spar_map[i]->b_data;
break;
}
}
- if (st)
- {
- for (i=0; i<le16_to_cpu(st->reallocationTableLen); i++)
- {
- if (le32_to_cpu(st->mapEntry[i].origLocation) >= 0xFFFFFFF0)
+ if (st) {
+ for (i = 0; i < le16_to_cpu(st->reallocationTableLen); i++) {
+ struct sparingEntry *entry = &st->mapEntry[i];
+ u32 origLoc = le32_to_cpu(entry->origLocation);
+ if (origLoc >= 0xFFFFFFF0)
break;
- else if (le32_to_cpu(st->mapEntry[i].origLocation) == packet)
- {
- return le32_to_cpu(st->mapEntry[i].mappedLocation) +
- ((block + offset) & (UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1));
- }
- else if (le32_to_cpu(st->mapEntry[i].origLocation) > packet)
+ else if (origLoc == packet)
+ return le32_to_cpu(entry->mappedLocation) +
+ ((block + offset) &
+ (sdata->s_packet_len - 1));
+ else if (origLoc > packet)
break;
}
}
- return UDF_SB_PARTROOT(sb,partition) + block + offset;
+
+ return map->s_partition_root + block + offset;
}
int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
@@ -142,85 +157,183 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
struct sparingEntry mapEntry;
uint32_t packet;
int i, j, k, l;
+ struct udf_sb_info *sbi = UDF_SB(sb);
+ u16 reallocationTableLen;
+ struct buffer_head *bh;
+ int ret = 0;
+
+ mutex_lock(&sbi->s_alloc_mutex);
+ for (i = 0; i < sbi->s_partitions; i++) {
+ struct udf_part_map *map = &sbi->s_partmaps[i];
+ if (old_block > map->s_partition_root &&
+ old_block < map->s_partition_root + map->s_partition_len) {
+ sdata = &map->s_type_specific.s_sparing;
+ packet = (old_block - map->s_partition_root) &
+ ~(sdata->s_packet_len - 1);
- for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
- {
- if (old_block > UDF_SB_PARTROOT(sb,i) &&
- old_block < UDF_SB_PARTROOT(sb,i) + UDF_SB_PARTLEN(sb,i))
- {
- sdata = &UDF_SB_TYPESPAR(sb,i);
- packet = (old_block - UDF_SB_PARTROOT(sb,i)) & ~(sdata->s_packet_len - 1);
-
- for (j=0; j<4; j++)
- {
- if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL)
- {
- st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
+ for (j = 0; j < 4; j++)
+ if (sdata->s_spar_map[j] != NULL) {
+ st = (struct sparingTable *)
+ sdata->s_spar_map[j]->b_data;
break;
}
+
+ if (!st) {
+ ret = 1;
+ goto out;
}
- if (!st)
- return 1;
-
- for (k=0; k<le16_to_cpu(st->reallocationTableLen); k++)
- {
- if (le32_to_cpu(st->mapEntry[k].origLocation) == 0xFFFFFFFF)
- {
- for (; j<4; j++)
- {
- if (sdata->s_spar_map[j])
- {
- st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
- st->mapEntry[k].origLocation = cpu_to_le32(packet);
- udf_update_tag((char *)st, sizeof(struct sparingTable) + le16_to_cpu(st->reallocationTableLen) * sizeof(struct sparingEntry));
- mark_buffer_dirty(sdata->s_spar_map[j]);
- }
+ reallocationTableLen =
+ le16_to_cpu(st->reallocationTableLen);
+ for (k = 0; k < reallocationTableLen; k++) {
+ struct sparingEntry *entry = &st->mapEntry[k];
+ u32 origLoc = le32_to_cpu(entry->origLocation);
+
+ if (origLoc == 0xFFFFFFFF) {
+ for (; j < 4; j++) {
+ int len;
+ bh = sdata->s_spar_map[j];
+ if (!bh)
+ continue;
+
+ st = (struct sparingTable *)
+ bh->b_data;
+ entry->origLocation =
+ cpu_to_le32(packet);
+ len =
+ sizeof(struct sparingTable) +
+ reallocationTableLen *
+ sizeof(struct sparingEntry);
+ udf_update_tag((char *)st, len);
+ mark_buffer_dirty(bh);
}
- *new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
- ((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
- return 0;
- }
- else if (le32_to_cpu(st->mapEntry[k].origLocation) == packet)
- {
- *new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
- ((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
- return 0;
- }
- else if (le32_to_cpu(st->mapEntry[k].origLocation) > packet)
+ *new_block = le32_to_cpu(
+ entry->mappedLocation) +
+ ((old_block -
+ map->s_partition_root) &
+ (sdata->s_packet_len - 1));
+ ret = 0;
+ goto out;
+ } else if (origLoc == packet) {
+ *new_block = le32_to_cpu(
+ entry->mappedLocation) +
+ ((old_block -
+ map->s_partition_root) &
+ (sdata->s_packet_len - 1));
+ ret = 0;
+ goto out;
+ } else if (origLoc > packet)
break;
}
- for (l=k; l<le16_to_cpu(st->reallocationTableLen); l++)
- {
- if (le32_to_cpu(st->mapEntry[l].origLocation) == 0xFFFFFFFF)
- {
- for (; j<4; j++)
- {
- if (sdata->s_spar_map[j])
- {
- st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
- mapEntry = st->mapEntry[l];
- mapEntry.origLocation = cpu_to_le32(packet);
- memmove(&st->mapEntry[k+1], &st->mapEntry[k], (l-k)*sizeof(struct sparingEntry));
- st->mapEntry[k] = mapEntry;
- udf_update_tag((char *)st, sizeof(struct sparingTable) + le16_to_cpu(st->reallocationTableLen) * sizeof(struct sparingEntry));
- mark_buffer_dirty(sdata->s_spar_map[j]);
- }
- }
- *new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
- ((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
- return 0;
+
+ for (l = k; l < reallocationTableLen; l++) {
+ struct sparingEntry *entry = &st->mapEntry[l];
+ u32 origLoc = le32_to_cpu(entry->origLocation);
+
+ if (origLoc != 0xFFFFFFFF)
+ continue;
+
+ for (; j < 4; j++) {
+ bh = sdata->s_spar_map[j];
+ if (!bh)
+ continue;
+
+ st = (struct sparingTable *)bh->b_data;
+ mapEntry = st->mapEntry[l];
+ mapEntry.origLocation =
+ cpu_to_le32(packet);
+ memmove(&st->mapEntry[k + 1],
+ &st->mapEntry[k],
+ (l - k) *
+ sizeof(struct sparingEntry));
+ st->mapEntry[k] = mapEntry;
+ udf_update_tag((char *)st,
+ sizeof(struct sparingTable) +
+ reallocationTableLen *
+ sizeof(struct sparingEntry));
+ mark_buffer_dirty(bh);
}
+ *new_block =
+ le32_to_cpu(
+ st->mapEntry[k].mappedLocation) +
+ ((old_block - map->s_partition_root) &
+ (sdata->s_packet_len - 1));
+ ret = 0;
+ goto out;
}
- return 1;
- }
+
+ ret = 1;
+ goto out;
+ } /* if old_block */
}
- if (i == UDF_SB_NUMPARTS(sb))
- {
+
+ if (i == sbi->s_partitions) {
/* outside of partitions */
/* for now, fail =) */
- return 1;
+ ret = 1;
+ }
+
+out:
+ mutex_unlock(&sbi->s_alloc_mutex);
+ return ret;
+}
+
+static uint32_t udf_try_read_meta(struct inode *inode, uint32_t block,
+ uint16_t partition, uint32_t offset)
+{
+ struct super_block *sb = inode->i_sb;
+ struct udf_part_map *map;
+ struct kernel_lb_addr eloc;
+ uint32_t elen;
+ sector_t ext_offset;
+ struct extent_position epos = {};
+ uint32_t phyblock;
+
+ if (inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset) !=
+ (EXT_RECORDED_ALLOCATED >> 30))
+ phyblock = 0xFFFFFFFF;
+ else {
+ map = &UDF_SB(sb)->s_partmaps[partition];
+ /* map to sparable/physical partition desc */
+ phyblock = udf_get_pblock(sb, eloc.logicalBlockNum,
+ map->s_partition_num, ext_offset + offset);
+ }
+
+ brelse(epos.bh);
+ return phyblock;
+}
+
+uint32_t udf_get_pblock_meta25(struct super_block *sb, uint32_t block,
+ uint16_t partition, uint32_t offset)
+{
+ struct udf_sb_info *sbi = UDF_SB(sb);
+ struct udf_part_map *map;
+ struct udf_meta_data *mdata;
+ uint32_t retblk;
+ struct inode *inode;
+
+ udf_debug("READING from METADATA\n");
+
+ map = &sbi->s_partmaps[partition];
+ mdata = &map->s_type_specific.s_metadata;
+ inode = mdata->s_metadata_fe ? : mdata->s_mirror_fe;
+
+ /* We shouldn't mount such media... */
+ BUG_ON(!inode);
+ retblk = udf_try_read_meta(inode, block, partition, offset);
+ if (retblk == 0xFFFFFFFF && mdata->s_metadata_fe) {
+ udf_warn(sb, "error reading from METADATA, trying to read from MIRROR\n");
+ if (!(mdata->s_flags & MF_MIRROR_FE_LOADED)) {
+ mdata->s_mirror_fe = udf_find_metadata_inode_efe(sb,
+ mdata->s_mirror_file_loc, map->s_partition_num);
+ mdata->s_flags |= MF_MIRROR_FE_LOADED;
+ }
+
+ inode = mdata->s_mirror_fe;
+ if (!inode)
+ return 0xFFFFFFFF;
+ retblk = udf_try_read_meta(inode, block, partition, offset);
}
- return 0;
+ return retblk;
}
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 15bd4f24c5b..3286db047a4 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -14,11 +14,6 @@
* http://www.ecma.ch/
* http://www.iso.org/
*
- * CONTACTS
- * E-mail regarding any portion of the Linux UDF file system should be
- * directed to the development team mailing list (run by majordomo):
- * linux_udf@hpesjro.fc.hp.com
- *
* COPYRIGHT
* This file is distributed under the terms of the GNU General Public
* License (GPL). Copies of the GPL can be obtained from:
@@ -38,14 +33,13 @@
* 10/17/98 added freespace count for "df"
* 11/11/98 gr added novrs option
* 11/26/98 dgb added fileset,anchor mount options
- * 12/06/98 blf really hosed things royally. vat/sparing support. sequenced vol descs
- * rewrote option handling based on isofs
+ * 12/06/98 blf really hosed things royally. vat/sparing support. sequenced
+ * vol descs. rewrote option handling based on isofs
* 12/20/98 find the free space bitmap (if it exists)
*/
-#include "udfdecl.h"
+#include "udfdecl.h"
-#include <linux/config.h>
#include <linux/blkdev.h>
#include <linux/slab.h>
#include <linux/kernel.h>
@@ -54,13 +48,17 @@
#include <linux/stat.h>
#include <linux/cdrom.h>
#include <linux/nls.h>
-#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
#include <linux/vfs.h>
#include <linux/vmalloc.h>
+#include <linux/errno.h>
+#include <linux/mount.h>
+#include <linux/seq_file.h>
+#include <linux/bitmap.h>
+#include <linux/crc-itu-t.h>
+#include <linux/log2.h>
#include <asm/byteorder.h>
-#include <linux/udf_fs.h>
#include "udf_sb.h"
#include "udf_i.h"
@@ -76,103 +74,143 @@
#define VDS_POS_TERMINATING_DESC 6
#define VDS_POS_LENGTH 7
-static char error_buf[1024];
+#define UDF_DEFAULT_BLOCKSIZE 2048
+
+#define VSD_FIRST_SECTOR_OFFSET 32768
+#define VSD_MAX_SECTOR_OFFSET 0x800000
+
+enum { UDF_MAX_LINKS = 0xffff };
/* These are the "meat" - everything else is stuffing */
static int udf_fill_super(struct super_block *, void *, int);
static void udf_put_super(struct super_block *);
-static void udf_write_super(struct super_block *);
+static int udf_sync_fs(struct super_block *, int);
static int udf_remount_fs(struct super_block *, int *, char *);
-static int udf_check_valid(struct super_block *, int, int);
-static int udf_vrs(struct super_block *sb, int silent);
-static int udf_load_partition(struct super_block *, kernel_lb_addr *);
-static int udf_load_logicalvol(struct super_block *, struct buffer_head *, kernel_lb_addr *);
-static void udf_load_logicalvolint(struct super_block *, kernel_extent_ad);
-static void udf_find_anchor(struct super_block *);
-static int udf_find_fileset(struct super_block *, kernel_lb_addr *, kernel_lb_addr *);
-static void udf_load_pvoldesc(struct super_block *, struct buffer_head *);
-static void udf_load_fileset(struct super_block *, struct buffer_head *, kernel_lb_addr *);
-static void udf_load_partdesc(struct super_block *, struct buffer_head *);
+static void udf_load_logicalvolint(struct super_block *, struct kernel_extent_ad);
+static int udf_find_fileset(struct super_block *, struct kernel_lb_addr *,
+ struct kernel_lb_addr *);
+static void udf_load_fileset(struct super_block *, struct buffer_head *,
+ struct kernel_lb_addr *);
static void udf_open_lvid(struct super_block *);
static void udf_close_lvid(struct super_block *);
static unsigned int udf_count_free(struct super_block *);
-static int udf_statfs(struct super_block *, struct kstatfs *);
+static int udf_statfs(struct dentry *, struct kstatfs *);
+static int udf_show_options(struct seq_file *, struct dentry *);
+
+struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct super_block *sb)
+{
+ struct logicalVolIntegrityDesc *lvid;
+ unsigned int partnum;
+ unsigned int offset;
+
+ if (!UDF_SB(sb)->s_lvid_bh)
+ return NULL;
+ lvid = (struct logicalVolIntegrityDesc *)UDF_SB(sb)->s_lvid_bh->b_data;
+ partnum = le32_to_cpu(lvid->numOfPartitions);
+ if ((sb->s_blocksize - sizeof(struct logicalVolIntegrityDescImpUse) -
+ offsetof(struct logicalVolIntegrityDesc, impUse)) /
+ (2 * sizeof(uint32_t)) < partnum) {
+ udf_err(sb, "Logical volume integrity descriptor corrupted "
+ "(numOfPartitions = %u)!\n", partnum);
+ return NULL;
+ }
+ /* The offset is to skip freeSpaceTable and sizeTable arrays */
+ offset = partnum * 2 * sizeof(uint32_t);
+ return (struct logicalVolIntegrityDescImpUse *)&(lvid->impUse[offset]);
+}
/* UDF filesystem type */
-static struct super_block *udf_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+static struct dentry *udf_mount(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data)
{
- return get_sb_bdev(fs_type, flags, dev_name, data, udf_fill_super);
+ return mount_bdev(fs_type, flags, dev_name, data, udf_fill_super);
}
static struct file_system_type udf_fstype = {
.owner = THIS_MODULE,
.name = "udf",
- .get_sb = udf_get_sb,
+ .mount = udf_mount,
.kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV,
};
+MODULE_ALIAS_FS("udf");
-static kmem_cache_t * udf_inode_cachep;
+static struct kmem_cache *udf_inode_cachep;
static struct inode *udf_alloc_inode(struct super_block *sb)
{
struct udf_inode_info *ei;
- ei = (struct udf_inode_info *)kmem_cache_alloc(udf_inode_cachep, SLAB_KERNEL);
+ ei = kmem_cache_alloc(udf_inode_cachep, GFP_KERNEL);
if (!ei)
return NULL;
+
+ ei->i_unique = 0;
+ ei->i_lenExtents = 0;
+ ei->i_next_alloc_block = 0;
+ ei->i_next_alloc_goal = 0;
+ ei->i_strat4096 = 0;
+ init_rwsem(&ei->i_data_sem);
+ ei->cached_extent.lstart = -1;
+ spin_lock_init(&ei->i_extent_cache_lock);
+
return &ei->vfs_inode;
}
-static void udf_destroy_inode(struct inode *inode)
+static void udf_i_callback(struct rcu_head *head)
{
+ struct inode *inode = container_of(head, struct inode, i_rcu);
kmem_cache_free(udf_inode_cachep, UDF_I(inode));
}
-static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+static void udf_destroy_inode(struct inode *inode)
{
- struct udf_inode_info *ei = (struct udf_inode_info *) foo;
+ call_rcu(&inode->i_rcu, udf_i_callback);
+}
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
- {
- ei->i_ext.i_data = NULL;
- inode_init_once(&ei->vfs_inode);
- }
+static void init_once(void *foo)
+{
+ struct udf_inode_info *ei = (struct udf_inode_info *)foo;
+
+ ei->i_ext.i_data = NULL;
+ inode_init_once(&ei->vfs_inode);
}
-static int init_inodecache(void)
+static int __init init_inodecache(void)
{
udf_inode_cachep = kmem_cache_create("udf_inode_cache",
sizeof(struct udf_inode_info),
- 0, SLAB_RECLAIM_ACCOUNT,
- init_once, NULL);
- if (udf_inode_cachep == NULL)
+ 0, (SLAB_RECLAIM_ACCOUNT |
+ SLAB_MEM_SPREAD),
+ init_once);
+ if (!udf_inode_cachep)
return -ENOMEM;
return 0;
}
static void destroy_inodecache(void)
{
- if (kmem_cache_destroy(udf_inode_cachep))
- printk(KERN_INFO "udf_inode_cache: not all structures were freed\n");
+ /*
+ * Make sure all delayed rcu free inodes are flushed before we
+ * destroy cache.
+ */
+ rcu_barrier();
+ kmem_cache_destroy(udf_inode_cachep);
}
/* Superblock operations */
-static struct super_operations udf_sb_ops = {
- .alloc_inode = udf_alloc_inode,
- .destroy_inode = udf_destroy_inode,
- .write_inode = udf_write_inode,
- .delete_inode = udf_delete_inode,
- .clear_inode = udf_clear_inode,
- .put_super = udf_put_super,
- .write_super = udf_write_super,
- .statfs = udf_statfs,
- .remount_fs = udf_remount_fs,
+static const struct super_operations udf_sb_ops = {
+ .alloc_inode = udf_alloc_inode,
+ .destroy_inode = udf_destroy_inode,
+ .write_inode = udf_write_inode,
+ .evict_inode = udf_evict_inode,
+ .put_super = udf_put_super,
+ .sync_fs = udf_sync_fs,
+ .statfs = udf_statfs,
+ .remount_fs = udf_remount_fs,
+ .show_options = udf_show_options,
};
-struct udf_options
-{
+struct udf_options {
unsigned char novrs;
unsigned int blocksize;
unsigned int session;
@@ -183,24 +221,30 @@ struct udf_options
unsigned int fileset;
unsigned int rootdir;
unsigned int flags;
- mode_t umask;
- gid_t gid;
- uid_t uid;
+ umode_t umask;
+ kgid_t gid;
+ kuid_t uid;
+ umode_t fmode;
+ umode_t dmode;
struct nls_table *nls_map;
};
static int __init init_udf_fs(void)
{
int err;
+
err = init_inodecache();
if (err)
goto out1;
err = register_filesystem(&udf_fstype);
if (err)
goto out;
+
return 0;
+
out:
destroy_inodecache();
+
out1:
return err;
}
@@ -214,6 +258,134 @@ static void __exit exit_udf_fs(void)
module_init(init_udf_fs)
module_exit(exit_udf_fs)
+static int udf_sb_alloc_partition_maps(struct super_block *sb, u32 count)
+{
+ struct udf_sb_info *sbi = UDF_SB(sb);
+
+ sbi->s_partmaps = kcalloc(count, sizeof(struct udf_part_map),
+ GFP_KERNEL);
+ if (!sbi->s_partmaps) {
+ udf_err(sb, "Unable to allocate space for %d partition maps\n",
+ count);
+ sbi->s_partitions = 0;
+ return -ENOMEM;
+ }
+
+ sbi->s_partitions = count;
+ return 0;
+}
+
+static void udf_sb_free_bitmap(struct udf_bitmap *bitmap)
+{
+ int i;
+ int nr_groups = bitmap->s_nr_groups;
+ int size = sizeof(struct udf_bitmap) + (sizeof(struct buffer_head *) *
+ nr_groups);
+
+ for (i = 0; i < nr_groups; i++)
+ if (bitmap->s_block_bitmap[i])
+ brelse(bitmap->s_block_bitmap[i]);
+
+ if (size <= PAGE_SIZE)
+ kfree(bitmap);
+ else
+ vfree(bitmap);
+}
+
+static void udf_free_partition(struct udf_part_map *map)
+{
+ int i;
+ struct udf_meta_data *mdata;
+
+ if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE)
+ iput(map->s_uspace.s_table);
+ if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE)
+ iput(map->s_fspace.s_table);
+ if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP)
+ udf_sb_free_bitmap(map->s_uspace.s_bitmap);
+ if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP)
+ udf_sb_free_bitmap(map->s_fspace.s_bitmap);
+ if (map->s_partition_type == UDF_SPARABLE_MAP15)
+ for (i = 0; i < 4; i++)
+ brelse(map->s_type_specific.s_sparing.s_spar_map[i]);
+ else if (map->s_partition_type == UDF_METADATA_MAP25) {
+ mdata = &map->s_type_specific.s_metadata;
+ iput(mdata->s_metadata_fe);
+ mdata->s_metadata_fe = NULL;
+
+ iput(mdata->s_mirror_fe);
+ mdata->s_mirror_fe = NULL;
+
+ iput(mdata->s_bitmap_fe);
+ mdata->s_bitmap_fe = NULL;
+ }
+}
+
+static void udf_sb_free_partitions(struct super_block *sb)
+{
+ struct udf_sb_info *sbi = UDF_SB(sb);
+ int i;
+ if (sbi->s_partmaps == NULL)
+ return;
+ for (i = 0; i < sbi->s_partitions; i++)
+ udf_free_partition(&sbi->s_partmaps[i]);
+ kfree(sbi->s_partmaps);
+ sbi->s_partmaps = NULL;
+}
+
+static int udf_show_options(struct seq_file *seq, struct dentry *root)
+{
+ struct super_block *sb = root->d_sb;
+ struct udf_sb_info *sbi = UDF_SB(sb);
+
+ if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT))
+ seq_puts(seq, ",nostrict");
+ if (UDF_QUERY_FLAG(sb, UDF_FLAG_BLOCKSIZE_SET))
+ seq_printf(seq, ",bs=%lu", sb->s_blocksize);
+ if (UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE))
+ seq_puts(seq, ",unhide");
+ if (UDF_QUERY_FLAG(sb, UDF_FLAG_UNDELETE))
+ seq_puts(seq, ",undelete");
+ if (!UDF_QUERY_FLAG(sb, UDF_FLAG_USE_AD_IN_ICB))
+ seq_puts(seq, ",noadinicb");
+ if (UDF_QUERY_FLAG(sb, UDF_FLAG_USE_SHORT_AD))
+ 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))
+ seq_printf(seq, ",gid=%u", from_kgid(&init_user_ns, sbi->s_gid));
+ if (sbi->s_umask != 0)
+ seq_printf(seq, ",umask=%ho", sbi->s_umask);
+ if (sbi->s_fmode != UDF_INVALID_MODE)
+ seq_printf(seq, ",mode=%ho", sbi->s_fmode);
+ if (sbi->s_dmode != UDF_INVALID_MODE)
+ seq_printf(seq, ",dmode=%ho", sbi->s_dmode);
+ if (UDF_QUERY_FLAG(sb, UDF_FLAG_SESSION_SET))
+ seq_printf(seq, ",session=%u", sbi->s_session);
+ if (UDF_QUERY_FLAG(sb, UDF_FLAG_LASTBLOCK_SET))
+ 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)
+ seq_printf(seq, ",iocharset=%s", sbi->s_nls_map->charset);
+
+ return 0;
+}
+
/*
* udf_parse_options
*
@@ -225,6 +397,8 @@ module_exit(exit_udf_fs)
*
* gid= Set the default group.
* umask= Set the default umask.
+ * mode= Set the default file permissions.
+ * dmode= Set the default directory permissions.
* uid= Set the default user.
* bs= Set the block size.
* unhide Show otherwise hidden files.
@@ -238,7 +412,7 @@ module_exit(exit_udf_fs)
*
* The remaining are for debugging and disaster recovery:
*
- * novrs Skip volume sequence recognition
+ * novrs Skip volume sequence recognition
*
* The following expect a offset from 0.
*
@@ -274,42 +448,48 @@ enum {
Opt_gid, Opt_uid, Opt_umask, Opt_session, Opt_lastblock,
Opt_anchor, Opt_volume, Opt_partition, Opt_fileset,
Opt_rootdir, Opt_utf8, Opt_iocharset,
- Opt_err
+ Opt_err, Opt_uforget, Opt_uignore, Opt_gforget, Opt_gignore,
+ Opt_fmode, Opt_dmode
};
-static match_table_t tokens = {
- {Opt_novrs, "novrs"},
- {Opt_nostrict, "nostrict"},
- {Opt_bs, "bs=%u"},
- {Opt_unhide, "unhide"},
- {Opt_undelete, "undelete"},
- {Opt_noadinicb, "noadinicb"},
- {Opt_adinicb, "adinicb"},
- {Opt_shortad, "shortad"},
- {Opt_longad, "longad"},
- {Opt_gid, "gid=%u"},
- {Opt_uid, "uid=%u"},
- {Opt_umask, "umask=%o"},
- {Opt_session, "session=%u"},
- {Opt_lastblock, "lastblock=%u"},
- {Opt_anchor, "anchor=%u"},
- {Opt_volume, "volume=%u"},
- {Opt_partition, "partition=%u"},
- {Opt_fileset, "fileset=%u"},
- {Opt_rootdir, "rootdir=%u"},
- {Opt_utf8, "utf8"},
- {Opt_iocharset, "iocharset=%s"},
- {Opt_err, NULL}
+static const match_table_t tokens = {
+ {Opt_novrs, "novrs"},
+ {Opt_nostrict, "nostrict"},
+ {Opt_bs, "bs=%u"},
+ {Opt_unhide, "unhide"},
+ {Opt_undelete, "undelete"},
+ {Opt_noadinicb, "noadinicb"},
+ {Opt_adinicb, "adinicb"},
+ {Opt_shortad, "shortad"},
+ {Opt_longad, "longad"},
+ {Opt_uforget, "uid=forget"},
+ {Opt_uignore, "uid=ignore"},
+ {Opt_gforget, "gid=forget"},
+ {Opt_gignore, "gid=ignore"},
+ {Opt_gid, "gid=%u"},
+ {Opt_uid, "uid=%u"},
+ {Opt_umask, "umask=%o"},
+ {Opt_session, "session=%u"},
+ {Opt_lastblock, "lastblock=%u"},
+ {Opt_anchor, "anchor=%u"},
+ {Opt_volume, "volume=%u"},
+ {Opt_partition, "partition=%u"},
+ {Opt_fileset, "fileset=%u"},
+ {Opt_rootdir, "rootdir=%u"},
+ {Opt_utf8, "utf8"},
+ {Opt_iocharset, "iocharset=%s"},
+ {Opt_fmode, "mode=%o"},
+ {Opt_dmode, "dmode=%o"},
+ {Opt_err, NULL}
};
-static int
-udf_parse_options(char *options, struct udf_options *uopt)
+static int udf_parse_options(char *options, struct udf_options *uopt,
+ bool remount)
{
char *p;
int option;
uopt->novrs = 0;
- uopt->blocksize = 2048;
uopt->partition = 0xFFFF;
uopt->session = 0xFFFFFFFF;
uopt->lastblock = 0;
@@ -322,221 +502,227 @@ udf_parse_options(char *options, struct udf_options *uopt)
if (!options)
return 1;
- while ((p = strsep(&options, ",")) != NULL)
- {
+ while ((p = strsep(&options, ",")) != NULL) {
substring_t args[MAX_OPT_ARGS];
int token;
+ unsigned n;
if (!*p)
continue;
token = match_token(p, tokens, args);
- switch (token)
- {
- case Opt_novrs:
- uopt->novrs = 1;
- case Opt_bs:
- if (match_int(&args[0], &option))
- return 0;
- uopt->blocksize = option;
- break;
- case Opt_unhide:
- uopt->flags |= (1 << UDF_FLAG_UNHIDE);
- break;
- case Opt_undelete:
- uopt->flags |= (1 << UDF_FLAG_UNDELETE);
- break;
- case Opt_noadinicb:
- uopt->flags &= ~(1 << UDF_FLAG_USE_AD_IN_ICB);
- break;
- case Opt_adinicb:
- uopt->flags |= (1 << UDF_FLAG_USE_AD_IN_ICB);
- break;
- case Opt_shortad:
- uopt->flags |= (1 << UDF_FLAG_USE_SHORT_AD);
- break;
- case Opt_longad:
- uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD);
- break;
- case Opt_gid:
- if (match_int(args, &option))
- return 0;
- uopt->gid = option;
- break;
- case Opt_uid:
- if (match_int(args, &option))
- return 0;
- uopt->uid = option;
- break;
- case Opt_umask:
- if (match_octal(args, &option))
- return 0;
- uopt->umask = option;
- break;
- case Opt_nostrict:
- uopt->flags &= ~(1 << UDF_FLAG_STRICT);
- break;
- case Opt_session:
- if (match_int(args, &option))
- return 0;
- uopt->session = option;
- break;
- case Opt_lastblock:
- if (match_int(args, &option))
- return 0;
- uopt->lastblock = option;
- break;
- case Opt_anchor:
- if (match_int(args, &option))
- return 0;
- 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;
- break;
- case Opt_utf8:
- uopt->flags |= (1 << UDF_FLAG_UTF8);
- break;
+ switch (token) {
+ case Opt_novrs:
+ uopt->novrs = 1;
+ break;
+ case Opt_bs:
+ if (match_int(&args[0], &option))
+ return 0;
+ n = option;
+ if (n != 512 && n != 1024 && n != 2048 && n != 4096)
+ return 0;
+ uopt->blocksize = n;
+ uopt->flags |= (1 << UDF_FLAG_BLOCKSIZE_SET);
+ break;
+ case Opt_unhide:
+ uopt->flags |= (1 << UDF_FLAG_UNHIDE);
+ break;
+ case Opt_undelete:
+ uopt->flags |= (1 << UDF_FLAG_UNDELETE);
+ break;
+ case Opt_noadinicb:
+ uopt->flags &= ~(1 << UDF_FLAG_USE_AD_IN_ICB);
+ break;
+ case Opt_adinicb:
+ uopt->flags |= (1 << UDF_FLAG_USE_AD_IN_ICB);
+ break;
+ case Opt_shortad:
+ uopt->flags |= (1 << UDF_FLAG_USE_SHORT_AD);
+ break;
+ case Opt_longad:
+ uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD);
+ break;
+ case Opt_gid:
+ if (match_int(args, &option))
+ return 0;
+ uopt->gid = make_kgid(current_user_ns(), option);
+ if (!gid_valid(uopt->gid))
+ return 0;
+ uopt->flags |= (1 << UDF_FLAG_GID_SET);
+ break;
+ case Opt_uid:
+ if (match_int(args, &option))
+ return 0;
+ uopt->uid = make_kuid(current_user_ns(), option);
+ if (!uid_valid(uopt->uid))
+ return 0;
+ uopt->flags |= (1 << UDF_FLAG_UID_SET);
+ break;
+ case Opt_umask:
+ if (match_octal(args, &option))
+ return 0;
+ uopt->umask = option;
+ break;
+ case Opt_nostrict:
+ uopt->flags &= ~(1 << UDF_FLAG_STRICT);
+ break;
+ case Opt_session:
+ if (match_int(args, &option))
+ return 0;
+ uopt->session = option;
+ if (!remount)
+ uopt->flags |= (1 << UDF_FLAG_SESSION_SET);
+ break;
+ case Opt_lastblock:
+ if (match_int(args, &option))
+ return 0;
+ uopt->lastblock = option;
+ if (!remount)
+ uopt->flags |= (1 << UDF_FLAG_LASTBLOCK_SET);
+ break;
+ case Opt_anchor:
+ if (match_int(args, &option))
+ return 0;
+ 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;
+ 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);
- break;
+ case Opt_iocharset:
+ uopt->nls_map = load_nls(args[0].from);
+ uopt->flags |= (1 << UDF_FLAG_NLS_MAP);
+ break;
#endif
- default:
- printk(KERN_ERR "udf: bad mount option \"%s\" "
- "or missing value\n", p);
+ case Opt_uignore:
+ uopt->flags |= (1 << UDF_FLAG_UID_IGNORE);
+ break;
+ case Opt_uforget:
+ uopt->flags |= (1 << UDF_FLAG_UID_FORGET);
+ break;
+ case Opt_gignore:
+ uopt->flags |= (1 << UDF_FLAG_GID_IGNORE);
+ break;
+ case Opt_gforget:
+ uopt->flags |= (1 << UDF_FLAG_GID_FORGET);
+ break;
+ case Opt_fmode:
+ if (match_octal(args, &option))
+ return 0;
+ uopt->fmode = option & 0777;
+ break;
+ case Opt_dmode:
+ if (match_octal(args, &option))
+ return 0;
+ uopt->dmode = option & 0777;
+ break;
+ default:
+ pr_err("bad mount option \"%s\" or missing value\n", p);
return 0;
}
}
return 1;
}
-void
-udf_write_super(struct super_block *sb)
-{
- lock_kernel();
- if (!(sb->s_flags & MS_RDONLY))
- udf_open_lvid(sb);
- sb->s_dirt = 0;
- unlock_kernel();
-}
-
-static int
-udf_remount_fs(struct super_block *sb, int *flags, char *options)
+static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
{
struct udf_options uopt;
+ struct udf_sb_info *sbi = UDF_SB(sb);
+ int error = 0;
+ struct logicalVolIntegrityDescImpUse *lvidiu = udf_sb_lvidiu(sb);
+
+ sync_filesystem(sb);
+ if (lvidiu) {
+ int write_rev = le16_to_cpu(lvidiu->minUDFWriteRev);
+ if (write_rev > UDF_MAX_WRITE_VERSION && !(*flags & MS_RDONLY))
+ return -EACCES;
+ }
- uopt.flags = UDF_SB(sb)->s_flags ;
- uopt.uid = UDF_SB(sb)->s_uid ;
- uopt.gid = UDF_SB(sb)->s_gid ;
- uopt.umask = UDF_SB(sb)->s_umask ;
+ uopt.flags = sbi->s_flags;
+ uopt.uid = sbi->s_uid;
+ uopt.gid = sbi->s_gid;
+ uopt.umask = sbi->s_umask;
+ uopt.fmode = sbi->s_fmode;
+ uopt.dmode = sbi->s_dmode;
- if ( !udf_parse_options(options, &uopt) )
+ if (!udf_parse_options(options, &uopt, true))
return -EINVAL;
- UDF_SB(sb)->s_flags = uopt.flags;
- UDF_SB(sb)->s_uid = uopt.uid;
- UDF_SB(sb)->s_gid = uopt.gid;
- UDF_SB(sb)->s_umask = uopt.umask;
-
- if (UDF_SB_LVIDBH(sb)) {
- int write_rev = le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFWriteRev);
- if (write_rev > UDF_MAX_WRITE_VERSION)
- *flags |= MS_RDONLY;
- }
+ write_lock(&sbi->s_cred_lock);
+ sbi->s_flags = uopt.flags;
+ sbi->s_uid = uopt.uid;
+ sbi->s_gid = uopt.gid;
+ sbi->s_umask = uopt.umask;
+ sbi->s_fmode = uopt.fmode;
+ sbi->s_dmode = uopt.dmode;
+ write_unlock(&sbi->s_cred_lock);
if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
- return 0;
+ goto out_unlock;
+
if (*flags & MS_RDONLY)
udf_close_lvid(sb);
else
udf_open_lvid(sb);
- return 0;
+out_unlock:
+ return error;
}
-/*
- * udf_set_blocksize
- *
- * PURPOSE
- * Set the block size to be used in all transfers.
- *
- * DESCRIPTION
- * To allow room for a DMA transfer, it is best to guess big when unsure.
- * This routine picks 2048 bytes as the blocksize when guessing. This
- * should be adequate until devices with larger block sizes become common.
- *
- * Note that the Linux kernel can currently only deal with blocksizes of
- * 512, 1024, 2048, 4096, and 8192 bytes.
- *
- * PRE-CONDITIONS
- * sb Pointer to _locked_ superblock.
- *
- * POST-CONDITIONS
- * sb->s_blocksize Blocksize.
- * sb->s_blocksize_bits log2 of blocksize.
- * <return> 0 Blocksize is valid.
- * <return> 1 Blocksize is invalid.
- *
- * HISTORY
- * July 1, 1997 - Andrew E. Mileski
- * Written, tested, and released.
- */
-static int
-udf_set_blocksize(struct super_block *sb, int bsize)
-{
- if (!sb_min_blocksize(sb, bsize)) {
- udf_debug("Bad block size (%d)\n", bsize);
- printk(KERN_ERR "udf: bad block size (%d)\n", bsize);
- return 0;
- }
- return sb->s_blocksize;
-}
-
-static int
-udf_vrs(struct super_block *sb, int silent)
+/* Check Volume Structure Descriptors (ECMA 167 2/9.1) */
+/* We also check any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */
+static loff_t udf_check_vsd(struct super_block *sb)
{
struct volStructDesc *vsd = NULL;
- int sector = 32768;
+ loff_t sector = VSD_FIRST_SECTOR_OFFSET;
int sectorsize;
struct buffer_head *bh = NULL;
- int iso9660=0;
- int nsr02=0;
- int nsr03=0;
-
- /* Block size must be a multiple of 512 */
- if (sb->s_blocksize & 511)
- return 0;
+ int nsr02 = 0;
+ int nsr03 = 0;
+ struct udf_sb_info *sbi;
+ sbi = UDF_SB(sb);
if (sb->s_blocksize < sizeof(struct volStructDesc))
sectorsize = sizeof(struct volStructDesc);
else
sectorsize = sb->s_blocksize;
- sector += (UDF_SB_SESSION(sb) << sb->s_blocksize_bits);
+ sector += (sbi->s_session << sb->s_blocksize_bits);
udf_debug("Starting at sector %u (%ld byte sectors)\n",
- (sector >> sb->s_blocksize_bits), sb->s_blocksize);
- /* Process the sequence (if applicable) */
- for (;!nsr02 && !nsr03; sector += sectorsize)
- {
+ (unsigned int)(sector >> sb->s_blocksize_bits),
+ sb->s_blocksize);
+ /* Process the sequence (if applicable). The hard limit on the sector
+ * offset is arbitrary, hopefully large enough so that all valid UDF
+ * filesystems will be recognised. There is no mention of an upper
+ * bound to the size of the volume recognition area in the standard.
+ * The limit will prevent the code to read all the sectors of a
+ * specially crafted image (like a bluray disc full of CD001 sectors),
+ * potentially causing minutes or even hours of uninterruptible I/O
+ * activity. This actually happened with uninitialised SSD partitions
+ * (all 0xFF) before the check for the limit and all valid IDs were
+ * added */
+ for (; !nsr02 && !nsr03 && sector < VSD_MAX_SECTOR_OFFSET;
+ sector += sectorsize) {
/* Read a block */
bh = udf_tread(sb, sector >> sb->s_blocksize_bits);
if (!bh)
@@ -544,362 +730,308 @@ udf_vrs(struct super_block *sb, int silent)
/* Look for ISO descriptors */
vsd = (struct volStructDesc *)(bh->b_data +
- (sector & (sb->s_blocksize - 1)));
+ (sector & (sb->s_blocksize - 1)));
- if (vsd->stdIdent[0] == 0)
- {
- udf_release_data(bh);
- break;
- }
- else if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001, VSD_STD_ID_LEN))
- {
- iso9660 = sector;
- switch (vsd->structType)
- {
- case 0:
- udf_debug("ISO9660 Boot Record found\n");
- break;
- case 1:
- udf_debug("ISO9660 Primary Volume Descriptor found\n");
- break;
- case 2:
- udf_debug("ISO9660 Supplementary Volume Descriptor found\n");
- break;
- case 3:
- udf_debug("ISO9660 Volume Partition Descriptor found\n");
- break;
- case 255:
- udf_debug("ISO9660 Volume Descriptor Set Terminator found\n");
- break;
- default:
- udf_debug("ISO9660 VRS (%u) found\n", vsd->structType);
- break;
+ if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001,
+ VSD_STD_ID_LEN)) {
+ switch (vsd->structType) {
+ case 0:
+ udf_debug("ISO9660 Boot Record found\n");
+ break;
+ case 1:
+ udf_debug("ISO9660 Primary Volume Descriptor found\n");
+ break;
+ case 2:
+ udf_debug("ISO9660 Supplementary Volume Descriptor found\n");
+ break;
+ case 3:
+ udf_debug("ISO9660 Volume Partition Descriptor found\n");
+ break;
+ case 255:
+ udf_debug("ISO9660 Volume Descriptor Set Terminator found\n");
+ break;
+ default:
+ udf_debug("ISO9660 VRS (%u) found\n",
+ vsd->structType);
+ break;
}
- }
- else if (!strncmp(vsd->stdIdent, VSD_STD_ID_BEA01, VSD_STD_ID_LEN))
- {
- }
- else if (!strncmp(vsd->stdIdent, VSD_STD_ID_TEA01, VSD_STD_ID_LEN))
- {
- udf_release_data(bh);
+ } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_BEA01,
+ VSD_STD_ID_LEN))
+ ; /* nothing */
+ else if (!strncmp(vsd->stdIdent, VSD_STD_ID_TEA01,
+ VSD_STD_ID_LEN)) {
+ brelse(bh);
break;
- }
- else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR02, VSD_STD_ID_LEN))
- {
+ } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR02,
+ VSD_STD_ID_LEN))
nsr02 = sector;
- }
- else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR03, VSD_STD_ID_LEN))
- {
+ else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR03,
+ VSD_STD_ID_LEN))
nsr03 = sector;
+ else if (!strncmp(vsd->stdIdent, VSD_STD_ID_BOOT2,
+ VSD_STD_ID_LEN))
+ ; /* nothing */
+ else if (!strncmp(vsd->stdIdent, VSD_STD_ID_CDW02,
+ VSD_STD_ID_LEN))
+ ; /* nothing */
+ else {
+ /* invalid id : end of volume recognition area */
+ brelse(bh);
+ break;
}
- udf_release_data(bh);
+ brelse(bh);
}
if (nsr03)
return nsr03;
else if (nsr02)
return nsr02;
- else if (sector - (UDF_SB_SESSION(sb) << sb->s_blocksize_bits) == 32768)
+ else if (!bh && sector - (sbi->s_session << sb->s_blocksize_bits) ==
+ VSD_FIRST_SECTOR_OFFSET)
return -1;
else
return 0;
}
-/*
- * udf_find_anchor
- *
- * PURPOSE
- * Find an anchor volume descriptor.
- *
- * PRE-CONDITIONS
- * sb Pointer to _locked_ superblock.
- * lastblock Last block on media.
- *
- * POST-CONDITIONS
- * <return> 1 if not found, 0 if ok
- *
- * HISTORY
- * July 1, 1997 - Andrew E. Mileski
- * Written, tested, and released.
- */
-static void
-udf_find_anchor(struct super_block *sb)
-{
- int lastblock = UDF_SB_LASTBLOCK(sb);
- struct buffer_head *bh = NULL;
- uint16_t ident;
- uint32_t location;
- int i;
-
- if (lastblock)
- {
- int varlastblock = udf_variable_to_fixed(lastblock);
- int last[] = { lastblock, lastblock - 2,
- lastblock - 150, lastblock - 152,
- varlastblock, varlastblock - 2,
- varlastblock - 150, varlastblock - 152 };
-
- lastblock = 0;
-
- /* Search for an anchor volume descriptor pointer */
-
- /* according to spec, anchor is in either:
- * block 256
- * lastblock-256
- * lastblock
- * however, if the disc isn't closed, it could be 512 */
-
- for (i=0; (!lastblock && i<sizeof(last)/sizeof(int)); i++)
- {
- if (last[i] < 0 || !(bh = sb_bread(sb, last[i])))
- {
- ident = location = 0;
- }
- else
- {
- ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
- location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
- udf_release_data(bh);
- }
-
- if (ident == TAG_IDENT_AVDP)
- {
- if (location == last[i] - UDF_SB_SESSION(sb))
- {
- lastblock = UDF_SB_ANCHOR(sb)[0] = last[i] - UDF_SB_SESSION(sb);
- UDF_SB_ANCHOR(sb)[1] = last[i] - 256 - UDF_SB_SESSION(sb);
- }
- else if (location == udf_variable_to_fixed(last[i]) - UDF_SB_SESSION(sb))
- {
- UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
- lastblock = UDF_SB_ANCHOR(sb)[0] = udf_variable_to_fixed(last[i]) - UDF_SB_SESSION(sb);
- UDF_SB_ANCHOR(sb)[1] = lastblock - 256 - UDF_SB_SESSION(sb);
- }
- else
- udf_debug("Anchor found at block %d, location mismatch %d.\n",
- last[i], location);
- }
- else if (ident == TAG_IDENT_FE || ident == TAG_IDENT_EFE)
- {
- lastblock = last[i];
- UDF_SB_ANCHOR(sb)[3] = 512;
- }
- else
- {
- if (last[i] < 256 || !(bh = sb_bread(sb, last[i] - 256)))
- {
- ident = location = 0;
- }
- else
- {
- ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
- location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
- udf_release_data(bh);
- }
-
- if (ident == TAG_IDENT_AVDP &&
- location == last[i] - 256 - UDF_SB_SESSION(sb))
- {
- lastblock = last[i];
- UDF_SB_ANCHOR(sb)[1] = last[i] - 256;
- }
- else
- {
- if (last[i] < 312 + UDF_SB_SESSION(sb) || !(bh = sb_bread(sb, last[i] - 312 - UDF_SB_SESSION(sb))))
- {
- ident = location = 0;
- }
- else
- {
- ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
- location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
- udf_release_data(bh);
- }
-
- if (ident == TAG_IDENT_AVDP &&
- location == udf_variable_to_fixed(last[i]) - 256)
- {
- UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
- lastblock = udf_variable_to_fixed(last[i]);
- UDF_SB_ANCHOR(sb)[1] = lastblock - 256;
- }
- }
- }
- }
- }
-
- if (!lastblock)
- {
- /* We havn't found the lastblock. check 312 */
- if ((bh = sb_bread(sb, 312 + UDF_SB_SESSION(sb))))
- {
- ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
- location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
- udf_release_data(bh);
-
- if (ident == TAG_IDENT_AVDP && location == 256)
- UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
- }
- }
-
- for (i=0; i<sizeof(UDF_SB_ANCHOR(sb))/sizeof(int); i++)
- {
- if (UDF_SB_ANCHOR(sb)[i])
- {
- if (!(bh = udf_read_tagged(sb,
- UDF_SB_ANCHOR(sb)[i], UDF_SB_ANCHOR(sb)[i], &ident)))
- {
- UDF_SB_ANCHOR(sb)[i] = 0;
- }
- else
- {
- udf_release_data(bh);
- if ((ident != TAG_IDENT_AVDP) && (i ||
- (ident != TAG_IDENT_FE && ident != TAG_IDENT_EFE)))
- {
- UDF_SB_ANCHOR(sb)[i] = 0;
- }
- }
- }
- }
-
- UDF_SB_LASTBLOCK(sb) = lastblock;
-}
-
-static int
-udf_find_fileset(struct super_block *sb, kernel_lb_addr *fileset, kernel_lb_addr *root)
+static int udf_find_fileset(struct super_block *sb,
+ struct kernel_lb_addr *fileset,
+ struct kernel_lb_addr *root)
{
struct buffer_head *bh = NULL;
long lastblock;
uint16_t ident;
+ struct udf_sb_info *sbi;
if (fileset->logicalBlockNum != 0xFFFFFFFF ||
- fileset->partitionReferenceNum != 0xFFFF)
- {
- bh = udf_read_ptagged(sb, *fileset, 0, &ident);
+ fileset->partitionReferenceNum != 0xFFFF) {
+ bh = udf_read_ptagged(sb, fileset, 0, &ident);
- if (!bh)
+ if (!bh) {
return 1;
- else if (ident != TAG_IDENT_FSD)
- {
- udf_release_data(bh);
+ } else if (ident != TAG_IDENT_FSD) {
+ brelse(bh);
return 1;
}
-
+
}
- if (!bh) /* Search backwards through the partitions */
- {
- kernel_lb_addr newfileset;
+ sbi = UDF_SB(sb);
+ if (!bh) {
+ /* Search backwards through the partitions */
+ struct kernel_lb_addr newfileset;
+/* --> cvg: FIXME - is it reasonable? */
return 1;
-
- for (newfileset.partitionReferenceNum=UDF_SB_NUMPARTS(sb)-1;
- (newfileset.partitionReferenceNum != 0xFFFF &&
- fileset->logicalBlockNum == 0xFFFFFFFF &&
- fileset->partitionReferenceNum == 0xFFFF);
- newfileset.partitionReferenceNum--)
- {
- lastblock = UDF_SB_PARTLEN(sb, newfileset.partitionReferenceNum);
+
+ for (newfileset.partitionReferenceNum = sbi->s_partitions - 1;
+ (newfileset.partitionReferenceNum != 0xFFFF &&
+ fileset->logicalBlockNum == 0xFFFFFFFF &&
+ fileset->partitionReferenceNum == 0xFFFF);
+ newfileset.partitionReferenceNum--) {
+ lastblock = sbi->s_partmaps
+ [newfileset.partitionReferenceNum]
+ .s_partition_len;
newfileset.logicalBlockNum = 0;
- do
- {
- bh = udf_read_ptagged(sb, newfileset, 0, &ident);
- if (!bh)
- {
- newfileset.logicalBlockNum ++;
+ do {
+ bh = udf_read_ptagged(sb, &newfileset, 0,
+ &ident);
+ if (!bh) {
+ newfileset.logicalBlockNum++;
continue;
}
- switch (ident)
+ switch (ident) {
+ case TAG_IDENT_SBD:
{
- case TAG_IDENT_SBD:
- {
- struct spaceBitmapDesc *sp;
- sp = (struct spaceBitmapDesc *)bh->b_data;
- newfileset.logicalBlockNum += 1 +
- ((le32_to_cpu(sp->numOfBytes) + sizeof(struct spaceBitmapDesc) - 1)
- >> sb->s_blocksize_bits);
- udf_release_data(bh);
- break;
- }
- case TAG_IDENT_FSD:
- {
- *fileset = newfileset;
- break;
- }
- default:
- {
- newfileset.logicalBlockNum ++;
- udf_release_data(bh);
- bh = NULL;
- break;
- }
+ struct spaceBitmapDesc *sp;
+ sp = (struct spaceBitmapDesc *)
+ bh->b_data;
+ newfileset.logicalBlockNum += 1 +
+ ((le32_to_cpu(sp->numOfBytes) +
+ sizeof(struct spaceBitmapDesc)
+ - 1) >> sb->s_blocksize_bits);
+ brelse(bh);
+ break;
}
- }
- while (newfileset.logicalBlockNum < lastblock &&
- fileset->logicalBlockNum == 0xFFFFFFFF &&
- fileset->partitionReferenceNum == 0xFFFF);
+ case TAG_IDENT_FSD:
+ *fileset = newfileset;
+ break;
+ default:
+ newfileset.logicalBlockNum++;
+ brelse(bh);
+ bh = NULL;
+ break;
+ }
+ } while (newfileset.logicalBlockNum < lastblock &&
+ fileset->logicalBlockNum == 0xFFFFFFFF &&
+ fileset->partitionReferenceNum == 0xFFFF);
}
}
if ((fileset->logicalBlockNum != 0xFFFFFFFF ||
- fileset->partitionReferenceNum != 0xFFFF) && bh)
- {
+ fileset->partitionReferenceNum != 0xFFFF) && bh) {
udf_debug("Fileset at block=%d, partition=%d\n",
- fileset->logicalBlockNum, fileset->partitionReferenceNum);
+ fileset->logicalBlockNum,
+ fileset->partitionReferenceNum);
- UDF_SB_PARTITION(sb) = fileset->partitionReferenceNum;
+ sbi->s_partition = fileset->partitionReferenceNum;
udf_load_fileset(sb, bh, root);
- udf_release_data(bh);
+ brelse(bh);
return 0;
}
return 1;
}
-static void
-udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh)
+/*
+ * Load primary Volume Descriptor Sequence
+ *
+ * Return <0 on error, 0 on success. -EAGAIN is special meaning next sequence
+ * should be tried.
+ */
+static int udf_load_pvoldesc(struct super_block *sb, sector_t block)
{
struct primaryVolDesc *pvoldesc;
- time_t recording;
- long recording_usec;
- struct ustr instr;
- struct ustr outstr;
+ struct ustr *instr, *outstr;
+ struct buffer_head *bh;
+ uint16_t ident;
+ int ret = -ENOMEM;
+
+ instr = kmalloc(sizeof(struct ustr), GFP_NOFS);
+ if (!instr)
+ return -ENOMEM;
+
+ outstr = kmalloc(sizeof(struct ustr), GFP_NOFS);
+ if (!outstr)
+ goto out1;
+
+ bh = udf_read_tagged(sb, block, block, &ident);
+ if (!bh) {
+ ret = -EAGAIN;
+ goto out2;
+ }
+
+ if (ident != TAG_IDENT_PVD) {
+ ret = -EIO;
+ goto out_bh;
+ }
pvoldesc = (struct primaryVolDesc *)bh->b_data;
- if ( udf_stamp_to_time(&recording, &recording_usec,
- lets_to_cpu(pvoldesc->recordingDateAndTime)) )
- {
- kernel_timestamp ts;
- ts = lets_to_cpu(pvoldesc->recordingDateAndTime);
- udf_debug("recording time %ld/%ld, %04u/%02u/%02u %02u:%02u (%x)\n",
- recording, recording_usec,
- ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.typeAndTimezone);
- UDF_SB_RECORDTIME(sb).tv_sec = recording;
- UDF_SB_RECORDTIME(sb).tv_nsec = recording_usec * 1000;
- }
-
- if ( !udf_build_ustr(&instr, pvoldesc->volIdent, 32) )
- {
- if (udf_CS0toUTF8(&outstr, &instr))
- {
- strncpy( UDF_SB_VOLIDENT(sb), outstr.u_name,
- outstr.u_len > 31 ? 31 : outstr.u_len);
- udf_debug("volIdent[] = '%s'\n", UDF_SB_VOLIDENT(sb));
+ if (udf_disk_stamp_to_time(&UDF_SB(sb)->s_record_time,
+ pvoldesc->recordingDateAndTime)) {
+#ifdef UDFFS_DEBUG
+ struct timestamp *ts = &pvoldesc->recordingDateAndTime;
+ udf_debug("recording time %04u/%02u/%02u %02u:%02u (%x)\n",
+ le16_to_cpu(ts->year), ts->month, ts->day, ts->hour,
+ ts->minute, le16_to_cpu(ts->typeAndTimezone));
+#endif
+ }
+
+ if (!udf_build_ustr(instr, pvoldesc->volIdent, 32))
+ if (udf_CS0toUTF8(outstr, instr)) {
+ strncpy(UDF_SB(sb)->s_volume_ident, outstr->u_name,
+ outstr->u_len > 31 ? 31 : outstr->u_len);
+ udf_debug("volIdent[] = '%s'\n",
+ UDF_SB(sb)->s_volume_ident);
}
+
+ if (!udf_build_ustr(instr, pvoldesc->volSetIdent, 128))
+ if (udf_CS0toUTF8(outstr, instr))
+ udf_debug("volSetIdent[] = '%s'\n", outstr->u_name);
+
+ ret = 0;
+out_bh:
+ brelse(bh);
+out2:
+ kfree(outstr);
+out1:
+ kfree(instr);
+ return ret;
+}
+
+struct inode *udf_find_metadata_inode_efe(struct super_block *sb,
+ u32 meta_file_loc, u32 partition_num)
+{
+ struct kernel_lb_addr addr;
+ struct inode *metadata_fe;
+
+ addr.logicalBlockNum = meta_file_loc;
+ addr.partitionReferenceNum = partition_num;
+
+ metadata_fe = udf_iget(sb, &addr);
+
+ if (metadata_fe == NULL)
+ udf_warn(sb, "metadata inode efe not found\n");
+ else if (UDF_I(metadata_fe)->i_alloc_type != ICBTAG_FLAG_AD_SHORT) {
+ udf_warn(sb, "metadata inode efe does not have short allocation descriptors!\n");
+ iput(metadata_fe);
+ metadata_fe = NULL;
}
- if ( !udf_build_ustr(&instr, pvoldesc->volSetIdent, 128) )
- {
- if (udf_CS0toUTF8(&outstr, &instr))
- udf_debug("volSetIdent[] = '%s'\n", outstr.u_name);
+ return metadata_fe;
+}
+
+static int udf_load_metadata_files(struct super_block *sb, int partition)
+{
+ struct udf_sb_info *sbi = UDF_SB(sb);
+ struct udf_part_map *map;
+ struct udf_meta_data *mdata;
+ struct kernel_lb_addr addr;
+
+ map = &sbi->s_partmaps[partition];
+ mdata = &map->s_type_specific.s_metadata;
+
+ /* metadata address */
+ udf_debug("Metadata file location: block = %d part = %d\n",
+ mdata->s_meta_file_loc, map->s_partition_num);
+
+ mdata->s_metadata_fe = udf_find_metadata_inode_efe(sb,
+ mdata->s_meta_file_loc, map->s_partition_num);
+
+ if (mdata->s_metadata_fe == NULL) {
+ /* mirror file entry */
+ udf_debug("Mirror metadata file location: block = %d part = %d\n",
+ mdata->s_mirror_file_loc, map->s_partition_num);
+
+ mdata->s_mirror_fe = udf_find_metadata_inode_efe(sb,
+ mdata->s_mirror_file_loc, map->s_partition_num);
+
+ if (mdata->s_mirror_fe == NULL) {
+ udf_err(sb, "Both metadata and mirror metadata inode efe can not found\n");
+ return -EIO;
+ }
}
+
+ /*
+ * bitmap file entry
+ * Note:
+ * Load only if bitmap file location differs from 0xFFFFFFFF (DCN-5102)
+ */
+ if (mdata->s_bitmap_file_loc != 0xFFFFFFFF) {
+ addr.logicalBlockNum = mdata->s_bitmap_file_loc;
+ addr.partitionReferenceNum = map->s_partition_num;
+
+ udf_debug("Bitmap file location: block = %d part = %d\n",
+ addr.logicalBlockNum, addr.partitionReferenceNum);
+
+ mdata->s_bitmap_fe = udf_iget(sb, &addr);
+ if (mdata->s_bitmap_fe == NULL) {
+ if (sb->s_flags & MS_RDONLY)
+ udf_warn(sb, "bitmap inode efe not found but it's ok since the disc is mounted read-only\n");
+ else {
+ udf_err(sb, "bitmap inode efe not found and attempted read-write mount\n");
+ return -EIO;
+ }
+ }
+ }
+
+ udf_debug("udf_load_metadata_files Ok\n");
+ return 0;
}
-static void
-udf_load_fileset(struct super_block *sb, struct buffer_head *bh, kernel_lb_addr *root)
+static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh,
+ struct kernel_lb_addr *root)
{
struct fileSetDesc *fset;
@@ -907,357 +1039,670 @@ udf_load_fileset(struct super_block *sb, struct buffer_head *bh, kernel_lb_addr
*root = lelb_to_cpu(fset->rootDirectoryICB.extLocation);
- UDF_SB_SERIALNUM(sb) = le16_to_cpu(fset->descTag.tagSerialNum);
+ UDF_SB(sb)->s_serial_number = le16_to_cpu(fset->descTag.tagSerialNum);
+
+ udf_debug("Rootdir at block=%d, partition=%d\n",
+ root->logicalBlockNum, root->partitionReferenceNum);
+}
+
+int udf_compute_nr_groups(struct super_block *sb, u32 partition)
+{
+ struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition];
+ return DIV_ROUND_UP(map->s_partition_len +
+ (sizeof(struct spaceBitmapDesc) << 3),
+ sb->s_blocksize * 8);
+}
+
+static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index)
+{
+ struct udf_bitmap *bitmap;
+ int nr_groups;
+ int size;
+
+ nr_groups = udf_compute_nr_groups(sb, index);
+ size = sizeof(struct udf_bitmap) +
+ (sizeof(struct buffer_head *) * nr_groups);
- udf_debug("Rootdir at block=%d, partition=%d\n",
- root->logicalBlockNum, root->partitionReferenceNum);
+ if (size <= PAGE_SIZE)
+ bitmap = kzalloc(size, GFP_KERNEL);
+ else
+ bitmap = vzalloc(size); /* TODO: get rid of vzalloc */
+
+ if (bitmap == NULL)
+ return NULL;
+
+ bitmap->s_nr_groups = nr_groups;
+ return bitmap;
+}
+
+static int udf_fill_partdesc_info(struct super_block *sb,
+ struct partitionDesc *p, int p_index)
+{
+ struct udf_part_map *map;
+ struct udf_sb_info *sbi = UDF_SB(sb);
+ struct partitionHeaderDesc *phd;
+
+ map = &sbi->s_partmaps[p_index];
+
+ map->s_partition_len = le32_to_cpu(p->partitionLength); /* blocks */
+ map->s_partition_root = le32_to_cpu(p->partitionStartingLocation);
+
+ if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY))
+ map->s_partition_flags |= UDF_PART_FLAG_READ_ONLY;
+ if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_WRITE_ONCE))
+ map->s_partition_flags |= UDF_PART_FLAG_WRITE_ONCE;
+ if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_REWRITABLE))
+ map->s_partition_flags |= UDF_PART_FLAG_REWRITABLE;
+ if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_OVERWRITABLE))
+ map->s_partition_flags |= UDF_PART_FLAG_OVERWRITABLE;
+
+ udf_debug("Partition (%d type %x) starts at physical %d, block length %d\n",
+ p_index, map->s_partition_type,
+ map->s_partition_root, map->s_partition_len);
+
+ if (strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR02) &&
+ strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR03))
+ return 0;
+
+ phd = (struct partitionHeaderDesc *)p->partitionContentsUse;
+ if (phd->unallocSpaceTable.extLength) {
+ struct kernel_lb_addr loc = {
+ .logicalBlockNum = le32_to_cpu(
+ phd->unallocSpaceTable.extPosition),
+ .partitionReferenceNum = p_index,
+ };
+
+ map->s_uspace.s_table = udf_iget(sb, &loc);
+ if (!map->s_uspace.s_table) {
+ udf_debug("cannot load unallocSpaceTable (part %d)\n",
+ p_index);
+ return -EIO;
+ }
+ map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_TABLE;
+ udf_debug("unallocSpaceTable (part %d) @ %ld\n",
+ p_index, map->s_uspace.s_table->i_ino);
+ }
+
+ if (phd->unallocSpaceBitmap.extLength) {
+ struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index);
+ if (!bitmap)
+ return -ENOMEM;
+ map->s_uspace.s_bitmap = bitmap;
+ bitmap->s_extPosition = le32_to_cpu(
+ phd->unallocSpaceBitmap.extPosition);
+ map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP;
+ udf_debug("unallocSpaceBitmap (part %d) @ %d\n",
+ p_index, bitmap->s_extPosition);
+ }
+
+ if (phd->partitionIntegrityTable.extLength)
+ udf_debug("partitionIntegrityTable (part %d)\n", p_index);
+
+ if (phd->freedSpaceTable.extLength) {
+ struct kernel_lb_addr loc = {
+ .logicalBlockNum = le32_to_cpu(
+ phd->freedSpaceTable.extPosition),
+ .partitionReferenceNum = p_index,
+ };
+
+ map->s_fspace.s_table = udf_iget(sb, &loc);
+ if (!map->s_fspace.s_table) {
+ udf_debug("cannot load freedSpaceTable (part %d)\n",
+ p_index);
+ return -EIO;
+ }
+
+ map->s_partition_flags |= UDF_PART_FLAG_FREED_TABLE;
+ udf_debug("freedSpaceTable (part %d) @ %ld\n",
+ p_index, map->s_fspace.s_table->i_ino);
+ }
+
+ if (phd->freedSpaceBitmap.extLength) {
+ struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index);
+ if (!bitmap)
+ return -ENOMEM;
+ map->s_fspace.s_bitmap = bitmap;
+ bitmap->s_extPosition = le32_to_cpu(
+ phd->freedSpaceBitmap.extPosition);
+ map->s_partition_flags |= UDF_PART_FLAG_FREED_BITMAP;
+ udf_debug("freedSpaceBitmap (part %d) @ %d\n",
+ p_index, bitmap->s_extPosition);
+ }
+ return 0;
+}
+
+static void udf_find_vat_block(struct super_block *sb, int p_index,
+ int type1_index, sector_t start_block)
+{
+ struct udf_sb_info *sbi = UDF_SB(sb);
+ struct udf_part_map *map = &sbi->s_partmaps[p_index];
+ sector_t vat_block;
+ struct kernel_lb_addr ino;
+
+ /*
+ * VAT file entry is in the last recorded block. Some broken disks have
+ * it a few blocks before so try a bit harder...
+ */
+ ino.partitionReferenceNum = type1_index;
+ for (vat_block = start_block;
+ vat_block >= map->s_partition_root &&
+ vat_block >= start_block - 3 &&
+ !sbi->s_vat_inode; vat_block--) {
+ ino.logicalBlockNum = vat_block - map->s_partition_root;
+ sbi->s_vat_inode = udf_iget(sb, &ino);
+ }
}
-static void
-udf_load_partdesc(struct super_block *sb, struct buffer_head *bh)
+static int udf_load_vat(struct super_block *sb, int p_index, int type1_index)
{
+ struct udf_sb_info *sbi = UDF_SB(sb);
+ struct udf_part_map *map = &sbi->s_partmaps[p_index];
+ struct buffer_head *bh = NULL;
+ struct udf_inode_info *vati;
+ uint32_t pos;
+ struct virtualAllocationTable20 *vat20;
+ sector_t blocks = sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits;
+
+ udf_find_vat_block(sb, p_index, type1_index, sbi->s_last_block);
+ if (!sbi->s_vat_inode &&
+ sbi->s_last_block != blocks - 1) {
+ pr_notice("Failed to read VAT inode from the last recorded block (%lu), retrying with the last block of the device (%lu).\n",
+ (unsigned long)sbi->s_last_block,
+ (unsigned long)blocks - 1);
+ udf_find_vat_block(sb, p_index, type1_index, blocks - 1);
+ }
+ if (!sbi->s_vat_inode)
+ return -EIO;
+
+ if (map->s_partition_type == UDF_VIRTUAL_MAP15) {
+ map->s_type_specific.s_virtual.s_start_offset = 0;
+ map->s_type_specific.s_virtual.s_num_entries =
+ (sbi->s_vat_inode->i_size - 36) >> 2;
+ } else if (map->s_partition_type == UDF_VIRTUAL_MAP20) {
+ vati = UDF_I(sbi->s_vat_inode);
+ if (vati->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+ pos = udf_block_map(sbi->s_vat_inode, 0);
+ bh = sb_bread(sb, pos);
+ if (!bh)
+ return -EIO;
+ vat20 = (struct virtualAllocationTable20 *)bh->b_data;
+ } else {
+ vat20 = (struct virtualAllocationTable20 *)
+ vati->i_ext.i_data;
+ }
+
+ map->s_type_specific.s_virtual.s_start_offset =
+ le16_to_cpu(vat20->lengthHeader);
+ map->s_type_specific.s_virtual.s_num_entries =
+ (sbi->s_vat_inode->i_size -
+ map->s_type_specific.s_virtual.
+ s_start_offset) >> 2;
+ brelse(bh);
+ }
+ return 0;
+}
+
+/*
+ * Load partition descriptor block
+ *
+ * Returns <0 on error, 0 on success, -EAGAIN is special - try next descriptor
+ * sequence.
+ */
+static int udf_load_partdesc(struct super_block *sb, sector_t block)
+{
+ struct buffer_head *bh;
struct partitionDesc *p;
- int i;
+ struct udf_part_map *map;
+ struct udf_sb_info *sbi = UDF_SB(sb);
+ int i, type1_idx;
+ uint16_t partitionNumber;
+ uint16_t ident;
+ int ret;
+
+ bh = udf_read_tagged(sb, block, block, &ident);
+ if (!bh)
+ return -EAGAIN;
+ if (ident != TAG_IDENT_PD) {
+ ret = 0;
+ goto out_bh;
+ }
p = (struct partitionDesc *)bh->b_data;
+ partitionNumber = le16_to_cpu(p->partitionNumber);
+
+ /* First scan for TYPE1, SPARABLE and METADATA partitions */
+ for (i = 0; i < sbi->s_partitions; i++) {
+ map = &sbi->s_partmaps[i];
+ udf_debug("Searching map: (%d == %d)\n",
+ map->s_partition_num, partitionNumber);
+ if (map->s_partition_num == partitionNumber &&
+ (map->s_partition_type == UDF_TYPE1_MAP15 ||
+ map->s_partition_type == UDF_SPARABLE_MAP15))
+ break;
+ }
- for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
- {
- udf_debug("Searching map: (%d == %d)\n",
- UDF_SB_PARTMAPS(sb)[i].s_partition_num, le16_to_cpu(p->partitionNumber));
- if (UDF_SB_PARTMAPS(sb)[i].s_partition_num == le16_to_cpu(p->partitionNumber))
- {
- UDF_SB_PARTLEN(sb,i) = le32_to_cpu(p->partitionLength); /* blocks */
- UDF_SB_PARTROOT(sb,i) = le32_to_cpu(p->partitionStartingLocation);
- if (le32_to_cpu(p->accessType) == PD_ACCESS_TYPE_READ_ONLY)
- UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_READ_ONLY;
- if (le32_to_cpu(p->accessType) == PD_ACCESS_TYPE_WRITE_ONCE)
- UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_WRITE_ONCE;
- if (le32_to_cpu(p->accessType) == PD_ACCESS_TYPE_REWRITABLE)
- UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_REWRITABLE;
- if (le32_to_cpu(p->accessType) == PD_ACCESS_TYPE_OVERWRITABLE)
- UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_OVERWRITABLE;
-
- if (!strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR02) ||
- !strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR03))
- {
- struct partitionHeaderDesc *phd;
-
- phd = (struct partitionHeaderDesc *)(p->partitionContentsUse);
- if (phd->unallocSpaceTable.extLength)
- {
- kernel_lb_addr loc = { le32_to_cpu(phd->unallocSpaceTable.extPosition), i };
+ if (i >= sbi->s_partitions) {
+ udf_debug("Partition (%d) not found in partition map\n",
+ partitionNumber);
+ ret = 0;
+ goto out_bh;
+ }
- UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table =
- udf_iget(sb, loc);
- UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_UNALLOC_TABLE;
- udf_debug("unallocSpaceTable (part %d) @ %ld\n",
- i, UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table->i_ino);
- }
- if (phd->unallocSpaceBitmap.extLength)
- {
- UDF_SB_ALLOC_BITMAP(sb, i, s_uspace);
- if (UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap != NULL)
- {
- UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_extLength =
- le32_to_cpu(phd->unallocSpaceBitmap.extLength);
- UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_extPosition =
- le32_to_cpu(phd->unallocSpaceBitmap.extPosition);
- UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_UNALLOC_BITMAP;
- udf_debug("unallocSpaceBitmap (part %d) @ %d\n",
- i, UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_extPosition);
- }
- }
- if (phd->partitionIntegrityTable.extLength)
- udf_debug("partitionIntegrityTable (part %d)\n", i);
- if (phd->freedSpaceTable.extLength)
- {
- kernel_lb_addr loc = { le32_to_cpu(phd->freedSpaceTable.extPosition), i };
+ ret = udf_fill_partdesc_info(sb, p, i);
+ if (ret < 0)
+ goto out_bh;
+
+ /*
+ * Now rescan for VIRTUAL or METADATA partitions when SPARABLE and
+ * PHYSICAL partitions are already set up
+ */
+ type1_idx = i;
+#ifdef UDFFS_DEBUG
+ map = NULL; /* supress 'maybe used uninitialized' warning */
+#endif
+ for (i = 0; i < sbi->s_partitions; i++) {
+ map = &sbi->s_partmaps[i];
- UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table =
- udf_iget(sb, loc);
- UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_FREED_TABLE;
- udf_debug("freedSpaceTable (part %d) @ %ld\n",
- i, UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table->i_ino);
- }
- if (phd->freedSpaceBitmap.extLength)
- {
- UDF_SB_ALLOC_BITMAP(sb, i, s_fspace);
- if (UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap != NULL)
- {
- UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_extLength =
- le32_to_cpu(phd->freedSpaceBitmap.extLength);
- UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_extPosition =
- le32_to_cpu(phd->freedSpaceBitmap.extPosition);
- UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_FREED_BITMAP;
- udf_debug("freedSpaceBitmap (part %d) @ %d\n",
- i, UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_extPosition);
- }
- }
- }
+ if (map->s_partition_num == partitionNumber &&
+ (map->s_partition_type == UDF_VIRTUAL_MAP15 ||
+ map->s_partition_type == UDF_VIRTUAL_MAP20 ||
+ map->s_partition_type == UDF_METADATA_MAP25))
break;
+ }
+
+ if (i >= sbi->s_partitions) {
+ ret = 0;
+ goto out_bh;
+ }
+
+ ret = udf_fill_partdesc_info(sb, p, i);
+ if (ret < 0)
+ goto out_bh;
+
+ if (map->s_partition_type == UDF_METADATA_MAP25) {
+ ret = udf_load_metadata_files(sb, i);
+ if (ret < 0) {
+ udf_err(sb, "error loading MetaData partition map %d\n",
+ i);
+ goto out_bh;
+ }
+ } else {
+ /*
+ * If we have a partition with virtual map, we don't handle
+ * writing to it (we overwrite blocks instead of relocating
+ * them).
+ */
+ if (!(sb->s_flags & MS_RDONLY)) {
+ ret = -EACCES;
+ goto out_bh;
}
+ ret = udf_load_vat(sb, i, type1_idx);
+ if (ret < 0)
+ goto out_bh;
+ }
+ ret = 0;
+out_bh:
+ /* In case loading failed, we handle cleanup in udf_fill_super */
+ brelse(bh);
+ return ret;
+}
+
+static int udf_load_sparable_map(struct super_block *sb,
+ struct udf_part_map *map,
+ struct sparablePartitionMap *spm)
+{
+ uint32_t loc;
+ uint16_t ident;
+ struct sparingTable *st;
+ struct udf_sparing_data *sdata = &map->s_type_specific.s_sparing;
+ int i;
+ struct buffer_head *bh;
+
+ map->s_partition_type = UDF_SPARABLE_MAP15;
+ sdata->s_packet_len = le16_to_cpu(spm->packetLength);
+ if (!is_power_of_2(sdata->s_packet_len)) {
+ udf_err(sb, "error loading logical volume descriptor: "
+ "Invalid packet length %u\n",
+ (unsigned)sdata->s_packet_len);
+ return -EIO;
}
- if (i == UDF_SB_NUMPARTS(sb))
- {
- udf_debug("Partition (%d) not found in partition map\n", le16_to_cpu(p->partitionNumber));
+ if (spm->numSparingTables > 4) {
+ udf_err(sb, "error loading logical volume descriptor: "
+ "Too many sparing tables (%d)\n",
+ (int)spm->numSparingTables);
+ return -EIO;
}
- else
- {
- udf_debug("Partition (%d:%d type %x) starts at physical %d, block length %d\n",
- le16_to_cpu(p->partitionNumber), i, UDF_SB_PARTTYPE(sb,i),
- UDF_SB_PARTROOT(sb,i), UDF_SB_PARTLEN(sb,i));
+
+ for (i = 0; i < spm->numSparingTables; i++) {
+ loc = le32_to_cpu(spm->locSparingTable[i]);
+ bh = udf_read_tagged(sb, loc, loc, &ident);
+ if (!bh)
+ continue;
+
+ st = (struct sparingTable *)bh->b_data;
+ if (ident != 0 ||
+ strncmp(st->sparingIdent.ident, UDF_ID_SPARING,
+ strlen(UDF_ID_SPARING)) ||
+ sizeof(*st) + le16_to_cpu(st->reallocationTableLen) >
+ sb->s_blocksize) {
+ brelse(bh);
+ continue;
+ }
+
+ sdata->s_spar_map[i] = bh;
}
+ map->s_partition_func = udf_get_pblock_spar15;
+ return 0;
}
-static int
-udf_load_logicalvol(struct super_block *sb, struct buffer_head * bh, kernel_lb_addr *fileset)
+static int udf_load_logicalvol(struct super_block *sb, sector_t block,
+ struct kernel_lb_addr *fileset)
{
struct logicalVolDesc *lvd;
- int i, j, offset;
+ int i, offset;
uint8_t type;
+ struct udf_sb_info *sbi = UDF_SB(sb);
+ struct genericPartitionMap *gpm;
+ uint16_t ident;
+ struct buffer_head *bh;
+ unsigned int table_len;
+ int ret;
+ bh = udf_read_tagged(sb, block, block, &ident);
+ if (!bh)
+ return -EAGAIN;
+ BUG_ON(ident != TAG_IDENT_LVD);
lvd = (struct logicalVolDesc *)bh->b_data;
+ table_len = le32_to_cpu(lvd->mapTableLength);
+ if (table_len > sb->s_blocksize - sizeof(*lvd)) {
+ udf_err(sb, "error loading logical volume descriptor: "
+ "Partition table too long (%u > %lu)\n", table_len,
+ sb->s_blocksize - sizeof(*lvd));
+ ret = -EIO;
+ goto out_bh;
+ }
- UDF_SB_ALLOC_PARTMAPS(sb, le32_to_cpu(lvd->numPartitionMaps));
-
- for (i=0,offset=0;
- i<UDF_SB_NUMPARTS(sb) && offset<le32_to_cpu(lvd->mapTableLength);
- i++,offset+=((struct genericPartitionMap *)&(lvd->partitionMaps[offset]))->partitionMapLength)
- {
- type = ((struct genericPartitionMap *)&(lvd->partitionMaps[offset]))->partitionMapType;
- if (type == 1)
- {
- struct genericPartitionMap1 *gpm1 = (struct genericPartitionMap1 *)&(lvd->partitionMaps[offset]);
- UDF_SB_PARTTYPE(sb,i) = UDF_TYPE1_MAP15;
- UDF_SB_PARTVSN(sb,i) = le16_to_cpu(gpm1->volSeqNum);
- UDF_SB_PARTNUM(sb,i) = le16_to_cpu(gpm1->partitionNum);
- UDF_SB_PARTFUNC(sb,i) = NULL;
- }
- else if (type == 2)
- {
- struct udfPartitionMap2 *upm2 = (struct udfPartitionMap2 *)&(lvd->partitionMaps[offset]);
- if (!strncmp(upm2->partIdent.ident, UDF_ID_VIRTUAL, strlen(UDF_ID_VIRTUAL)))
- {
- if (le16_to_cpu(((__le16 *)upm2->partIdent.identSuffix)[0]) == 0x0150)
- {
- UDF_SB_PARTTYPE(sb,i) = UDF_VIRTUAL_MAP15;
- UDF_SB_PARTFUNC(sb,i) = udf_get_pblock_virt15;
- }
- else if (le16_to_cpu(((__le16 *)upm2->partIdent.identSuffix)[0]) == 0x0200)
- {
- UDF_SB_PARTTYPE(sb,i) = UDF_VIRTUAL_MAP20;
- UDF_SB_PARTFUNC(sb,i) = udf_get_pblock_virt20;
+ ret = udf_sb_alloc_partition_maps(sb, le32_to_cpu(lvd->numPartitionMaps));
+ if (ret)
+ goto out_bh;
+
+ for (i = 0, offset = 0;
+ i < sbi->s_partitions && offset < table_len;
+ i++, offset += gpm->partitionMapLength) {
+ struct udf_part_map *map = &sbi->s_partmaps[i];
+ gpm = (struct genericPartitionMap *)
+ &(lvd->partitionMaps[offset]);
+ type = gpm->partitionMapType;
+ if (type == 1) {
+ struct genericPartitionMap1 *gpm1 =
+ (struct genericPartitionMap1 *)gpm;
+ map->s_partition_type = UDF_TYPE1_MAP15;
+ map->s_volumeseqnum = le16_to_cpu(gpm1->volSeqNum);
+ map->s_partition_num = le16_to_cpu(gpm1->partitionNum);
+ map->s_partition_func = NULL;
+ } else if (type == 2) {
+ struct udfPartitionMap2 *upm2 =
+ (struct udfPartitionMap2 *)gpm;
+ if (!strncmp(upm2->partIdent.ident, UDF_ID_VIRTUAL,
+ strlen(UDF_ID_VIRTUAL))) {
+ u16 suf =
+ le16_to_cpu(((__le16 *)upm2->partIdent.
+ identSuffix)[0]);
+ if (suf < 0x0200) {
+ map->s_partition_type =
+ UDF_VIRTUAL_MAP15;
+ map->s_partition_func =
+ udf_get_pblock_virt15;
+ } else {
+ map->s_partition_type =
+ UDF_VIRTUAL_MAP20;
+ map->s_partition_func =
+ udf_get_pblock_virt20;
}
- }
- else if (!strncmp(upm2->partIdent.ident, UDF_ID_SPARABLE, strlen(UDF_ID_SPARABLE)))
- {
- uint32_t loc;
- uint16_t ident;
- struct sparingTable *st;
- struct sparablePartitionMap *spm = (struct sparablePartitionMap *)&(lvd->partitionMaps[offset]);
-
- UDF_SB_PARTTYPE(sb,i) = UDF_SPARABLE_MAP15;
- UDF_SB_TYPESPAR(sb,i).s_packet_len = le16_to_cpu(spm->packetLength);
- for (j=0; j<spm->numSparingTables; j++)
- {
- loc = le32_to_cpu(spm->locSparingTable[j]);
- UDF_SB_TYPESPAR(sb,i).s_spar_map[j] =
- udf_read_tagged(sb, loc, loc, &ident);
- if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL)
- {
- st = (struct sparingTable *)UDF_SB_TYPESPAR(sb,i).s_spar_map[j]->b_data;
- if (ident != 0 ||
- strncmp(st->sparingIdent.ident, UDF_ID_SPARING, strlen(UDF_ID_SPARING)))
- {
- udf_release_data(UDF_SB_TYPESPAR(sb,i).s_spar_map[j]);
- UDF_SB_TYPESPAR(sb,i).s_spar_map[j] = NULL;
- }
- }
- }
- UDF_SB_PARTFUNC(sb,i) = udf_get_pblock_spar15;
- }
- else
- {
- udf_debug("Unknown ident: %s\n", upm2->partIdent.ident);
+ } else if (!strncmp(upm2->partIdent.ident,
+ UDF_ID_SPARABLE,
+ strlen(UDF_ID_SPARABLE))) {
+ ret = udf_load_sparable_map(sb, map,
+ (struct sparablePartitionMap *)gpm);
+ if (ret < 0)
+ goto out_bh;
+ } else if (!strncmp(upm2->partIdent.ident,
+ UDF_ID_METADATA,
+ strlen(UDF_ID_METADATA))) {
+ struct udf_meta_data *mdata =
+ &map->s_type_specific.s_metadata;
+ struct metadataPartitionMap *mdm =
+ (struct metadataPartitionMap *)
+ &(lvd->partitionMaps[offset]);
+ udf_debug("Parsing Logical vol part %d type %d id=%s\n",
+ i, type, UDF_ID_METADATA);
+
+ map->s_partition_type = UDF_METADATA_MAP25;
+ map->s_partition_func = udf_get_pblock_meta25;
+
+ mdata->s_meta_file_loc =
+ le32_to_cpu(mdm->metadataFileLoc);
+ mdata->s_mirror_file_loc =
+ le32_to_cpu(mdm->metadataMirrorFileLoc);
+ mdata->s_bitmap_file_loc =
+ le32_to_cpu(mdm->metadataBitmapFileLoc);
+ mdata->s_alloc_unit_size =
+ le32_to_cpu(mdm->allocUnitSize);
+ mdata->s_align_unit_size =
+ le16_to_cpu(mdm->alignUnitSize);
+ if (mdm->flags & 0x01)
+ mdata->s_flags |= MF_DUPLICATE_MD;
+
+ udf_debug("Metadata Ident suffix=0x%x\n",
+ le16_to_cpu(*(__le16 *)
+ mdm->partIdent.identSuffix));
+ udf_debug("Metadata part num=%d\n",
+ le16_to_cpu(mdm->partitionNum));
+ udf_debug("Metadata part alloc unit size=%d\n",
+ le32_to_cpu(mdm->allocUnitSize));
+ udf_debug("Metadata file loc=%d\n",
+ le32_to_cpu(mdm->metadataFileLoc));
+ udf_debug("Mirror file loc=%d\n",
+ le32_to_cpu(mdm->metadataMirrorFileLoc));
+ udf_debug("Bitmap file loc=%d\n",
+ le32_to_cpu(mdm->metadataBitmapFileLoc));
+ udf_debug("Flags: %d %d\n",
+ mdata->s_flags, mdm->flags);
+ } else {
+ udf_debug("Unknown ident: %s\n",
+ upm2->partIdent.ident);
continue;
}
- UDF_SB_PARTVSN(sb,i) = le16_to_cpu(upm2->volSeqNum);
- UDF_SB_PARTNUM(sb,i) = le16_to_cpu(upm2->partitionNum);
+ map->s_volumeseqnum = le16_to_cpu(upm2->volSeqNum);
+ map->s_partition_num = le16_to_cpu(upm2->partitionNum);
}
udf_debug("Partition (%d:%d) type %d on volume %d\n",
- i, UDF_SB_PARTNUM(sb,i), type, UDF_SB_PARTVSN(sb,i));
+ i, map->s_partition_num, type, map->s_volumeseqnum);
}
- if (fileset)
- {
- long_ad *la = (long_ad *)&(lvd->logicalVolContentsUse[0]);
+ if (fileset) {
+ struct long_ad *la = (struct long_ad *)&(lvd->logicalVolContentsUse[0]);
*fileset = lelb_to_cpu(la->extLocation);
udf_debug("FileSet found in LogicalVolDesc at block=%d, partition=%d\n",
- fileset->logicalBlockNum,
- fileset->partitionReferenceNum);
+ fileset->logicalBlockNum,
+ fileset->partitionReferenceNum);
}
if (lvd->integritySeqExt.extLength)
udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt));
- return 0;
+ ret = 0;
+out_bh:
+ brelse(bh);
+ return ret;
}
/*
* udf_load_logicalvolint
*
*/
-static void
-udf_load_logicalvolint(struct super_block *sb, kernel_extent_ad loc)
+static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_ad loc)
{
struct buffer_head *bh = NULL;
uint16_t ident;
+ struct udf_sb_info *sbi = UDF_SB(sb);
+ struct logicalVolIntegrityDesc *lvid;
while (loc.extLength > 0 &&
- (bh = udf_read_tagged(sb, loc.extLocation,
- loc.extLocation, &ident)) &&
- ident == TAG_IDENT_LVID)
- {
- UDF_SB_LVIDBH(sb) = bh;
-
- if (UDF_SB_LVID(sb)->nextIntegrityExt.extLength)
- udf_load_logicalvolint(sb, leea_to_cpu(UDF_SB_LVID(sb)->nextIntegrityExt));
-
- if (UDF_SB_LVIDBH(sb) != bh)
- udf_release_data(bh);
+ (bh = udf_read_tagged(sb, loc.extLocation,
+ loc.extLocation, &ident)) &&
+ ident == TAG_IDENT_LVID) {
+ sbi->s_lvid_bh = bh;
+ lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
+
+ if (lvid->nextIntegrityExt.extLength)
+ udf_load_logicalvolint(sb,
+ leea_to_cpu(lvid->nextIntegrityExt));
+
+ if (sbi->s_lvid_bh != bh)
+ brelse(bh);
loc.extLength -= sb->s_blocksize;
- loc.extLocation ++;
+ loc.extLocation++;
}
- if (UDF_SB_LVIDBH(sb) != bh)
- udf_release_data(bh);
+ if (sbi->s_lvid_bh != bh)
+ brelse(bh);
}
/*
- * udf_process_sequence
- *
- * PURPOSE
- * Process a main/reserve volume descriptor sequence.
- *
- * PRE-CONDITIONS
- * sb Pointer to _locked_ superblock.
- * block First block of first extent of the sequence.
- * lastblock Lastblock of first extent of the sequence.
+ * Process a main/reserve volume descriptor sequence.
+ * @block First block of first extent of the sequence.
+ * @lastblock Lastblock of first extent of the sequence.
+ * @fileset There we store extent containing root fileset
*
- * HISTORY
- * July 1, 1997 - Andrew E. Mileski
- * Written, tested, and released.
+ * Returns <0 on error, 0 on success. -EAGAIN is special - try next descriptor
+ * sequence
*/
-static int
-udf_process_sequence(struct super_block *sb, long block, long lastblock, kernel_lb_addr *fileset)
+static noinline int udf_process_sequence(
+ struct super_block *sb,
+ sector_t block, sector_t lastblock,
+ 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;
- int done=0;
- int i,j;
+ int done = 0;
uint32_t vdsn;
uint16_t ident;
long next_s = 0, next_e = 0;
+ int ret;
memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH);
- /* Read the main descriptor sequence */
- for (;(!done && block <= lastblock); block++)
- {
+ /*
+ * Read the main descriptor sequence and find which descriptors
+ * are in it.
+ */
+ for (; (!done && block <= lastblock); block++) {
bh = udf_read_tagged(sb, block, block, &ident);
- if (!bh)
- break;
+ 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;
+ }
/* 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 */
- if (vdsn >= vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum)
- {
- vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum = vdsn;
- vds[VDS_POS_PRIMARY_VOL_DESC].block = block;
- }
- break;
- case TAG_IDENT_VDP: /* ISO 13346 3/10.3 */
- if (vdsn >= vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum)
- {
- vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum = vdsn;
- vds[VDS_POS_VOL_DESC_PTR].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;
- }
- break;
- case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */
- if (vdsn >= vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum)
- {
- vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum = vdsn;
- vds[VDS_POS_IMP_USE_VOL_DESC].block = block;
- }
- break;
- case TAG_IDENT_PD: /* ISO 13346 3/10.5 */
- if (!vds[VDS_POS_PARTITION_DESC].block)
- vds[VDS_POS_PARTITION_DESC].block = block;
- break;
- case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */
- if (vdsn >= vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum)
- {
- vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum = vdsn;
- vds[VDS_POS_LOGICAL_VOL_DESC].block = block;
- }
- break;
- case TAG_IDENT_USD: /* ISO 13346 3/10.8 */
- if (vdsn >= vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum)
- {
- vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum = vdsn;
- vds[VDS_POS_UNALLOC_SPACE_DESC].block = block;
- }
- break;
- case TAG_IDENT_TD: /* ISO 13346 3/10.9 */
- vds[VDS_POS_TERMINATING_DESC].block = block;
- if (next_e)
- {
- block = next_s;
- lastblock = next_e;
- next_s = next_e = 0;
- }
- else
- done = 1;
- break;
- }
- udf_release_data(bh);
- }
- for (i=0; i<VDS_POS_LENGTH; i++)
- {
- if (vds[i].block)
- {
- bh = udf_read_tagged(sb, vds[i].block, vds[i].block, &ident);
-
- if (i == VDS_POS_PRIMARY_VOL_DESC)
- udf_load_pvoldesc(sb, bh);
- else if (i == VDS_POS_LOGICAL_VOL_DESC)
- udf_load_logicalvol(sb, bh, fileset);
- else if (i == VDS_POS_PARTITION_DESC)
- {
- struct buffer_head *bh2 = NULL;
- udf_load_partdesc(sb, bh);
- for (j=vds[i].block+1; j<vds[VDS_POS_TERMINATING_DESC].block; j++)
- {
- bh2 = udf_read_tagged(sb, j, j, &ident);
- gd = (struct generic_desc *)bh2->b_data;
- if (ident == TAG_IDENT_PD)
- udf_load_partdesc(sb, bh2);
- udf_release_data(bh2);
- }
+ 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;
+ }
+ break;
+ 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];
+ if (vdsn >= curr->volDescSeqNum) {
+ curr->volDescSeqNum = vdsn;
+ curr->block = block;
}
- udf_release_data(bh);
+ break;
+ case TAG_IDENT_TD: /* ISO 13346 3/10.9 */
+ vds[VDS_POS_TERMINATING_DESC].block = block;
+ if (next_e) {
+ block = next_s;
+ lastblock = next_e;
+ next_s = next_e = 0;
+ } else
+ done = 1;
+ break;
+ }
+ brelse(bh);
+ }
+ /*
+ * Now read interesting descriptors again and process them
+ * in a suitable order
+ */
+ if (!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);
+ if (ret < 0)
+ return ret;
+
+ if (vds[VDS_POS_LOGICAL_VOL_DESC].block) {
+ ret = udf_load_logicalvol(sb,
+ 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);
+ if (ret < 0)
+ return ret;
}
}
@@ -1265,260 +1710,374 @@ udf_process_sequence(struct super_block *sb, long block, long lastblock, kernel_
}
/*
- * udf_check_valid()
+ * Load Volume Descriptor Sequence described by anchor in bh
+ *
+ * Returns <0 on error, 0 on success
*/
-static int
-udf_check_valid(struct super_block *sb, int novrs, int silent)
+static int udf_load_sequence(struct super_block *sb, struct buffer_head *bh,
+ struct kernel_lb_addr *fileset)
{
- long block;
-
- if (novrs)
- {
- udf_debug("Validity check skipped because of novrs option\n");
- return 0;
- }
- /* Check that it is NSR02 compliant */
- /* Process any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */
- else if ((block = udf_vrs(sb, silent)) == -1)
- {
- udf_debug("Failed to read byte 32768. Assuming open disc. Skipping validity check\n");
- if (!UDF_SB_LASTBLOCK(sb))
- UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb);
- return 0;
+ struct anchorVolDescPtr *anchor;
+ sector_t main_s, main_e, reserve_s, reserve_e;
+ int ret;
+
+ anchor = (struct anchorVolDescPtr *)bh->b_data;
+
+ /* Locate the main sequence */
+ 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;
+
+ /* 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;
+
+ /* Process the main & reserve sequences */
+ /* responsible for finding the PartitionDesc(s) */
+ ret = udf_process_sequence(sb, main_s, main_e, fileset);
+ if (ret != -EAGAIN)
+ return ret;
+ udf_sb_free_partitions(sb);
+ ret = udf_process_sequence(sb, reserve_s, reserve_e, fileset);
+ if (ret < 0) {
+ udf_sb_free_partitions(sb);
+ /* No sequence was OK, return -EIO */
+ if (ret == -EAGAIN)
+ ret = -EIO;
}
- else
- return !block;
+ return ret;
}
-static int
-udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
+/*
+ * Check whether there is an anchor block in the given block and
+ * load Volume Descriptor Sequence if so.
+ *
+ * Returns <0 on error, 0 on success, -EAGAIN is special - try next anchor
+ * block
+ */
+static int udf_check_anchor_block(struct super_block *sb, sector_t block,
+ struct kernel_lb_addr *fileset)
{
- struct anchorVolDescPtr *anchor;
- uint16_t ident;
struct buffer_head *bh;
- long main_s, main_e, reserve_s, reserve_e;
- int i, j;
+ uint16_t ident;
+ int ret;
- if (!sb)
- return 1;
+ if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV) &&
+ udf_fixed_to_variable(block) >=
+ sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits)
+ return -EAGAIN;
- for (i=0; i<sizeof(UDF_SB_ANCHOR(sb))/sizeof(int); i++)
- {
- if (UDF_SB_ANCHOR(sb)[i] && (bh = udf_read_tagged(sb,
- UDF_SB_ANCHOR(sb)[i], UDF_SB_ANCHOR(sb)[i], &ident)))
- {
- anchor = (struct anchorVolDescPtr *)bh->b_data;
-
- /* Locate the main sequence */
- 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;
-
- /* 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;
-
- udf_release_data(bh);
-
- /* Process the main & reserve sequences */
- /* responsible for finding the PartitionDesc(s) */
- if (!(udf_process_sequence(sb, main_s, main_e, fileset) &&
- udf_process_sequence(sb, reserve_s, reserve_e, fileset)))
- {
- break;
- }
- }
+ bh = udf_read_tagged(sb, block, block, &ident);
+ if (!bh)
+ return -EAGAIN;
+ if (ident != TAG_IDENT_AVDP) {
+ brelse(bh);
+ return -EAGAIN;
}
+ ret = udf_load_sequence(sb, bh, fileset);
+ brelse(bh);
+ return ret;
+}
- if (i == sizeof(UDF_SB_ANCHOR(sb))/sizeof(int))
- {
- udf_debug("No Anchor block found\n");
- return 1;
+/*
+ * Search for an anchor volume descriptor pointer.
+ *
+ * Returns < 0 on error, 0 on success. -EAGAIN is special - try next set
+ * of anchors.
+ */
+static int udf_scan_anchors(struct super_block *sb, sector_t *lastblock,
+ struct kernel_lb_addr *fileset)
+{
+ sector_t last[6];
+ int i;
+ struct udf_sb_info *sbi = UDF_SB(sb);
+ int last_count = 0;
+ int ret;
+
+ /* First try user provided anchor */
+ if (sbi->s_anchor) {
+ ret = udf_check_anchor_block(sb, sbi->s_anchor, fileset);
+ if (ret != -EAGAIN)
+ return ret;
+ }
+ /*
+ * according to spec, anchor is in either:
+ * block 256
+ * lastblock-256
+ * lastblock
+ * however, if the disc isn't closed, it could be 512.
+ */
+ ret = udf_check_anchor_block(sb, sbi->s_session + 256, fileset);
+ if (ret != -EAGAIN)
+ return ret;
+ /*
+ * The trouble is which block is the last one. Drives often misreport
+ * this so we try various possibilities.
+ */
+ last[last_count++] = *lastblock;
+ if (*lastblock >= 1)
+ last[last_count++] = *lastblock - 1;
+ last[last_count++] = *lastblock + 1;
+ if (*lastblock >= 2)
+ last[last_count++] = *lastblock - 2;
+ if (*lastblock >= 150)
+ last[last_count++] = *lastblock - 150;
+ if (*lastblock >= 152)
+ last[last_count++] = *lastblock - 152;
+
+ for (i = 0; i < last_count; i++) {
+ if (last[i] >= sb->s_bdev->bd_inode->i_size >>
+ sb->s_blocksize_bits)
+ continue;
+ ret = udf_check_anchor_block(sb, last[i], fileset);
+ if (ret != -EAGAIN) {
+ if (!ret)
+ *lastblock = last[i];
+ return ret;
+ }
+ if (last[i] < 256)
+ continue;
+ ret = udf_check_anchor_block(sb, last[i] - 256, fileset);
+ if (ret != -EAGAIN) {
+ if (!ret)
+ *lastblock = last[i];
+ return ret;
+ }
}
- else
- udf_debug("Using anchor in block %d\n", UDF_SB_ANCHOR(sb)[i]);
-
- for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
- {
- switch UDF_SB_PARTTYPE(sb, i)
- {
- case UDF_VIRTUAL_MAP15:
- case UDF_VIRTUAL_MAP20:
- {
- kernel_lb_addr ino;
-
- if (!UDF_SB_LASTBLOCK(sb))
- {
- UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb);
- udf_find_anchor(sb);
- }
- if (!UDF_SB_LASTBLOCK(sb))
- {
- udf_debug("Unable to determine Lastblock (For Virtual Partition)\n");
- return 1;
- }
+ /* Finally try block 512 in case media is open */
+ return udf_check_anchor_block(sb, sbi->s_session + 512, fileset);
+}
- for (j=0; j<UDF_SB_NUMPARTS(sb); j++)
- {
- if (j != i &&
- UDF_SB_PARTVSN(sb,i) == UDF_SB_PARTVSN(sb,j) &&
- UDF_SB_PARTNUM(sb,i) == UDF_SB_PARTNUM(sb,j))
- {
- ino.partitionReferenceNum = j;
- ino.logicalBlockNum = UDF_SB_LASTBLOCK(sb) -
- UDF_SB_PARTROOT(sb,j);
- break;
- }
- }
+/*
+ * Find an anchor volume descriptor and load Volume Descriptor Sequence from
+ * area specified by it. The function expects sbi->s_lastblock to be the last
+ * block on the media.
+ *
+ * Return <0 on error, 0 if anchor found. -EAGAIN is special meaning anchor
+ * was not found.
+ */
+static int udf_find_anchor(struct super_block *sb,
+ struct kernel_lb_addr *fileset)
+{
+ struct udf_sb_info *sbi = UDF_SB(sb);
+ sector_t lastblock = sbi->s_last_block;
+ int ret;
- if (j == UDF_SB_NUMPARTS(sb))
- return 1;
+ ret = udf_scan_anchors(sb, &lastblock, fileset);
+ if (ret != -EAGAIN)
+ goto out;
- if (!(UDF_SB_VAT(sb) = udf_iget(sb, ino)))
- return 1;
+ /* No anchor found? Try VARCONV conversion of block numbers */
+ UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
+ lastblock = udf_variable_to_fixed(sbi->s_last_block);
+ /* Firstly, we try to not convert number of the last block */
+ ret = udf_scan_anchors(sb, &lastblock, fileset);
+ if (ret != -EAGAIN)
+ goto out;
- if (UDF_SB_PARTTYPE(sb,i) == UDF_VIRTUAL_MAP15)
- {
- UDF_SB_TYPEVIRT(sb,i).s_start_offset = udf_ext0_offset(UDF_SB_VAT(sb));
- UDF_SB_TYPEVIRT(sb,i).s_num_entries = (UDF_SB_VAT(sb)->i_size - 36) >> 2;
- }
- else if (UDF_SB_PARTTYPE(sb,i) == UDF_VIRTUAL_MAP20)
- {
- struct buffer_head *bh = NULL;
- uint32_t pos;
-
- pos = udf_block_map(UDF_SB_VAT(sb), 0);
- bh = sb_bread(sb, pos);
- UDF_SB_TYPEVIRT(sb,i).s_start_offset =
- le16_to_cpu(((struct virtualAllocationTable20 *)bh->b_data + udf_ext0_offset(UDF_SB_VAT(sb)))->lengthHeader) +
- udf_ext0_offset(UDF_SB_VAT(sb));
- UDF_SB_TYPEVIRT(sb,i).s_num_entries = (UDF_SB_VAT(sb)->i_size -
- UDF_SB_TYPEVIRT(sb,i).s_start_offset) >> 2;
- udf_release_data(bh);
- }
- UDF_SB_PARTROOT(sb,i) = udf_get_pblock(sb, 0, i, 0);
- UDF_SB_PARTLEN(sb,i) = UDF_SB_PARTLEN(sb,ino.partitionReferenceNum);
- }
+ lastblock = sbi->s_last_block;
+ /* Secondly, we try with converted number of the last block */
+ ret = udf_scan_anchors(sb, &lastblock, fileset);
+ if (ret < 0) {
+ /* VARCONV didn't help. Clear it. */
+ UDF_CLEAR_FLAG(sb, UDF_FLAG_VARCONV);
+ }
+out:
+ if (ret == 0)
+ sbi->s_last_block = lastblock;
+ return ret;
+}
+
+/*
+ * Check Volume Structure Descriptor, find Anchor block and load Volume
+ * Descriptor Sequence.
+ *
+ * Returns < 0 on error, 0 on success. -EAGAIN is special meaning anchor
+ * block was not found.
+ */
+static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt,
+ int silent, struct kernel_lb_addr *fileset)
+{
+ struct udf_sb_info *sbi = UDF_SB(sb);
+ loff_t nsr_off;
+ int ret;
+
+ if (!sb_set_blocksize(sb, uopt->blocksize)) {
+ if (!silent)
+ udf_warn(sb, "Bad block size\n");
+ return -EINVAL;
+ }
+ sbi->s_last_block = uopt->lastblock;
+ if (!uopt->novrs) {
+ /* Check that it is NSR02 compliant */
+ nsr_off = udf_check_vsd(sb);
+ if (!nsr_off) {
+ if (!silent)
+ udf_warn(sb, "No VRS found\n");
+ return 0;
}
+ if (nsr_off == -1)
+ udf_debug("Failed to read sector at offset %d. "
+ "Assuming open disc. Skipping validity "
+ "check\n", VSD_FIRST_SECTOR_OFFSET);
+ if (!sbi->s_last_block)
+ sbi->s_last_block = udf_get_last_block(sb);
+ } else {
+ udf_debug("Validity check skipped because of novrs option\n");
+ }
+
+ /* Look for anchor block and load Volume Descriptor Sequence */
+ sbi->s_anchor = uopt->anchor;
+ ret = udf_find_anchor(sb, fileset);
+ if (ret < 0) {
+ if (!silent && ret == -EAGAIN)
+ udf_warn(sb, "No anchor found\n");
+ return ret;
}
return 0;
}
static void udf_open_lvid(struct super_block *sb)
{
- if (UDF_SB_LVIDBH(sb))
- {
- int i;
- kernel_timestamp cpu_time;
+ struct udf_sb_info *sbi = UDF_SB(sb);
+ struct buffer_head *bh = sbi->s_lvid_bh;
+ struct logicalVolIntegrityDesc *lvid;
+ struct logicalVolIntegrityDescImpUse *lvidiu;
- UDF_SB_LVIDIU(sb)->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
- UDF_SB_LVIDIU(sb)->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
- if (udf_time_to_stamp(&cpu_time, CURRENT_TIME))
- UDF_SB_LVID(sb)->recordingDateAndTime = cpu_to_lets(cpu_time);
- UDF_SB_LVID(sb)->integrityType = LVID_INTEGRITY_TYPE_OPEN;
-
- UDF_SB_LVID(sb)->descTag.descCRC =
- cpu_to_le16(udf_crc((char *)UDF_SB_LVID(sb) + sizeof(tag),
- le16_to_cpu(UDF_SB_LVID(sb)->descTag.descCRCLength), 0));
+ if (!bh)
+ return;
+ lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
+ lvidiu = udf_sb_lvidiu(sb);
+ if (!lvidiu)
+ return;
+
+ mutex_lock(&sbi->s_alloc_mutex);
+ lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
+ lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
+ udf_time_to_disk_stamp(&lvid->recordingDateAndTime,
+ CURRENT_TIME);
+ lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_OPEN);
+
+ lvid->descTag.descCRC = cpu_to_le16(
+ crc_itu_t(0, (char *)lvid + sizeof(struct tag),
+ le16_to_cpu(lvid->descTag.descCRCLength)));
+
+ lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag);
+ mark_buffer_dirty(bh);
+ sbi->s_lvid_dirty = 0;
+ mutex_unlock(&sbi->s_alloc_mutex);
+ /* Make opening of filesystem visible on the media immediately */
+ sync_dirty_buffer(bh);
+}
- UDF_SB_LVID(sb)->descTag.tagChecksum = 0;
- for (i=0; i<16; i++)
- if (i != 4)
- UDF_SB_LVID(sb)->descTag.tagChecksum +=
- ((uint8_t *)&(UDF_SB_LVID(sb)->descTag))[i];
+static void udf_close_lvid(struct super_block *sb)
+{
+ struct udf_sb_info *sbi = UDF_SB(sb);
+ struct buffer_head *bh = sbi->s_lvid_bh;
+ struct logicalVolIntegrityDesc *lvid;
+ struct logicalVolIntegrityDescImpUse *lvidiu;
- mark_buffer_dirty(UDF_SB_LVIDBH(sb));
- }
+ if (!bh)
+ return;
+ lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
+ lvidiu = udf_sb_lvidiu(sb);
+ if (!lvidiu)
+ return;
+
+ mutex_lock(&sbi->s_alloc_mutex);
+ lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
+ lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
+ udf_time_to_disk_stamp(&lvid->recordingDateAndTime, CURRENT_TIME);
+ if (UDF_MAX_WRITE_VERSION > le16_to_cpu(lvidiu->maxUDFWriteRev))
+ lvidiu->maxUDFWriteRev = cpu_to_le16(UDF_MAX_WRITE_VERSION);
+ if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFReadRev))
+ 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);
+
+ lvid->descTag.descCRC = cpu_to_le16(
+ crc_itu_t(0, (char *)lvid + sizeof(struct tag),
+ le16_to_cpu(lvid->descTag.descCRCLength)));
+
+ lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag);
+ /*
+ * We set buffer uptodate unconditionally here to avoid spurious
+ * warnings from mark_buffer_dirty() when previous EIO has marked
+ * the buffer as !uptodate
+ */
+ set_buffer_uptodate(bh);
+ mark_buffer_dirty(bh);
+ sbi->s_lvid_dirty = 0;
+ mutex_unlock(&sbi->s_alloc_mutex);
+ /* Make closing of filesystem visible on the media immediately */
+ sync_dirty_buffer(bh);
}
-static void udf_close_lvid(struct super_block *sb)
+u64 lvid_get_unique_id(struct super_block *sb)
{
- if (UDF_SB_LVIDBH(sb) &&
- UDF_SB_LVID(sb)->integrityType == LVID_INTEGRITY_TYPE_OPEN)
- {
- int i;
- kernel_timestamp cpu_time;
-
- UDF_SB_LVIDIU(sb)->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
- UDF_SB_LVIDIU(sb)->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
- if (udf_time_to_stamp(&cpu_time, CURRENT_TIME))
- UDF_SB_LVID(sb)->recordingDateAndTime = cpu_to_lets(cpu_time);
- if (UDF_MAX_WRITE_VERSION > le16_to_cpu(UDF_SB_LVIDIU(sb)->maxUDFWriteRev))
- UDF_SB_LVIDIU(sb)->maxUDFWriteRev = cpu_to_le16(UDF_MAX_WRITE_VERSION);
- if (UDF_SB_UDFREV(sb) > le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFReadRev))
- UDF_SB_LVIDIU(sb)->minUDFReadRev = cpu_to_le16(UDF_SB_UDFREV(sb));
- if (UDF_SB_UDFREV(sb) > le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFWriteRev))
- UDF_SB_LVIDIU(sb)->minUDFWriteRev = cpu_to_le16(UDF_SB_UDFREV(sb));
- UDF_SB_LVID(sb)->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE);
-
- UDF_SB_LVID(sb)->descTag.descCRC =
- cpu_to_le16(udf_crc((char *)UDF_SB_LVID(sb) + sizeof(tag),
- le16_to_cpu(UDF_SB_LVID(sb)->descTag.descCRCLength), 0));
-
- UDF_SB_LVID(sb)->descTag.tagChecksum = 0;
- for (i=0; i<16; i++)
- if (i != 4)
- UDF_SB_LVID(sb)->descTag.tagChecksum +=
- ((uint8_t *)&(UDF_SB_LVID(sb)->descTag))[i];
-
- mark_buffer_dirty(UDF_SB_LVIDBH(sb));
- }
+ struct buffer_head *bh;
+ struct udf_sb_info *sbi = UDF_SB(sb);
+ struct logicalVolIntegrityDesc *lvid;
+ struct logicalVolHeaderDesc *lvhd;
+ u64 uniqueID;
+ u64 ret;
+
+ bh = sbi->s_lvid_bh;
+ if (!bh)
+ return 0;
+
+ lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
+ lvhd = (struct logicalVolHeaderDesc *)lvid->logicalVolContentsUse;
+
+ mutex_lock(&sbi->s_alloc_mutex);
+ ret = uniqueID = le64_to_cpu(lvhd->uniqueID);
+ if (!(++uniqueID & 0xFFFFFFFF))
+ uniqueID += 16;
+ lvhd->uniqueID = cpu_to_le64(uniqueID);
+ mutex_unlock(&sbi->s_alloc_mutex);
+ mark_buffer_dirty(bh);
+
+ return ret;
}
-/*
- * udf_read_super
- *
- * PURPOSE
- * Complete the specified super block.
- *
- * PRE-CONDITIONS
- * sb Pointer to superblock to complete - never NULL.
- * sb->s_dev Device to read suberblock from.
- * options Pointer to mount options.
- * silent Silent flag.
- *
- * HISTORY
- * July 1, 1997 - Andrew E. Mileski
- * Written, tested, and released.
- */
static int udf_fill_super(struct super_block *sb, void *options, int silent)
{
- int i;
- struct inode *inode=NULL;
+ int ret = -EINVAL;
+ struct inode *inode = NULL;
struct udf_options uopt;
- kernel_lb_addr rootdir, fileset;
+ struct kernel_lb_addr rootdir, fileset;
struct udf_sb_info *sbi;
uopt.flags = (1 << UDF_FLAG_USE_AD_IN_ICB) | (1 << UDF_FLAG_STRICT);
- uopt.uid = -1;
- uopt.gid = -1;
+ uopt.uid = INVALID_UID;
+ uopt.gid = INVALID_GID;
uopt.umask = 0;
+ uopt.fmode = UDF_INVALID_MODE;
+ uopt.dmode = UDF_INVALID_MODE;
- sbi = kmalloc(sizeof(struct udf_sb_info), GFP_KERNEL);
+ sbi = kzalloc(sizeof(struct udf_sb_info), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
+
sb->s_fs_info = sbi;
- memset(UDF_SB(sb), 0x00, sizeof(struct udf_sb_info));
- init_MUTEX(&sbi->s_alloc_sem);
+ mutex_init(&sbi->s_alloc_mutex);
- if (!udf_parse_options((char *)options, &uopt))
+ if (!udf_parse_options((char *)options, &uopt, false))
goto error_out;
if (uopt.flags & (1 << UDF_FLAG_UTF8) &&
- uopt.flags & (1 << UDF_FLAG_NLS_MAP))
- {
- udf_error(sb, "udf_read_super",
- "utf8 cannot be combined with iocharset\n");
+ uopt.flags & (1 << UDF_FLAG_NLS_MAP)) {
+ udf_err(sb, "utf8 cannot be combined with iocharset\n");
goto error_out;
}
#ifdef CONFIG_UDF_NLS
- if ((uopt.flags & (1 << UDF_FLAG_NLS_MAP)) && !uopt.nls_map)
- {
+ if ((uopt.flags & (1 << UDF_FLAG_NLS_MAP)) && !uopt.nls_map) {
uopt.nls_map = load_nls_default();
if (!uopt.nls_map)
uopt.flags &= ~(1 << UDF_FLAG_NLS_MAP);
@@ -1532,70 +2091,79 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
fileset.logicalBlockNum = 0xFFFFFFFF;
fileset.partitionReferenceNum = 0xFFFF;
- UDF_SB(sb)->s_flags = uopt.flags;
- UDF_SB(sb)->s_uid = uopt.uid;
- UDF_SB(sb)->s_gid = uopt.gid;
- UDF_SB(sb)->s_umask = uopt.umask;
- UDF_SB(sb)->s_nls_map = uopt.nls_map;
-
- /* Set the block size for all transfers */
- if (!udf_set_blocksize(sb, uopt.blocksize))
- goto error_out;
-
- if ( uopt.session == 0xFFFFFFFF )
- UDF_SB_SESSION(sb) = udf_get_last_session(sb);
+ sbi->s_flags = uopt.flags;
+ sbi->s_uid = uopt.uid;
+ sbi->s_gid = uopt.gid;
+ sbi->s_umask = uopt.umask;
+ sbi->s_fmode = uopt.fmode;
+ sbi->s_dmode = uopt.dmode;
+ sbi->s_nls_map = uopt.nls_map;
+ rwlock_init(&sbi->s_cred_lock);
+
+ if (uopt.session == 0xFFFFFFFF)
+ sbi->s_session = udf_get_last_session(sb);
else
- UDF_SB_SESSION(sb) = uopt.session;
-
- udf_debug("Multi-session=%d\n", UDF_SB_SESSION(sb));
-
- UDF_SB_LASTBLOCK(sb) = uopt.lastblock;
- UDF_SB_ANCHOR(sb)[0] = UDF_SB_ANCHOR(sb)[1] = 0;
- UDF_SB_ANCHOR(sb)[2] = uopt.anchor;
- UDF_SB_ANCHOR(sb)[3] = 256;
-
- if (udf_check_valid(sb, uopt.novrs, silent)) /* read volume recognition sequences */
- {
- printk("UDF-fs: No VRS found\n");
- goto error_out;
- }
+ sbi->s_session = uopt.session;
- udf_find_anchor(sb);
+ udf_debug("Multi-session=%d\n", sbi->s_session);
/* Fill in the rest of the superblock */
sb->s_op = &udf_sb_ops;
- sb->dq_op = NULL;
- sb->s_dirt = 0;
+ sb->s_export_op = &udf_export_ops;
+
sb->s_magic = UDF_SUPER_MAGIC;
sb->s_time_gran = 1000;
- if (udf_load_partition(sb, &fileset))
- {
- printk("UDF-fs: No partition found (1)\n");
+ if (uopt.flags & (1 << UDF_FLAG_BLOCKSIZE_SET)) {
+ ret = udf_load_vrs(sb, &uopt, silent, &fileset);
+ } else {
+ uopt.blocksize = bdev_logical_block_size(sb->s_bdev);
+ ret = udf_load_vrs(sb, &uopt, silent, &fileset);
+ if (ret == -EAGAIN && uopt.blocksize != UDF_DEFAULT_BLOCKSIZE) {
+ if (!silent)
+ pr_notice("Rescanning with blocksize %d\n",
+ UDF_DEFAULT_BLOCKSIZE);
+ brelse(sbi->s_lvid_bh);
+ sbi->s_lvid_bh = NULL;
+ uopt.blocksize = UDF_DEFAULT_BLOCKSIZE;
+ ret = udf_load_vrs(sb, &uopt, silent, &fileset);
+ }
+ }
+ if (ret < 0) {
+ if (ret == -EAGAIN) {
+ udf_warn(sb, "No partition found (1)\n");
+ ret = -EINVAL;
+ }
goto error_out;
}
- udf_debug("Lastblock=%d\n", UDF_SB_LASTBLOCK(sb));
+ udf_debug("Lastblock=%d\n", sbi->s_last_block);
- if ( UDF_SB_LVIDBH(sb) )
- {
- uint16_t minUDFReadRev = le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFReadRev);
- uint16_t minUDFWriteRev = le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFWriteRev);
- /* uint16_t maxUDFWriteRev = le16_to_cpu(UDF_SB_LVIDIU(sb)->maxUDFWriteRev); */
+ if (sbi->s_lvid_bh) {
+ struct logicalVolIntegrityDescImpUse *lvidiu =
+ udf_sb_lvidiu(sb);
+ uint16_t minUDFReadRev;
+ uint16_t minUDFWriteRev;
- if (minUDFReadRev > UDF_MAX_READ_VERSION)
- {
- printk("UDF-fs: minUDFReadRev=%x (max is %x)\n",
- le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFReadRev),
- UDF_MAX_READ_VERSION);
+ if (!lvidiu) {
+ ret = -EINVAL;
goto error_out;
}
- else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION)
- {
- sb->s_flags |= MS_RDONLY;
+ minUDFReadRev = le16_to_cpu(lvidiu->minUDFReadRev);
+ minUDFWriteRev = le16_to_cpu(lvidiu->minUDFWriteRev);
+ if (minUDFReadRev > UDF_MAX_READ_VERSION) {
+ udf_err(sb, "minUDFReadRev=%x (max is %x)\n",
+ minUDFReadRev,
+ UDF_MAX_READ_VERSION);
+ ret = -EINVAL;
+ goto error_out;
+ } else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION &&
+ !(sb->s_flags & MS_RDONLY)) {
+ ret = -EACCES;
+ goto error_out;
}
- UDF_SB_UDFREV(sb) = minUDFWriteRev;
+ sbi->s_udfrev = minUDFWriteRev;
if (minUDFReadRev >= UDF_VERS_USE_EXTENDED_FE)
UDF_SET_FLAG(sb, UDF_FLAG_USE_EXTENDED_FE);
@@ -1603,26 +2171,32 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
UDF_SET_FLAG(sb, UDF_FLAG_USE_STREAMS);
}
- if ( !UDF_SB_NUMPARTS(sb) )
- {
- printk("UDF-fs: No partition found (2)\n");
+ if (!sbi->s_partitions) {
+ udf_warn(sb, "No partition found (2)\n");
+ ret = -EINVAL;
+ goto error_out;
+ }
+
+ if (sbi->s_partmaps[sbi->s_partition].s_partition_flags &
+ UDF_PART_FLAG_READ_ONLY &&
+ !(sb->s_flags & MS_RDONLY)) {
+ ret = -EACCES;
goto error_out;
}
- if ( udf_find_fileset(sb, &fileset, &rootdir) )
- {
- printk("UDF-fs: No fileset found\n");
+ if (udf_find_fileset(sb, &fileset, &rootdir)) {
+ udf_warn(sb, "No fileset found\n");
+ ret = -EINVAL;
goto error_out;
}
- if (!silent)
- {
- kernel_timestamp ts;
- udf_time_to_stamp(&ts, UDF_SB_RECORDTIME(sb));
- udf_info("UDF %s (%s) Mounting volume '%s', timestamp %04u/%02u/%02u %02u:%02u (%x)\n",
- UDFFS_VERSION, UDFFS_DATE,
- UDF_SB_VOLIDENT(sb), ts.year, ts.month, ts.day, ts.hour, ts.minute,
- ts.typeAndTimezone);
+ if (!silent) {
+ struct timestamp ts;
+ udf_time_to_disk_stamp(&ts, sbi->s_record_time);
+ udf_info("Mounting volume '%s', timestamp %04u/%02u/%02u %02u:%02u (%x)\n",
+ sbi->s_volume_ident,
+ le16_to_cpu(ts.year), ts.month, ts.day,
+ ts.hour, ts.minute, le16_to_cpu(ts.typeAndTimezone));
}
if (!(sb->s_flags & MS_RDONLY))
udf_open_lvid(sb);
@@ -1630,198 +2204,159 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
/* Assign the root inode */
/* assign inodes by physical block number */
/* perhaps it's not extensible enough, but for now ... */
- inode = udf_iget(sb, rootdir);
- if (!inode)
- {
- printk("UDF-fs: Error in udf_iget, block=%d, partition=%d\n",
- rootdir.logicalBlockNum, rootdir.partitionReferenceNum);
+ inode = udf_iget(sb, &rootdir);
+ if (!inode) {
+ udf_err(sb, "Error in udf_iget, block=%d, partition=%d\n",
+ rootdir.logicalBlockNum, rootdir.partitionReferenceNum);
+ ret = -EIO;
goto error_out;
}
/* Allocate a dentry for the root inode */
- sb->s_root = d_alloc_root(inode);
- if (!sb->s_root)
- {
- printk("UDF-fs: Couldn't allocate root dentry\n");
- iput(inode);
+ sb->s_root = d_make_root(inode);
+ if (!sb->s_root) {
+ udf_err(sb, "Couldn't allocate root dentry\n");
+ ret = -ENOMEM;
goto error_out;
}
sb->s_maxbytes = MAX_LFS_FILESIZE;
+ sb->s_max_links = UDF_MAX_LINKS;
return 0;
error_out:
- if (UDF_SB_VAT(sb))
- iput(UDF_SB_VAT(sb));
- if (UDF_SB_NUMPARTS(sb))
- {
- if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE)
- iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table);
- if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE)
- iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table);
- if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP)
- UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace);
- if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP)
- UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace);
- if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15)
- {
- for (i=0; i<4; i++)
- udf_release_data(UDF_SB_TYPESPAR(sb, UDF_SB_PARTITION(sb)).s_spar_map[i]);
- }
- }
+ if (sbi->s_vat_inode)
+ iput(sbi->s_vat_inode);
#ifdef CONFIG_UDF_NLS
if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
- unload_nls(UDF_SB(sb)->s_nls_map);
+ unload_nls(sbi->s_nls_map);
#endif
if (!(sb->s_flags & MS_RDONLY))
udf_close_lvid(sb);
- udf_release_data(UDF_SB_LVIDBH(sb));
- UDF_SB_FREE(sb);
+ brelse(sbi->s_lvid_bh);
+ udf_sb_free_partitions(sb);
kfree(sbi);
sb->s_fs_info = NULL;
- return -EINVAL;
+
+ return ret;
}
-void udf_error(struct super_block *sb, const char *function,
- const char *fmt, ...)
+void _udf_err(struct super_block *sb, const char *function,
+ const char *fmt, ...)
{
+ struct va_format vaf;
va_list args;
- if (!(sb->s_flags & MS_RDONLY))
- {
- /* mark sb error */
- sb->s_dirt = 1;
- }
va_start(args, fmt);
- vsprintf(error_buf, fmt, args);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ pr_err("error (device %s): %s: %pV", sb->s_id, function, &vaf);
+
va_end(args);
- printk (KERN_CRIT "UDF-fs error (device %s): %s: %s\n",
- sb->s_id, function, error_buf);
}
-void udf_warning(struct super_block *sb, const char *function,
- const char *fmt, ...)
+void _udf_warn(struct super_block *sb, const char *function,
+ const char *fmt, ...)
{
+ struct va_format vaf;
va_list args;
- va_start (args, fmt);
- vsprintf(error_buf, fmt, args);
+ va_start(args, fmt);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ pr_warn("warning (device %s): %s: %pV", sb->s_id, function, &vaf);
+
va_end(args);
- printk(KERN_WARNING "UDF-fs warning (device %s): %s: %s\n",
- sb->s_id, function, error_buf);
}
-/*
- * udf_put_super
- *
- * PURPOSE
- * Prepare for destruction of the superblock.
- *
- * DESCRIPTION
- * Called before the filesystem is unmounted.
- *
- * HISTORY
- * July 1, 1997 - Andrew E. Mileski
- * Written, tested, and released.
- */
-static void
-udf_put_super(struct super_block *sb)
+static void udf_put_super(struct super_block *sb)
{
- int i;
+ struct udf_sb_info *sbi;
- if (UDF_SB_VAT(sb))
- iput(UDF_SB_VAT(sb));
- if (UDF_SB_NUMPARTS(sb))
- {
- if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE)
- iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table);
- if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE)
- iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table);
- if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP)
- UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace);
- if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP)
- UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace);
- if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15)
- {
- for (i=0; i<4; i++)
- udf_release_data(UDF_SB_TYPESPAR(sb, UDF_SB_PARTITION(sb)).s_spar_map[i]);
- }
- }
+ sbi = UDF_SB(sb);
+
+ if (sbi->s_vat_inode)
+ iput(sbi->s_vat_inode);
#ifdef CONFIG_UDF_NLS
if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
- unload_nls(UDF_SB(sb)->s_nls_map);
+ unload_nls(sbi->s_nls_map);
#endif
if (!(sb->s_flags & MS_RDONLY))
udf_close_lvid(sb);
- udf_release_data(UDF_SB_LVIDBH(sb));
- UDF_SB_FREE(sb);
+ brelse(sbi->s_lvid_bh);
+ udf_sb_free_partitions(sb);
kfree(sb->s_fs_info);
sb->s_fs_info = NULL;
}
-/*
- * udf_stat_fs
- *
- * PURPOSE
- * Return info about the filesystem.
- *
- * DESCRIPTION
- * Called by sys_statfs()
- *
- * HISTORY
- * July 1, 1997 - Andrew E. Mileski
- * Written, tested, and released.
- */
-static int
-udf_statfs(struct super_block *sb, struct kstatfs *buf)
+static int udf_sync_fs(struct super_block *sb, int wait)
+{
+ struct udf_sb_info *sbi = UDF_SB(sb);
+
+ mutex_lock(&sbi->s_alloc_mutex);
+ if (sbi->s_lvid_dirty) {
+ /*
+ * Blockdevice will be synced later so we don't have to submit
+ * the buffer for IO
+ */
+ mark_buffer_dirty(sbi->s_lvid_bh);
+ sbi->s_lvid_dirty = 0;
+ }
+ mutex_unlock(&sbi->s_alloc_mutex);
+
+ return 0;
+}
+
+static int udf_statfs(struct dentry *dentry, struct kstatfs *buf)
{
+ struct super_block *sb = dentry->d_sb;
+ struct udf_sb_info *sbi = UDF_SB(sb);
+ struct logicalVolIntegrityDescImpUse *lvidiu;
+ u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
+
+ lvidiu = udf_sb_lvidiu(sb);
buf->f_type = UDF_SUPER_MAGIC;
buf->f_bsize = sb->s_blocksize;
- buf->f_blocks = UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb));
+ buf->f_blocks = sbi->s_partmaps[sbi->s_partition].s_partition_len;
buf->f_bfree = udf_count_free(sb);
buf->f_bavail = buf->f_bfree;
- buf->f_files = (UDF_SB_LVIDBH(sb) ?
- (le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) +
- le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs)) : 0) + buf->f_bfree;
+ buf->f_files = (lvidiu != NULL ? (le32_to_cpu(lvidiu->numFiles) +
+ le32_to_cpu(lvidiu->numDirs)) : 0)
+ + buf->f_bfree;
buf->f_ffree = buf->f_bfree;
- /* __kernel_fsid_t f_fsid */
- buf->f_namelen = UDF_NAME_LEN-2;
+ buf->f_namelen = UDF_NAME_LEN - 2;
+ buf->f_fsid.val[0] = (u32)id;
+ buf->f_fsid.val[1] = (u32)(id >> 32);
return 0;
}
-static unsigned char udf_bitmap_lookup[16] = {
- 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
-};
-
-static unsigned int
-udf_count_free_bitmap(struct super_block *sb, struct udf_bitmap *bitmap)
+static unsigned int udf_count_free_bitmap(struct super_block *sb,
+ struct udf_bitmap *bitmap)
{
struct buffer_head *bh = NULL;
unsigned int accum = 0;
int index;
int block = 0, newblock;
- kernel_lb_addr loc;
+ struct kernel_lb_addr loc;
uint32_t bytes;
- uint8_t value;
uint8_t *ptr;
uint16_t ident;
struct spaceBitmapDesc *bm;
- lock_kernel();
-
loc.logicalBlockNum = bitmap->s_extPosition;
- loc.partitionReferenceNum = UDF_SB_PARTITION(sb);
- bh = udf_read_ptagged(sb, loc, 0, &ident);
+ loc.partitionReferenceNum = UDF_SB(sb)->s_partition;
+ bh = udf_read_ptagged(sb, &loc, 0, &ident);
- if (!bh)
- {
- printk(KERN_ERR "udf: udf_count_free failed\n");
+ if (!bh) {
+ udf_err(sb, "udf_count_free failed\n");
goto out;
- }
- else if (ident != TAG_IDENT_SBD)
- {
- udf_release_data(bh);
- printk(KERN_ERR "udf: udf_count_free failed\n");
+ } else if (ident != TAG_IDENT_SBD) {
+ brelse(bh);
+ udf_err(sb, "udf_count_free failed\n");
goto out;
}
@@ -1830,23 +2365,16 @@ udf_count_free_bitmap(struct super_block *sb, struct udf_bitmap *bitmap)
index = sizeof(struct spaceBitmapDesc); /* offset in first block only */
ptr = (uint8_t *)bh->b_data;
- while ( bytes > 0 )
- {
- while ((bytes > 0) && (index < sb->s_blocksize))
- {
- value = ptr[index];
- accum += udf_bitmap_lookup[ value & 0x0f ];
- accum += udf_bitmap_lookup[ value >> 4 ];
- index++;
- bytes--;
- }
- if ( bytes )
- {
- udf_release_data(bh);
- newblock = udf_get_lb_pblock(sb, loc, ++block);
+ while (bytes > 0) {
+ u32 cur_bytes = min_t(u32, bytes, sb->s_blocksize - index);
+ accum += bitmap_weight((const unsigned long *)(ptr + index),
+ cur_bytes * 8);
+ bytes -= cur_bytes;
+ if (bytes) {
+ brelse(bh);
+ newblock = udf_get_lb_pblock(sb, &loc, ++block);
bh = udf_tread(sb, newblock);
- if (!bh)
- {
+ if (!bh) {
udf_debug("read failed\n");
goto out;
}
@@ -1854,50 +2382,48 @@ udf_count_free_bitmap(struct super_block *sb, struct udf_bitmap *bitmap)
ptr = (uint8_t *)bh->b_data;
}
}
- udf_release_data(bh);
-
+ brelse(bh);
out:
- unlock_kernel();
-
return accum;
}
-static unsigned int
-udf_count_free_table(struct super_block *sb, struct inode * table)
+static unsigned int udf_count_free_table(struct super_block *sb,
+ struct inode *table)
{
unsigned int accum = 0;
- uint32_t extoffset, elen;
- kernel_lb_addr bloc, eloc;
+ uint32_t elen;
+ struct kernel_lb_addr eloc;
int8_t etype;
- struct buffer_head *bh = NULL;
+ struct extent_position epos;
- lock_kernel();
+ mutex_lock(&UDF_SB(sb)->s_alloc_mutex);
+ epos.block = UDF_I(table)->i_location;
+ epos.offset = sizeof(struct unallocSpaceEntry);
+ epos.bh = NULL;
- bloc = UDF_I_LOCATION(table);
- extoffset = sizeof(struct unallocSpaceEntry);
-
- while ((etype = udf_next_aext(table, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
- {
+ while ((etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1)
accum += (elen >> table->i_sb->s_blocksize_bits);
- }
- udf_release_data(bh);
- unlock_kernel();
+ brelse(epos.bh);
+ mutex_unlock(&UDF_SB(sb)->s_alloc_mutex);
return accum;
}
-
-static unsigned int
-udf_count_free(struct super_block *sb)
+
+static unsigned int udf_count_free(struct super_block *sb)
{
unsigned int accum = 0;
-
- if (UDF_SB_LVIDBH(sb))
- {
- if (le32_to_cpu(UDF_SB_LVID(sb)->numOfPartitions) > UDF_SB_PARTITION(sb))
- {
- accum = le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)]);
-
+ struct udf_sb_info *sbi;
+ struct udf_part_map *map;
+
+ sbi = UDF_SB(sb);
+ if (sbi->s_lvid_bh) {
+ struct logicalVolIntegrityDesc *lvid =
+ (struct logicalVolIntegrityDesc *)
+ sbi->s_lvid_bh->b_data;
+ if (le32_to_cpu(lvid->numOfPartitions) > sbi->s_partition) {
+ accum = le32_to_cpu(
+ lvid->freeSpaceTable[sbi->s_partition]);
if (accum == 0xFFFFFFFF)
accum = 0;
}
@@ -1906,28 +2432,25 @@ udf_count_free(struct super_block *sb)
if (accum)
return accum;
- if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP)
- {
+ map = &sbi->s_partmaps[sbi->s_partition];
+ if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) {
accum += udf_count_free_bitmap(sb,
- UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_bitmap);
+ map->s_uspace.s_bitmap);
}
- if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP)
- {
+ if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP) {
accum += udf_count_free_bitmap(sb,
- UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_bitmap);
+ map->s_fspace.s_bitmap);
}
if (accum)
return accum;
- if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE)
- {
+ if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) {
accum += udf_count_free_table(sb,
- UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table);
+ map->s_uspace.s_table);
}
- if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE)
- {
+ if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE) {
accum += udf_count_free_table(sb,
- UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table);
+ map->s_fspace.s_table);
}
return accum;
diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c
index 43f3051ef75..d7c6dbe4194 100644
--- a/fs/udf/symlink.c
+++ b/fs/udf/symlink.c
@@ -4,11 +4,6 @@
* PURPOSE
* Symlink handling routines for the OSTA-UDF(tm) filesystem.
*
- * CONTACTS
- * E-mail regarding any portion of the Linux UDF file system should be
- * directed to the development team mailing list (run by majordomo):
- * linux_udf@hpesjro.fc.hp.com
- *
* COPYRIGHT
* This file is distributed under the terms of the GNU General Public
* License (GPL). Copies of the GPL can be obtained from:
@@ -16,7 +11,7 @@
* Each contributing author retains all rights to their own work.
*
* (C) 1998-2001 Ben Fennema
- * (C) 1999 Stelias Computing Inc
+ * (C) 1999 Stelias Computing Inc
*
* HISTORY
*
@@ -28,51 +23,53 @@
#include <asm/uaccess.h>
#include <linux/errno.h>
#include <linux/fs.h>
-#include <linux/udf_fs.h>
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/stat.h>
-#include <linux/slab.h>
#include <linux/pagemap.h>
-#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
#include "udf_i.h"
-static void udf_pc_to_char(struct super_block *sb, char *from, int fromlen, char *to)
+static void udf_pc_to_char(struct super_block *sb, unsigned char *from,
+ int fromlen, unsigned char *to)
{
struct pathComponent *pc;
int elen = 0;
- char *p = to;
+ unsigned char *p = to;
- while (elen < fromlen)
- {
+ while (elen < fromlen) {
pc = (struct pathComponent *)(from + elen);
- switch (pc->componentType)
- {
- case 1:
- if (pc->lengthComponentIdent == 0)
- {
- p = to;
- *p++ = '/';
- }
- break;
- case 3:
- memcpy(p, "../", 3);
- p += 3;
- break;
- case 4:
- memcpy(p, "./", 2);
- p += 2;
- /* that would be . - just ignore */
- break;
- case 5:
- p += udf_get_filename(sb, pc->componentIdent, p, pc->lengthComponentIdent);
- *p++ = '/';
+ switch (pc->componentType) {
+ case 1:
+ /*
+ * Symlink points to some place which should be agreed
+ * upon between originator and receiver of the media. Ignore.
+ */
+ if (pc->lengthComponentIdent > 0)
break;
+ /* Fall through */
+ case 2:
+ p = to;
+ *p++ = '/';
+ break;
+ case 3:
+ memcpy(p, "../", 3);
+ p += 3;
+ break;
+ case 4:
+ memcpy(p, "./", 2);
+ p += 2;
+ /* that would be . - just ignore */
+ break;
+ case 5:
+ p += udf_get_filename(sb, pc->componentIdent, p,
+ pc->lengthComponentIdent);
+ *p++ = '/';
+ break;
}
elen += sizeof(struct pathComponent) + pc->lengthComponentIdent;
}
- if (p > to+1)
+ if (p > to + 1)
p[-1] = '\0';
else
p[0] = '\0';
@@ -82,16 +79,20 @@ static int udf_symlink_filler(struct file *file, struct page *page)
{
struct inode *inode = page->mapping->host;
struct buffer_head *bh = NULL;
- char *symlink;
+ unsigned char *symlink;
int err = -EIO;
- char *p = kmap(page);
+ unsigned char *p = kmap(page);
+ struct udf_inode_info *iinfo;
+ uint32_t pos;
- lock_kernel();
- if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
- symlink = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode);
- else
- {
- bh = sb_bread(inode->i_sb, udf_block_map(inode, 0));
+ iinfo = UDF_I(inode);
+ pos = udf_block_map(inode, 0);
+
+ down_read(&iinfo->i_data_sem);
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+ symlink = iinfo->i_ext.i_data + iinfo->i_lenEAttr;
+ } else {
+ bh = sb_bread(inode->i_sb, pos);
if (!bh)
goto out;
@@ -100,15 +101,16 @@ static int udf_symlink_filler(struct file *file, struct page *page)
}
udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p);
- udf_release_data(bh);
+ brelse(bh);
- unlock_kernel();
+ up_read(&iinfo->i_data_sem);
SetPageUptodate(page);
kunmap(page);
unlock_page(page);
return 0;
+
out:
- unlock_kernel();
+ up_read(&iinfo->i_data_sem);
SetPageError(page);
kunmap(page);
unlock_page(page);
@@ -118,6 +120,6 @@ out:
/*
* symlinks can't do much...
*/
-struct address_space_operations udf_symlink_aops = {
+const struct address_space_operations udf_symlink_aops = {
.readpage = udf_symlink_filler,
};
diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c
index 7dc8a5572ca..8a9657d7f7c 100644
--- a/fs/udf/truncate.c
+++ b/fs/udf/truncate.c
@@ -4,11 +4,6 @@
* PURPOSE
* Truncate handling routines for the OSTA-UDF(tm) filesystem.
*
- * CONTACTS
- * E-mail regarding any portion of the Linux UDF file system should be
- * directed to the development team mailing list (run by majordomo):
- * linux_udf@hpesjro.fc.hp.com
- *
* COPYRIGHT
* This file is distributed under the terms of the GNU General Public
* License (GPL). Copies of the GPL can be obtained from:
@@ -27,258 +22,266 @@
#include "udfdecl.h"
#include <linux/fs.h>
#include <linux/mm.h>
-#include <linux/udf_fs.h>
#include <linux/buffer_head.h>
#include "udf_i.h"
#include "udf_sb.h"
-static void extent_trunc(struct inode * inode, kernel_lb_addr bloc, int extoffset,
- kernel_lb_addr eloc, int8_t etype, uint32_t elen, struct buffer_head *bh, uint32_t nelen)
+static void extent_trunc(struct inode *inode, struct extent_position *epos,
+ struct kernel_lb_addr *eloc, int8_t etype, uint32_t elen,
+ uint32_t nelen)
{
- kernel_lb_addr neloc = { 0, 0 };
- int last_block = (elen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
- int first_block = (nelen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
+ struct kernel_lb_addr neloc = {};
+ int last_block = (elen + inode->i_sb->s_blocksize - 1) >>
+ inode->i_sb->s_blocksize_bits;
+ int first_block = (nelen + inode->i_sb->s_blocksize - 1) >>
+ inode->i_sb->s_blocksize_bits;
- if (nelen)
- {
- if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
- {
- udf_free_blocks(inode->i_sb, inode, eloc, 0, last_block);
+ if (nelen) {
+ if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
+ udf_free_blocks(inode->i_sb, inode, eloc, 0,
+ last_block);
etype = (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30);
- }
- else
- neloc = eloc;
+ } else
+ neloc = *eloc;
nelen = (etype << 30) | nelen;
}
- if (elen != nelen)
- {
- udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 0);
- if (last_block - first_block > 0)
- {
+ if (elen != nelen) {
+ udf_write_aext(inode, epos, &neloc, nelen, 0);
+ if (last_block - first_block > 0) {
if (etype == (EXT_RECORDED_ALLOCATED >> 30))
mark_inode_dirty(inode);
if (etype != (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
- udf_free_blocks(inode->i_sb, inode, eloc, first_block, last_block - first_block);
+ udf_free_blocks(inode->i_sb, inode, eloc,
+ first_block,
+ last_block - first_block);
}
}
}
-void udf_discard_prealloc(struct inode * inode)
+/*
+ * Truncate the last extent to match i_size. This function assumes
+ * that preallocation extent is already truncated.
+ */
+void udf_truncate_tail_extent(struct inode *inode)
{
- kernel_lb_addr bloc, eloc;
- uint32_t extoffset = 0, elen, nelen;
+ struct extent_position epos = {};
+ struct kernel_lb_addr eloc;
+ uint32_t elen, nelen;
uint64_t lbcount = 0;
int8_t etype = -1, netype;
- struct buffer_head *bh = NULL;
int adsize;
+ struct udf_inode_info *iinfo = UDF_I(inode);
- if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB ||
- inode->i_size == UDF_I_LENEXTENTS(inode))
- {
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB ||
+ inode->i_size == iinfo->i_lenExtents)
+ return;
+ /* Are we going to delete the file anyway? */
+ if (inode->i_nlink == 0)
return;
+
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+ adsize = sizeof(struct short_ad);
+ else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+ adsize = sizeof(struct long_ad);
+ else
+ BUG();
+
+ /* Find the last extent in the file */
+ while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) {
+ etype = netype;
+ lbcount += elen;
+ if (lbcount > inode->i_size) {
+ if (lbcount - inode->i_size >= inode->i_sb->s_blocksize)
+ udf_warn(inode->i_sb,
+ "Too long extent after EOF in inode %u: i_size: %lld lbcount: %lld extent %u+%u\n",
+ (unsigned)inode->i_ino,
+ (long long)inode->i_size,
+ (long long)lbcount,
+ (unsigned)eloc.logicalBlockNum,
+ (unsigned)elen);
+ nelen = elen - (lbcount - inode->i_size);
+ epos.offset -= adsize;
+ extent_trunc(inode, &epos, &eloc, etype, elen, nelen);
+ epos.offset += adsize;
+ if (udf_next_aext(inode, &epos, &eloc, &elen, 1) != -1)
+ udf_err(inode->i_sb,
+ "Extent after EOF in inode %u\n",
+ (unsigned)inode->i_ino);
+ break;
+ }
}
+ /* This inode entry is in-memory only and thus we don't have to mark
+ * the inode dirty */
+ iinfo->i_lenExtents = inode->i_size;
+ brelse(epos.bh);
+}
+
+void udf_discard_prealloc(struct inode *inode)
+{
+ struct extent_position epos = { NULL, 0, {0, 0} };
+ struct kernel_lb_addr eloc;
+ uint32_t elen;
+ uint64_t lbcount = 0;
+ int8_t etype = -1, netype;
+ int adsize;
+ struct udf_inode_info *iinfo = UDF_I(inode);
- if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
- adsize = sizeof(short_ad);
- else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG)
- adsize = sizeof(long_ad);
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB ||
+ inode->i_size == iinfo->i_lenExtents)
+ return;
+
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+ adsize = sizeof(struct short_ad);
+ else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+ adsize = sizeof(struct long_ad);
else
adsize = 0;
- bloc = UDF_I_LOCATION(inode);
+ epos.block = iinfo->i_location;
- while ((netype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
- {
+ /* Find the last extent in the file */
+ while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) {
etype = netype;
lbcount += elen;
- if (lbcount > inode->i_size && lbcount - inode->i_size < inode->i_sb->s_blocksize)
- {
- nelen = elen - (lbcount - inode->i_size);
- extent_trunc(inode, bloc, extoffset-adsize, eloc, etype, elen, bh, nelen);
- lbcount = inode->i_size;
- }
}
- if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
- {
- extoffset -= adsize;
+ if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
+ epos.offset -= adsize;
lbcount -= elen;
- extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, 0);
- if (!bh)
- {
- UDF_I_LENALLOC(inode) = extoffset - udf_file_entry_alloc_offset(inode);
+ extent_trunc(inode, &epos, &eloc, etype, elen, 0);
+ if (!epos.bh) {
+ iinfo->i_lenAlloc =
+ epos.offset -
+ udf_file_entry_alloc_offset(inode);
mark_inode_dirty(inode);
- }
- else
- {
- struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data);
- aed->lengthAllocDescs = cpu_to_le32(extoffset - sizeof(struct allocExtDesc));
- if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
- udf_update_tag(bh->b_data, extoffset);
+ } else {
+ struct allocExtDesc *aed =
+ (struct allocExtDesc *)(epos.bh->b_data);
+ aed->lengthAllocDescs =
+ cpu_to_le32(epos.offset -
+ sizeof(struct allocExtDesc));
+ if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
+ UDF_SB(inode->i_sb)->s_udfrev >= 0x0201)
+ udf_update_tag(epos.bh->b_data, epos.offset);
else
- udf_update_tag(bh->b_data, sizeof(struct allocExtDesc));
- mark_buffer_dirty_inode(bh, inode);
+ udf_update_tag(epos.bh->b_data,
+ sizeof(struct allocExtDesc));
+ mark_buffer_dirty_inode(epos.bh, inode);
}
}
- UDF_I_LENEXTENTS(inode) = lbcount;
+ /* This inode entry is in-memory only and thus we don't have to mark
+ * the inode dirty */
+ iinfo->i_lenExtents = lbcount;
+ brelse(epos.bh);
+}
+
+static void udf_update_alloc_ext_desc(struct inode *inode,
+ struct extent_position *epos,
+ u32 lenalloc)
+{
+ struct super_block *sb = inode->i_sb;
+ struct udf_sb_info *sbi = UDF_SB(sb);
- udf_release_data(bh);
+ struct allocExtDesc *aed = (struct allocExtDesc *) (epos->bh->b_data);
+ int len = sizeof(struct allocExtDesc);
+
+ aed->lengthAllocDescs = cpu_to_le32(lenalloc);
+ if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || sbi->s_udfrev >= 0x0201)
+ len += lenalloc;
+
+ udf_update_tag(epos->bh->b_data, len);
+ mark_buffer_dirty_inode(epos->bh, inode);
}
-void udf_truncate_extents(struct inode * inode)
+/*
+ * Truncate extents of inode to inode->i_size. This function can be used only
+ * for making file shorter. For making file longer, udf_extend_file() has to
+ * be used.
+ */
+void udf_truncate_extents(struct inode *inode)
{
- kernel_lb_addr bloc, eloc, neloc = { 0, 0 };
- uint32_t extoffset, elen, offset, nelen = 0, lelen = 0, lenalloc;
+ struct extent_position epos;
+ struct kernel_lb_addr eloc, neloc = {};
+ uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc;
int8_t etype;
- int first_block = inode->i_size >> inode->i_sb->s_blocksize_bits;
- struct buffer_head *bh = NULL;
+ struct super_block *sb = inode->i_sb;
+ sector_t first_block = inode->i_size >> sb->s_blocksize_bits, offset;
+ loff_t byte_offset;
int adsize;
+ struct udf_inode_info *iinfo = UDF_I(inode);
- if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
- adsize = sizeof(short_ad);
- else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG)
- adsize = sizeof(long_ad);
+ if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
+ adsize = sizeof(struct short_ad);
+ else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
+ adsize = sizeof(struct long_ad);
else
- adsize = 0;
-
- etype = inode_bmap(inode, first_block, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
- offset += (inode->i_size & (inode->i_sb->s_blocksize - 1));
- if (etype != -1)
- {
- extoffset -= adsize;
- extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, offset);
- extoffset += adsize;
+ BUG();
- if (offset)
- lenalloc = extoffset;
- else
- lenalloc = extoffset - adsize;
-
- if (!bh)
- lenalloc -= udf_file_entry_alloc_offset(inode);
- else
- lenalloc -= sizeof(struct allocExtDesc);
-
- while ((etype = udf_current_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 0)) != -1)
- {
- if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30))
- {
- udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 0);
- extoffset = 0;
- if (lelen)
- {
- if (!bh)
- BUG();
- else
- memset(bh->b_data, 0x00, sizeof(struct allocExtDesc));
- udf_free_blocks(inode->i_sb, inode, bloc, 0, lelen);
- }
- else
- {
- if (!bh)
- {
- UDF_I_LENALLOC(inode) = lenalloc;
- mark_inode_dirty(inode);
- }
- else
- {
- struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data);
- aed->lengthAllocDescs = cpu_to_le32(lenalloc);
- if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
- udf_update_tag(bh->b_data, lenalloc +
- sizeof(struct allocExtDesc));
- else
- udf_update_tag(bh->b_data, sizeof(struct allocExtDesc));
- mark_buffer_dirty_inode(bh, inode);
- }
- }
+ etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
+ byte_offset = (offset << sb->s_blocksize_bits) +
+ (inode->i_size & (sb->s_blocksize - 1));
+ if (etype == -1) {
+ /* We should extend the file? */
+ WARN_ON(byte_offset);
+ return;
+ }
+ epos.offset -= adsize;
+ extent_trunc(inode, &epos, &eloc, etype, elen, byte_offset);
+ epos.offset += adsize;
+ if (byte_offset)
+ lenalloc = epos.offset;
+ else
+ lenalloc = epos.offset - adsize;
- udf_release_data(bh);
- extoffset = sizeof(struct allocExtDesc);
- bloc = eloc;
- bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, bloc, 0));
- if (elen)
- lelen = (elen + inode->i_sb->s_blocksize - 1) >>
- inode->i_sb->s_blocksize_bits;
- else
- lelen = 1;
- }
- else
- {
- extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, 0);
- extoffset += adsize;
- }
- }
+ if (!epos.bh)
+ lenalloc -= udf_file_entry_alloc_offset(inode);
+ else
+ lenalloc -= sizeof(struct allocExtDesc);
- if (lelen)
- {
- if (!bh)
- BUG();
- else
- memset(bh->b_data, 0x00, sizeof(struct allocExtDesc));
- udf_free_blocks(inode->i_sb, inode, bloc, 0, lelen);
- }
- else
- {
- if (!bh)
- {
- UDF_I_LENALLOC(inode) = lenalloc;
+ while ((etype = udf_current_aext(inode, &epos, &eloc,
+ &elen, 0)) != -1) {
+ if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) {
+ udf_write_aext(inode, &epos, &neloc, nelen, 0);
+ if (indirect_ext_len) {
+ /* We managed to free all extents in the
+ * indirect extent - free it too */
+ BUG_ON(!epos.bh);
+ udf_free_blocks(sb, NULL, &epos.block,
+ 0, indirect_ext_len);
+ } else if (!epos.bh) {
+ iinfo->i_lenAlloc = lenalloc;
mark_inode_dirty(inode);
- }
+ } else
+ udf_update_alloc_ext_desc(inode,
+ &epos, lenalloc);
+ brelse(epos.bh);
+ epos.offset = sizeof(struct allocExtDesc);
+ epos.block = eloc;
+ epos.bh = udf_tread(sb,
+ udf_get_lb_pblock(sb, &eloc, 0));
+ if (elen)
+ indirect_ext_len =
+ (elen + sb->s_blocksize - 1) >>
+ sb->s_blocksize_bits;
else
- {
- struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data);
- aed->lengthAllocDescs = cpu_to_le32(lenalloc);
- if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
- udf_update_tag(bh->b_data, lenalloc +
- sizeof(struct allocExtDesc));
- else
- udf_update_tag(bh->b_data, sizeof(struct allocExtDesc));
- mark_buffer_dirty_inode(bh, inode);
- }
+ indirect_ext_len = 1;
+ } else {
+ extent_trunc(inode, &epos, &eloc, etype, elen, 0);
+ epos.offset += adsize;
}
}
- else if (inode->i_size)
- {
- if (offset)
- {
- extoffset -= adsize;
- etype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1);
- if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
- {
- extoffset -= adsize;
- elen = EXT_NOT_RECORDED_NOT_ALLOCATED | (elen + offset);
- udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 0);
- }
- else if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
- {
- kernel_lb_addr neloc = { 0, 0 };
- extoffset -= adsize;
- nelen = EXT_NOT_RECORDED_NOT_ALLOCATED |
- ((elen + offset + inode->i_sb->s_blocksize - 1) &
- ~(inode->i_sb->s_blocksize - 1));
- udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1);
- udf_add_aext(inode, &bloc, &extoffset, eloc, (etype << 30) | elen, &bh, 1);
- }
- else
- {
- if (elen & (inode->i_sb->s_blocksize - 1))
- {
- extoffset -= adsize;
- elen = EXT_RECORDED_ALLOCATED |
- ((elen + inode->i_sb->s_blocksize - 1) &
- ~(inode->i_sb->s_blocksize - 1));
- udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 1);
- }
- memset(&eloc, 0x00, sizeof(kernel_lb_addr));
- elen = EXT_NOT_RECORDED_NOT_ALLOCATED | offset;
- udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 1);
- }
- }
- }
- UDF_I_LENEXTENTS(inode) = inode->i_size;
- udf_release_data(bh);
+ if (indirect_ext_len) {
+ BUG_ON(!epos.bh);
+ udf_free_blocks(sb, NULL, &epos.block, 0, indirect_ext_len);
+ } else if (!epos.bh) {
+ iinfo->i_lenAlloc = lenalloc;
+ mark_inode_dirty(inode);
+ } else
+ udf_update_alloc_ext_desc(inode, &epos, lenalloc);
+ iinfo->i_lenExtents = inode->i_size;
+
+ brelse(epos.bh);
}
diff --git a/fs/udf/udf_i.h b/fs/udf/udf_i.h
index d7dbe6f3ba0..b5cd8ed2aa1 100644
--- a/fs/udf/udf_i.h
+++ b/fs/udf/udf_i.h
@@ -1,26 +1,62 @@
-#ifndef __LINUX_UDF_I_H
-#define __LINUX_UDF_I_H
+#ifndef _UDF_I_H
+#define _UDF_I_H
+
+struct extent_position {
+ struct buffer_head *bh;
+ uint32_t offset;
+ struct kernel_lb_addr block;
+};
+
+struct udf_ext_cache {
+ /* Extent position */
+ struct extent_position epos;
+ /* Start logical offset in bytes */
+ loff_t lstart;
+};
+
+/*
+ * The i_data_sem and i_mutex serve for protection of allocation information
+ * of a regular files and symlinks. This includes all extents belonging to
+ * the file/symlink, a fact whether data are in-inode or in external data
+ * blocks, preallocation, goal block information... When extents are read,
+ * i_mutex or i_data_sem must be held (for reading is enough in case of
+ * i_data_sem). When extents are changed, i_data_sem must be held for writing
+ * and also i_mutex must be held.
+ *
+ * For directories i_mutex is used for all the necessary protection.
+ */
+
+struct udf_inode_info {
+ struct timespec i_crtime;
+ /* Physical address of inode */
+ struct kernel_lb_addr i_location;
+ __u64 i_unique;
+ __u32 i_lenEAttr;
+ __u32 i_lenAlloc;
+ __u64 i_lenExtents;
+ __u32 i_next_alloc_block;
+ __u32 i_next_alloc_goal;
+ __u32 i_checkpoint;
+ unsigned i_alloc_type : 3;
+ unsigned i_efe : 1; /* extendedFileEntry */
+ unsigned i_use : 1; /* unallocSpaceEntry */
+ unsigned i_strat4096 : 1;
+ unsigned reserved : 26;
+ union {
+ struct short_ad *i_sad;
+ struct long_ad *i_lad;
+ __u8 *i_data;
+ } i_ext;
+ struct rw_semaphore i_data_sem;
+ struct udf_ext_cache cached_extent;
+ /* Spinlock for protecting extent cache */
+ spinlock_t i_extent_cache_lock;
+ struct inode vfs_inode;
+};
-#include <linux/udf_fs_i.h>
static inline struct udf_inode_info *UDF_I(struct inode *inode)
{
return list_entry(inode, struct udf_inode_info, vfs_inode);
}
-#define UDF_I_LOCATION(X) ( UDF_I(X)->i_location )
-#define UDF_I_LENEATTR(X) ( UDF_I(X)->i_lenEAttr )
-#define UDF_I_LENALLOC(X) ( UDF_I(X)->i_lenAlloc )
-#define UDF_I_LENEXTENTS(X) ( UDF_I(X)->i_lenExtents )
-#define UDF_I_UNIQUE(X) ( UDF_I(X)->i_unique )
-#define UDF_I_ALLOCTYPE(X) ( UDF_I(X)->i_alloc_type )
-#define UDF_I_EFE(X) ( UDF_I(X)->i_efe )
-#define UDF_I_USE(X) ( UDF_I(X)->i_use )
-#define UDF_I_STRAT4096(X) ( UDF_I(X)->i_strat4096 )
-#define UDF_I_NEXT_ALLOC_BLOCK(X) ( UDF_I(X)->i_next_alloc_block )
-#define UDF_I_NEXT_ALLOC_GOAL(X) ( UDF_I(X)->i_next_alloc_goal )
-#define UDF_I_CRTIME(X) ( UDF_I(X)->i_crtime )
-#define UDF_I_SAD(X) ( UDF_I(X)->i_ext.i_sad )
-#define UDF_I_LAD(X) ( UDF_I(X)->i_ext.i_lad )
-#define UDF_I_DATA(X) ( UDF_I(X)->i_ext.i_data )
-
-#endif /* !defined(_LINUX_UDF_I_H) */
+#endif /* _UDF_I_H) */
diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h
index 0e54922daa0..1f32c7bd9f5 100644
--- a/fs/udf/udf_sb.h
+++ b/fs/udf/udf_sb.h
@@ -1,10 +1,13 @@
#ifndef __LINUX_UDF_SB_H
#define __LINUX_UDF_SB_H
+#include <linux/mutex.h>
+#include <linux/bitops.h>
+
/* Since UDF 2.01 is ISO 13346 based... */
#define UDF_SUPER_MAGIC 0x15013346
-#define UDF_MAX_READ_VERSION 0x0201
+#define UDF_MAX_READ_VERSION 0x0250
#define UDF_MAX_WRITE_VERSION 0x0201
#define UDF_FLAG_USE_EXTENDED_FE 0
@@ -20,6 +23,15 @@
#define UDF_FLAG_VARCONV 8
#define UDF_FLAG_NLS_MAP 9
#define UDF_FLAG_UTF8 10
+#define UDF_FLAG_UID_FORGET 11 /* save -1 for uid to disk */
+#define UDF_FLAG_UID_IGNORE 12 /* use sb uid instead of on disk uid */
+#define UDF_FLAG_GID_FORGET 13
+#define UDF_FLAG_GID_IGNORE 14
+#define UDF_FLAG_UID_SET 15
+#define UDF_FLAG_GID_SET 16
+#define UDF_FLAG_SESSION_SET 17
+#define UDF_FLAG_LASTBLOCK_SET 18
+#define UDF_FLAG_BLOCKSIZE_SET 19
#define UDF_PART_FLAG_UNALLOC_BITMAP 0x0001
#define UDF_PART_FLAG_UNALLOC_TABLE 0x0002
@@ -30,110 +42,143 @@
#define UDF_PART_FLAG_REWRITABLE 0x0040
#define UDF_PART_FLAG_OVERWRITABLE 0x0080
+#define UDF_MAX_BLOCK_LOADED 8
+
+#define UDF_TYPE1_MAP15 0x1511U
+#define UDF_VIRTUAL_MAP15 0x1512U
+#define UDF_VIRTUAL_MAP20 0x2012U
+#define UDF_SPARABLE_MAP15 0x1522U
+#define UDF_METADATA_MAP25 0x2511U
+
+#define UDF_INVALID_MODE ((umode_t)-1)
+
+#pragma pack(1) /* XXX(hch): Why? This file just defines in-core structures */
+
+#define MF_DUPLICATE_MD 0x01
+#define MF_MIRROR_FE_LOADED 0x02
+
+struct udf_meta_data {
+ __u32 s_meta_file_loc;
+ __u32 s_mirror_file_loc;
+ __u32 s_bitmap_file_loc;
+ __u32 s_alloc_unit_size;
+ __u16 s_align_unit_size;
+ int s_flags;
+ struct inode *s_metadata_fe;
+ struct inode *s_mirror_fe;
+ struct inode *s_bitmap_fe;
+};
+
+struct udf_sparing_data {
+ __u16 s_packet_len;
+ struct buffer_head *s_spar_map[4];
+};
+
+struct udf_virtual_data {
+ __u32 s_num_entries;
+ __u16 s_start_offset;
+};
+
+struct udf_bitmap {
+ __u32 s_extPosition;
+ int s_nr_groups;
+ struct buffer_head *s_block_bitmap[0];
+};
+
+struct udf_part_map {
+ union {
+ struct udf_bitmap *s_bitmap;
+ struct inode *s_table;
+ } s_uspace;
+ union {
+ struct udf_bitmap *s_bitmap;
+ struct inode *s_table;
+ } s_fspace;
+ __u32 s_partition_root;
+ __u32 s_partition_len;
+ __u16 s_partition_type;
+ __u16 s_partition_num;
+ union {
+ struct udf_sparing_data s_sparing;
+ struct udf_virtual_data s_virtual;
+ struct udf_meta_data s_metadata;
+ } s_type_specific;
+ __u32 (*s_partition_func)(struct super_block *, __u32, __u16, __u32);
+ __u16 s_volumeseqnum;
+ __u16 s_partition_flags;
+};
+
+#pragma pack()
+
+struct udf_sb_info {
+ struct udf_part_map *s_partmaps;
+ __u8 s_volume_ident[32];
+
+ /* Overall info */
+ __u16 s_partitions;
+ __u16 s_partition;
+
+ /* Sector headers */
+ __s32 s_session;
+ __u32 s_anchor;
+ __u32 s_last_block;
+
+ struct buffer_head *s_lvid_bh;
+
+ /* Default permissions */
+ umode_t s_umask;
+ kgid_t s_gid;
+ kuid_t s_uid;
+ umode_t s_fmode;
+ umode_t s_dmode;
+ /* Lock protecting consistency of above permission settings */
+ rwlock_t s_cred_lock;
+
+ /* Root Info */
+ struct timespec s_record_time;
+
+ /* Fileset Info */
+ __u16 s_serial_number;
+
+ /* highest UDF revision we have recorded to this media */
+ __u16 s_udfrev;
+
+ /* Miscellaneous flags */
+ unsigned long s_flags;
+
+ /* Encoding info */
+ struct nls_table *s_nls_map;
+
+ /* VAT inode */
+ struct inode *s_vat_inode;
+
+ struct mutex s_alloc_mutex;
+ /* Protected by s_alloc_mutex */
+ unsigned int s_lvid_dirty;
+};
+
static inline struct udf_sb_info *UDF_SB(struct super_block *sb)
{
return sb->s_fs_info;
}
-#define UDF_SB_FREE(X)\
-{\
- if (UDF_SB(X))\
- {\
- if (UDF_SB_PARTMAPS(X))\
- kfree(UDF_SB_PARTMAPS(X));\
- UDF_SB_PARTMAPS(X) = NULL;\
- }\
-}
+struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct super_block *sb);
-#define UDF_SB_ALLOC_PARTMAPS(X,Y)\
-{\
- UDF_SB_PARTMAPS(X) = kmalloc(sizeof(struct udf_part_map) * Y, GFP_KERNEL);\
- if (UDF_SB_PARTMAPS(X) != NULL)\
- {\
- UDF_SB_NUMPARTS(X) = Y;\
- memset(UDF_SB_PARTMAPS(X), 0x00, sizeof(struct udf_part_map) * Y);\
- }\
- else\
- {\
- UDF_SB_NUMPARTS(X) = 0;\
- udf_error(X, __FUNCTION__, "Unable to allocate space for %d partition maps", Y);\
- }\
-}
+int udf_compute_nr_groups(struct super_block *sb, u32 partition);
-#define UDF_SB_ALLOC_BITMAP(X,Y,Z)\
-{\
- int nr_groups = ((UDF_SB_PARTLEN((X),(Y)) + (sizeof(struct spaceBitmapDesc) << 3) +\
- ((X)->s_blocksize * 8) - 1) / ((X)->s_blocksize * 8));\
- int size = sizeof(struct udf_bitmap) + (sizeof(struct buffer_head *) * nr_groups);\
- if (size <= PAGE_SIZE)\
- UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap = kmalloc(size, GFP_KERNEL);\
- else\
- UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap = vmalloc(size);\
- if (UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap != NULL)\
- {\
- memset(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap, 0x00, size);\
- UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_block_bitmap =\
- (struct buffer_head **)(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap + 1);\
- UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_nr_groups = nr_groups;\
- }\
- else\
- {\
- udf_error(X, __FUNCTION__, "Unable to allocate space for bitmap and %d buffer_head pointers", nr_groups);\
- }\
+static inline int UDF_QUERY_FLAG(struct super_block *sb, int flag)
+{
+ return test_bit(flag, &UDF_SB(sb)->s_flags);
}
-#define UDF_SB_FREE_BITMAP(X,Y,Z)\
-{\
- int i;\
- int nr_groups = UDF_SB_BITMAP_NR_GROUPS(X,Y,Z);\
- int size = sizeof(struct udf_bitmap) + (sizeof(struct buffer_head *) * nr_groups);\
- for (i=0; i<nr_groups; i++)\
- {\
- if (UDF_SB_BITMAP(X,Y,Z,i))\
- udf_release_data(UDF_SB_BITMAP(X,Y,Z,i));\
- }\
- if (size <= PAGE_SIZE)\
- kfree(UDF_SB_PARTMAPS(X)[Y].Z.s_bitmap);\
- else\
- vfree(UDF_SB_PARTMAPS(X)[Y].Z.s_bitmap);\
+static inline void UDF_SET_FLAG(struct super_block *sb, int flag)
+{
+ set_bit(flag, &UDF_SB(sb)->s_flags);
}
-#define UDF_QUERY_FLAG(X,Y) ( UDF_SB(X)->s_flags & ( 1 << (Y) ) )
-#define UDF_SET_FLAG(X,Y) ( UDF_SB(X)->s_flags |= ( 1 << (Y) ) )
-#define UDF_CLEAR_FLAG(X,Y) ( UDF_SB(X)->s_flags &= ~( 1 << (Y) ) )
-
-#define UDF_UPDATE_UDFREV(X,Y) ( ((Y) > UDF_SB_UDFREV(X)) ? UDF_SB_UDFREV(X) = (Y) : UDF_SB_UDFREV(X) )
-
-#define UDF_SB_PARTMAPS(X) ( UDF_SB(X)->s_partmaps )
-#define UDF_SB_PARTTYPE(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_type )
-#define UDF_SB_PARTROOT(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_root )
-#define UDF_SB_PARTLEN(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_len )
-#define UDF_SB_PARTVSN(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_volumeseqnum )
-#define UDF_SB_PARTNUM(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_num )
-#define UDF_SB_TYPESPAR(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_type_specific.s_sparing )
-#define UDF_SB_TYPEVIRT(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_type_specific.s_virtual )
-#define UDF_SB_PARTFUNC(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_func )
-#define UDF_SB_PARTFLAGS(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_flags )
-#define UDF_SB_BITMAP(X,Y,Z,I) ( UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_block_bitmap[I] )
-#define UDF_SB_BITMAP_NR_GROUPS(X,Y,Z) ( UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_nr_groups )
-
-#define UDF_SB_VOLIDENT(X) ( UDF_SB(X)->s_volident )
-#define UDF_SB_NUMPARTS(X) ( UDF_SB(X)->s_partitions )
-#define UDF_SB_PARTITION(X) ( UDF_SB(X)->s_partition )
-#define UDF_SB_SESSION(X) ( UDF_SB(X)->s_session )
-#define UDF_SB_ANCHOR(X) ( UDF_SB(X)->s_anchor )
-#define UDF_SB_LASTBLOCK(X) ( UDF_SB(X)->s_lastblock )
-#define UDF_SB_LVIDBH(X) ( UDF_SB(X)->s_lvidbh )
-#define UDF_SB_LVID(X) ( (struct logicalVolIntegrityDesc *)UDF_SB_LVIDBH(X)->b_data )
-#define UDF_SB_LVIDIU(X) ( (struct logicalVolIntegrityDescImpUse *)&(UDF_SB_LVID(X)->impUse[le32_to_cpu(UDF_SB_LVID(X)->numOfPartitions) * 2 * sizeof(uint32_t)/sizeof(uint8_t)]) )
-
-#define UDF_SB_UMASK(X) ( UDF_SB(X)->s_umask )
-#define UDF_SB_GID(X) ( UDF_SB(X)->s_gid )
-#define UDF_SB_UID(X) ( UDF_SB(X)->s_uid )
-#define UDF_SB_RECORDTIME(X) ( UDF_SB(X)->s_recordtime )
-#define UDF_SB_SERIALNUM(X) ( UDF_SB(X)->s_serialnum )
-#define UDF_SB_UDFREV(X) ( UDF_SB(X)->s_udfrev )
-#define UDF_SB_FLAGS(X) ( UDF_SB(X)->s_flags )
-#define UDF_SB_VAT(X) ( UDF_SB(X)->s_vat )
+static inline void UDF_CLEAR_FLAG(struct super_block *sb, int flag)
+{
+ clear_bit(flag, &UDF_SB(sb)->s_flags);
+}
#endif /* __LINUX_UDF_SB_H */
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index 1d5800e0cbe..be7dabbbcb4 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -1,18 +1,46 @@
#ifndef __UDF_DECL_H
#define __UDF_DECL_H
-#include <linux/udf_fs.h>
+#define pr_fmt(fmt) "UDF-fs: " fmt
+
#include "ecma_167.h"
#include "osta_udf.h"
#include <linux/fs.h>
-#include <linux/config.h>
#include <linux/types.h>
-#include <linux/udf_fs_i.h>
-#include <linux/udf_fs_sb.h>
#include <linux/buffer_head.h>
+#include <linux/udf_fs_i.h>
+#include "udf_sb.h"
#include "udfend.h"
+#include "udf_i.h"
+
+#define UDF_PREALLOCATE
+#define UDF_DEFAULT_PREALLOC_BLOCKS 8
+
+extern __printf(3, 4) void _udf_err(struct super_block *sb,
+ const char *function, const char *fmt, ...);
+#define udf_err(sb, fmt, ...) \
+ _udf_err(sb, __func__, fmt, ##__VA_ARGS__)
+
+extern __printf(3, 4) void _udf_warn(struct super_block *sb,
+ const char *function, const char *fmt, ...);
+#define udf_warn(sb, fmt, ...) \
+ _udf_warn(sb, __func__, fmt, ##__VA_ARGS__)
+
+#define udf_info(fmt, ...) \
+ pr_info("INFO " fmt, ##__VA_ARGS__)
+
+#undef UDFFS_DEBUG
+
+#ifdef UDFFS_DEBUG
+#define udf_debug(fmt, ...) \
+ printk(KERN_DEBUG pr_fmt("%s:%d:%s: " fmt), \
+ __FILE__, __LINE__, __func__, ##__VA_ARGS__)
+#else
+#define udf_debug(fmt, ...) \
+ no_printk(fmt, ##__VA_ARGS__)
+#endif
#define udf_fixed_to_variable(x) ( ( ( (x) >> 5 ) * 39 ) + ( (x) & 0x0000001F ) )
#define udf_variable_to_fixed(x) ( ( ( (x) / 39 ) << 5 ) + ( (x) % 39 ) )
@@ -24,18 +52,27 @@
#define UDF_NAME_LEN 256
#define UDF_PATH_LEN 1023
-#define udf_file_entry_alloc_offset(inode)\
- (UDF_I_USE(inode) ?\
- sizeof(struct unallocSpaceEntry) :\
- ((UDF_I_EFE(inode) ?\
- sizeof(struct extendedFileEntry) :\
- sizeof(struct fileEntry)) + UDF_I_LENEATTR(inode)))
-
-#define udf_ext0_offset(inode)\
- (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB ?\
- udf_file_entry_alloc_offset(inode) : 0)
+static inline size_t udf_file_entry_alloc_offset(struct inode *inode)
+{
+ struct udf_inode_info *iinfo = UDF_I(inode);
+ if (iinfo->i_use)
+ return sizeof(struct unallocSpaceEntry);
+ else if (iinfo->i_efe)
+ return sizeof(struct extendedFileEntry) + iinfo->i_lenEAttr;
+ else
+ return sizeof(struct fileEntry) + iinfo->i_lenEAttr;
+}
+
+static inline size_t udf_ext0_offset(struct inode *inode)
+{
+ if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
+ return udf_file_entry_alloc_offset(inode);
+ else
+ return 0;
+}
-#define udf_get_lb_pblock(sb,loc,offset) udf_get_pblock((sb), (loc).logicalBlockNum, (loc).partitionReferenceNum, (offset))
+/* computes tag checksum */
+u8 udf_tag_checksum(const struct tag *t);
struct dentry;
struct inode;
@@ -43,78 +80,98 @@ struct task_struct;
struct buffer_head;
struct super_block;
-extern struct inode_operations udf_dir_inode_operations;
-extern struct file_operations udf_dir_operations;
-extern struct inode_operations udf_file_inode_operations;
-extern struct file_operations udf_file_operations;
-extern struct address_space_operations udf_aops;
-extern struct address_space_operations udf_adinicb_aops;
-extern struct address_space_operations udf_symlink_aops;
-
-struct udf_fileident_bh
-{
+extern const struct export_operations udf_export_ops;
+extern const struct inode_operations udf_dir_inode_operations;
+extern const struct file_operations udf_dir_operations;
+extern const struct inode_operations udf_file_inode_operations;
+extern const struct file_operations udf_file_operations;
+extern const struct inode_operations udf_symlink_inode_operations;
+extern const struct address_space_operations udf_aops;
+extern const struct address_space_operations udf_adinicb_aops;
+extern const struct address_space_operations udf_symlink_aops;
+
+struct udf_fileident_bh {
struct buffer_head *sbh;
struct buffer_head *ebh;
int soffset;
int eoffset;
};
-struct udf_vds_record
-{
+struct udf_vds_record {
uint32_t block;
uint32_t volDescSeqNum;
};
-struct generic_desc
-{
- tag descTag;
+struct generic_desc {
+ struct tag descTag;
__le32 volDescSeqNum;
};
-struct ustr
-{
+struct ustr {
uint8_t u_cmpID;
- uint8_t u_name[UDF_NAME_LEN-2];
+ uint8_t u_name[UDF_NAME_LEN - 2];
uint8_t u_len;
};
+
/* super.c */
-extern void udf_error(struct super_block *, const char *, const char *, ...);
-extern void udf_warning(struct super_block *, const char *, const char *, ...);
+
+static inline void udf_updated_lvid(struct super_block *sb)
+{
+ struct buffer_head *bh = UDF_SB(sb)->s_lvid_bh;
+
+ BUG_ON(!bh);
+ WARN_ON_ONCE(((struct logicalVolIntegrityDesc *)
+ bh->b_data)->integrityType !=
+ cpu_to_le32(LVID_INTEGRITY_TYPE_OPEN));
+ UDF_SB(sb)->s_lvid_dirty = 1;
+}
+extern u64 lvid_get_unique_id(struct super_block *sb);
+struct inode *udf_find_metadata_inode_efe(struct super_block *sb,
+ u32 meta_file_loc, u32 partition_num);
/* namei.c */
-extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *, struct fileIdentDesc *, struct udf_fileident_bh *, uint8_t *, uint8_t *);
+extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *,
+ struct fileIdentDesc *, struct udf_fileident_bh *,
+ uint8_t *, uint8_t *);
/* file.c */
-extern int udf_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
-
+extern long udf_ioctl(struct file *, unsigned int, unsigned long);
/* inode.c */
-extern struct inode *udf_iget(struct super_block *, kernel_lb_addr);
-extern int udf_sync_inode(struct inode *);
-extern void udf_expand_file_adinicb(struct inode *, int, int *);
-extern struct buffer_head * udf_expand_dir_adinicb(struct inode *, int *, int *);
-extern struct buffer_head * udf_bread(struct inode *, int, int, int *);
-extern void udf_truncate(struct inode *);
+extern struct inode *udf_iget(struct super_block *, struct kernel_lb_addr *);
+extern int udf_expand_file_adinicb(struct inode *);
+extern struct buffer_head *udf_expand_dir_adinicb(struct inode *, int *, int *);
+extern struct buffer_head *udf_bread(struct inode *, int, int, int *);
+extern int udf_setsize(struct inode *, loff_t);
extern void udf_read_inode(struct inode *);
-extern void udf_delete_inode(struct inode *);
-extern void udf_clear_inode(struct inode *);
-extern int udf_write_inode(struct inode *, int);
-extern long udf_block_map(struct inode *, long);
-extern int8_t inode_bmap(struct inode *, int, kernel_lb_addr *, uint32_t *, kernel_lb_addr *, uint32_t *, uint32_t *, struct buffer_head **);
-extern int8_t udf_add_aext(struct inode *, kernel_lb_addr *, int *, kernel_lb_addr, uint32_t, struct buffer_head **, int);
-extern int8_t udf_write_aext(struct inode *, kernel_lb_addr, int *, kernel_lb_addr, uint32_t, struct buffer_head *, int);
-extern int8_t udf_delete_aext(struct inode *, kernel_lb_addr, int, kernel_lb_addr, uint32_t, struct buffer_head *);
-extern int8_t udf_next_aext(struct inode *, kernel_lb_addr *, int *, kernel_lb_addr *, uint32_t *, struct buffer_head **, int);
-extern int8_t udf_current_aext(struct inode *, kernel_lb_addr *, int *, kernel_lb_addr *, uint32_t *, struct buffer_head **, int);
+extern void udf_evict_inode(struct inode *);
+extern int udf_write_inode(struct inode *, struct writeback_control *wbc);
+extern long udf_block_map(struct inode *, sector_t);
+extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *,
+ struct kernel_lb_addr *, uint32_t *, sector_t *);
+extern int udf_add_aext(struct inode *, struct extent_position *,
+ struct kernel_lb_addr *, uint32_t, int);
+extern void udf_write_aext(struct inode *, struct extent_position *,
+ struct kernel_lb_addr *, uint32_t, int);
+extern int8_t udf_delete_aext(struct inode *, struct extent_position,
+ struct kernel_lb_addr, uint32_t);
+extern int8_t udf_next_aext(struct inode *, struct extent_position *,
+ struct kernel_lb_addr *, uint32_t *, int);
+extern int8_t udf_current_aext(struct inode *, struct extent_position *,
+ struct kernel_lb_addr *, uint32_t *, int);
/* misc.c */
extern struct buffer_head *udf_tgetblk(struct super_block *, int);
extern struct buffer_head *udf_tread(struct super_block *, int);
-extern struct genericFormat *udf_add_extendedattr(struct inode *, uint32_t, uint32_t, uint8_t);
-extern struct genericFormat *udf_get_extendedattr(struct inode *, uint32_t, uint8_t);
-extern struct buffer_head *udf_read_tagged(struct super_block *, uint32_t, uint32_t, uint16_t *);
-extern struct buffer_head *udf_read_ptagged(struct super_block *, kernel_lb_addr, uint32_t, uint16_t *);
-extern void udf_release_data(struct buffer_head *);
+extern struct genericFormat *udf_add_extendedattr(struct inode *, uint32_t,
+ uint32_t, uint8_t);
+extern struct genericFormat *udf_get_extendedattr(struct inode *, uint32_t,
+ uint8_t);
+extern struct buffer_head *udf_read_tagged(struct super_block *, uint32_t,
+ uint32_t, uint16_t *);
+extern struct buffer_head *udf_read_ptagged(struct super_block *,
+ struct kernel_lb_addr *, uint32_t,
+ uint16_t *);
extern void udf_update_tag(char *, int);
extern void udf_new_tag(char *, uint16_t, uint16_t, uint16_t, uint32_t, int);
@@ -123,45 +180,65 @@ extern unsigned int udf_get_last_session(struct super_block *);
extern unsigned long udf_get_last_block(struct super_block *);
/* partition.c */
-extern uint32_t udf_get_pblock(struct super_block *, uint32_t, uint16_t, uint32_t);
-extern uint32_t udf_get_pblock_virt15(struct super_block *, uint32_t, uint16_t, uint32_t);
-extern uint32_t udf_get_pblock_virt20(struct super_block *, uint32_t, uint16_t, uint32_t);
-extern uint32_t udf_get_pblock_spar15(struct super_block *, uint32_t, uint16_t, uint32_t);
+extern uint32_t udf_get_pblock(struct super_block *, uint32_t, uint16_t,
+ uint32_t);
+extern uint32_t udf_get_pblock_virt15(struct super_block *, uint32_t, uint16_t,
+ uint32_t);
+extern uint32_t udf_get_pblock_virt20(struct super_block *, uint32_t, uint16_t,
+ uint32_t);
+extern uint32_t udf_get_pblock_spar15(struct super_block *, uint32_t, uint16_t,
+ uint32_t);
+extern uint32_t udf_get_pblock_meta25(struct super_block *, uint32_t, uint16_t,
+ uint32_t);
extern int udf_relocate_blocks(struct super_block *, long, long *);
+static inline uint32_t
+udf_get_lb_pblock(struct super_block *sb, struct kernel_lb_addr *loc,
+ uint32_t offset)
+{
+ return udf_get_pblock(sb, loc->logicalBlockNum,
+ loc->partitionReferenceNum, offset);
+}
+
/* unicode.c */
extern int udf_get_filename(struct super_block *, uint8_t *, uint8_t *, int);
-extern int udf_put_filename(struct super_block *, const uint8_t *, uint8_t *, int);
+extern int udf_put_filename(struct super_block *, const uint8_t *, uint8_t *,
+ int);
extern int udf_build_ustr(struct ustr *, dstring *, int);
-extern int udf_CS0toUTF8(struct ustr *, struct ustr *);
+extern int udf_CS0toUTF8(struct ustr *, const struct ustr *);
/* ialloc.c */
extern void udf_free_inode(struct inode *);
-extern struct inode * udf_new_inode (struct inode *, int, int *);
+extern struct inode *udf_new_inode(struct inode *, umode_t, int *);
/* truncate.c */
+extern void udf_truncate_tail_extent(struct inode *);
extern void udf_discard_prealloc(struct inode *);
extern void udf_truncate_extents(struct inode *);
/* balloc.c */
-extern void udf_free_blocks(struct super_block *, struct inode *, kernel_lb_addr, uint32_t, uint32_t);
-extern int udf_prealloc_blocks(struct super_block *, struct inode *, uint16_t, uint32_t, uint32_t);
-extern int udf_new_block(struct super_block *, struct inode *, uint16_t, uint32_t, int *);
-
-/* fsync.c */
-extern int udf_fsync_file(struct file *, struct dentry *, int);
+extern void udf_free_blocks(struct super_block *, struct inode *,
+ struct kernel_lb_addr *, uint32_t, uint32_t);
+extern int udf_prealloc_blocks(struct super_block *, struct inode *, uint16_t,
+ uint32_t, uint32_t);
+extern int udf_new_block(struct super_block *, struct inode *, uint16_t,
+ uint32_t, int *);
/* directory.c */
-extern struct fileIdentDesc * udf_fileident_read(struct inode *, loff_t *, struct udf_fileident_bh *, struct fileIdentDesc *, kernel_lb_addr *, uint32_t *, kernel_lb_addr *, uint32_t *, uint32_t *, struct buffer_head **);
-extern struct fileIdentDesc * udf_get_fileident(void * buffer, int bufsize, int * offset);
-extern long_ad * udf_get_filelongad(uint8_t *, int, int *, int);
-extern short_ad * udf_get_fileshortad(uint8_t *, int, int *, int);
-
-/* crc.c */
-extern uint16_t udf_crc(uint8_t *, uint32_t, uint16_t);
+extern struct fileIdentDesc *udf_fileident_read(struct inode *, loff_t *,
+ struct udf_fileident_bh *,
+ struct fileIdentDesc *,
+ struct extent_position *,
+ struct kernel_lb_addr *, uint32_t *,
+ sector_t *);
+extern struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize,
+ int *offset);
+extern struct long_ad *udf_get_filelongad(uint8_t *, int, uint32_t *, int);
+extern struct short_ad *udf_get_fileshortad(uint8_t *, int, uint32_t *, int);
/* udftime.c */
-extern time_t *udf_stamp_to_time(time_t *, long *, kernel_timestamp);
-extern kernel_timestamp *udf_time_to_stamp(kernel_timestamp *, struct timespec);
+extern struct timespec *udf_disk_stamp_to_time(struct timespec *dest,
+ struct timestamp src);
+extern struct timestamp *udf_time_to_disk_stamp(struct timestamp *dest, struct timespec src);
-#endif /* __UDF_DECL_H */
+#endif /* __UDF_DECL_H */
diff --git a/fs/udf/udfend.h b/fs/udf/udfend.h
index 17d37887956..6a9f3a9cc42 100644
--- a/fs/udf/udfend.h
+++ b/fs/udf/udfend.h
@@ -4,77 +4,73 @@
#include <asm/byteorder.h>
#include <linux/string.h>
-static inline kernel_lb_addr lelb_to_cpu(lb_addr in)
+static inline struct kernel_lb_addr lelb_to_cpu(struct lb_addr in)
{
- kernel_lb_addr out;
+ struct kernel_lb_addr out;
+
out.logicalBlockNum = le32_to_cpu(in.logicalBlockNum);
out.partitionReferenceNum = le16_to_cpu(in.partitionReferenceNum);
+
return out;
}
-static inline lb_addr cpu_to_lelb(kernel_lb_addr in)
+static inline struct lb_addr cpu_to_lelb(struct kernel_lb_addr in)
{
- lb_addr out;
+ struct lb_addr out;
+
out.logicalBlockNum = cpu_to_le32(in.logicalBlockNum);
out.partitionReferenceNum = cpu_to_le16(in.partitionReferenceNum);
- return out;
-}
-static inline kernel_timestamp lets_to_cpu(timestamp in)
-{
- kernel_timestamp out;
- memcpy(&out, &in, sizeof(timestamp));
- out.typeAndTimezone = le16_to_cpu(in.typeAndTimezone);
- out.year = le16_to_cpu(in.year);
return out;
}
-static inline short_ad lesa_to_cpu(short_ad in)
+static inline struct short_ad lesa_to_cpu(struct short_ad in)
{
- short_ad out;
+ struct short_ad out;
+
out.extLength = le32_to_cpu(in.extLength);
out.extPosition = le32_to_cpu(in.extPosition);
+
return out;
}
-static inline short_ad cpu_to_lesa(short_ad in)
+static inline struct short_ad cpu_to_lesa(struct short_ad in)
{
- short_ad out;
+ struct short_ad out;
+
out.extLength = cpu_to_le32(in.extLength);
out.extPosition = cpu_to_le32(in.extPosition);
+
return out;
}
-static inline kernel_long_ad lela_to_cpu(long_ad in)
+static inline struct kernel_long_ad lela_to_cpu(struct long_ad in)
{
- kernel_long_ad out;
+ struct kernel_long_ad out;
+
out.extLength = le32_to_cpu(in.extLength);
out.extLocation = lelb_to_cpu(in.extLocation);
+
return out;
}
-static inline long_ad cpu_to_lela(kernel_long_ad in)
+static inline struct long_ad cpu_to_lela(struct kernel_long_ad in)
{
- long_ad out;
+ struct long_ad out;
+
out.extLength = cpu_to_le32(in.extLength);
out.extLocation = cpu_to_lelb(in.extLocation);
+
return out;
}
-static inline kernel_extent_ad leea_to_cpu(extent_ad in)
+static inline struct kernel_extent_ad leea_to_cpu(struct extent_ad in)
{
- kernel_extent_ad out;
+ struct kernel_extent_ad out;
+
out.extLength = le32_to_cpu(in.extLength);
out.extLocation = le32_to_cpu(in.extLocation);
- return out;
-}
-static inline timestamp cpu_to_lets(kernel_timestamp in)
-{
- timestamp out;
- memcpy(&out, &in, sizeof(timestamp));
- out.typeAndTimezone = cpu_to_le16(in.typeAndTimezone);
- out.year = cpu_to_le16(in.year);
return out;
}
diff --git a/fs/udf/udftime.c b/fs/udf/udftime.c
index 85d8dbe843f..1f11483eba6 100644
--- a/fs/udf/udftime.c
+++ b/fs/udf/udftime.c
@@ -18,23 +18,26 @@
Boston, MA 02111-1307, USA. */
/*
- * dgb 10/02/98: ripped this from glibc source to help convert timestamps to unix time
- * 10/04/98: added new table-based lookup after seeing how ugly the gnu code is
+ * dgb 10/02/98: ripped this from glibc source to help convert timestamps
+ * to unix time
+ * 10/04/98: added new table-based lookup after seeing how ugly
+ * the gnu code is
* blf 09/27/99: ripped out all the old code and inserted new table from
- * John Brockmeyer (without leap second corrections)
- * rewrote udf_stamp_to_time and fixed timezone accounting in
- udf_time_to_stamp.
+ * John Brockmeyer (without leap second corrections)
+ * rewrote udf_stamp_to_time and fixed timezone accounting in
+ * udf_time_to_stamp.
*/
/*
* We don't take into account leap seconds. This may be correct or incorrect.
* For more NIST information (especially dealing with leap seconds), see:
- * http://www.boulder.nist.gov/timefreq/pubs/bulletin/leapsecond.htm
+ * http://www.boulder.nist.gov/timefreq/pubs/bulletin/leapsecond.htm
*/
+#include "udfdecl.h"
+
#include <linux/types.h>
#include <linux/kernel.h>
-#include "udfdecl.h"
#define EPOCH_YEAR 1970
@@ -46,37 +49,36 @@
#endif
/* How many days come before each month (0-12). */
-static const unsigned short int __mon_yday[2][13] =
-{
+static const unsigned short int __mon_yday[2][13] = {
/* Normal years. */
- { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+ {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
/* Leap years. */
- { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+ {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
};
#define MAX_YEAR_SECONDS 69
-#define SPD 0x15180 /*3600*24*/
-#define SPY(y,l,s) (SPD * (365*y+l)+s)
-
-static time_t year_seconds[MAX_YEAR_SECONDS]= {
-/*1970*/ SPY( 0, 0,0), SPY( 1, 0,0), SPY( 2, 0,0), SPY( 3, 1,0),
-/*1974*/ SPY( 4, 1,0), SPY( 5, 1,0), SPY( 6, 1,0), SPY( 7, 2,0),
-/*1978*/ SPY( 8, 2,0), SPY( 9, 2,0), SPY(10, 2,0), SPY(11, 3,0),
-/*1982*/ SPY(12, 3,0), SPY(13, 3,0), SPY(14, 3,0), SPY(15, 4,0),
-/*1986*/ SPY(16, 4,0), SPY(17, 4,0), SPY(18, 4,0), SPY(19, 5,0),
-/*1990*/ SPY(20, 5,0), SPY(21, 5,0), SPY(22, 5,0), SPY(23, 6,0),
-/*1994*/ SPY(24, 6,0), SPY(25, 6,0), SPY(26, 6,0), SPY(27, 7,0),
-/*1998*/ SPY(28, 7,0), SPY(29, 7,0), SPY(30, 7,0), SPY(31, 8,0),
-/*2002*/ SPY(32, 8,0), SPY(33, 8,0), SPY(34, 8,0), SPY(35, 9,0),
-/*2006*/ SPY(36, 9,0), SPY(37, 9,0), SPY(38, 9,0), SPY(39,10,0),
-/*2010*/ SPY(40,10,0), SPY(41,10,0), SPY(42,10,0), SPY(43,11,0),
-/*2014*/ SPY(44,11,0), SPY(45,11,0), SPY(46,11,0), SPY(47,12,0),
-/*2018*/ SPY(48,12,0), SPY(49,12,0), SPY(50,12,0), SPY(51,13,0),
-/*2022*/ SPY(52,13,0), SPY(53,13,0), SPY(54,13,0), SPY(55,14,0),
-/*2026*/ SPY(56,14,0), SPY(57,14,0), SPY(58,14,0), SPY(59,15,0),
-/*2030*/ SPY(60,15,0), SPY(61,15,0), SPY(62,15,0), SPY(63,16,0),
-/*2034*/ SPY(64,16,0), SPY(65,16,0), SPY(66,16,0), SPY(67,17,0),
-/*2038*/ SPY(68,17,0)
+#define SPD 0x15180 /*3600*24 */
+#define SPY(y, l, s) (SPD * (365 * y + l) + s)
+
+static time_t year_seconds[MAX_YEAR_SECONDS] = {
+/*1970*/ SPY(0, 0, 0), SPY(1, 0, 0), SPY(2, 0, 0), SPY(3, 1, 0),
+/*1974*/ SPY(4, 1, 0), SPY(5, 1, 0), SPY(6, 1, 0), SPY(7, 2, 0),
+/*1978*/ SPY(8, 2, 0), SPY(9, 2, 0), SPY(10, 2, 0), SPY(11, 3, 0),
+/*1982*/ SPY(12, 3, 0), SPY(13, 3, 0), SPY(14, 3, 0), SPY(15, 4, 0),
+/*1986*/ SPY(16, 4, 0), SPY(17, 4, 0), SPY(18, 4, 0), SPY(19, 5, 0),
+/*1990*/ SPY(20, 5, 0), SPY(21, 5, 0), SPY(22, 5, 0), SPY(23, 6, 0),
+/*1994*/ SPY(24, 6, 0), SPY(25, 6, 0), SPY(26, 6, 0), SPY(27, 7, 0),
+/*1998*/ SPY(28, 7, 0), SPY(29, 7, 0), SPY(30, 7, 0), SPY(31, 8, 0),
+/*2002*/ SPY(32, 8, 0), SPY(33, 8, 0), SPY(34, 8, 0), SPY(35, 9, 0),
+/*2006*/ SPY(36, 9, 0), SPY(37, 9, 0), SPY(38, 9, 0), SPY(39, 10, 0),
+/*2010*/ SPY(40, 10, 0), SPY(41, 10, 0), SPY(42, 10, 0), SPY(43, 11, 0),
+/*2014*/ SPY(44, 11, 0), SPY(45, 11, 0), SPY(46, 11, 0), SPY(47, 12, 0),
+/*2018*/ SPY(48, 12, 0), SPY(49, 12, 0), SPY(50, 12, 0), SPY(51, 13, 0),
+/*2022*/ SPY(52, 13, 0), SPY(53, 13, 0), SPY(54, 13, 0), SPY(55, 14, 0),
+/*2026*/ SPY(56, 14, 0), SPY(57, 14, 0), SPY(58, 14, 0), SPY(59, 15, 0),
+/*2030*/ SPY(60, 15, 0), SPY(61, 15, 0), SPY(62, 15, 0), SPY(63, 16, 0),
+/*2034*/ SPY(64, 16, 0), SPY(65, 16, 0), SPY(66, 16, 0), SPY(67, 17, 0),
+/*2038*/ SPY(68, 17, 0)
};
extern struct timezone sys_tz;
@@ -84,44 +86,40 @@ extern struct timezone sys_tz;
#define SECS_PER_HOUR (60 * 60)
#define SECS_PER_DAY (SECS_PER_HOUR * 24)
-time_t *
-udf_stamp_to_time(time_t *dest, long *dest_usec, kernel_timestamp src)
+struct timespec *
+udf_disk_stamp_to_time(struct timespec *dest, struct timestamp src)
{
int yday;
- uint8_t type = src.typeAndTimezone >> 12;
+ u16 typeAndTimezone = le16_to_cpu(src.typeAndTimezone);
+ u16 year = le16_to_cpu(src.year);
+ uint8_t type = typeAndTimezone >> 12;
int16_t offset;
- if (type == 1)
- {
- offset = src.typeAndTimezone << 4;
+ if (type == 1) {
+ offset = typeAndTimezone << 4;
/* sign extent offset */
offset = (offset >> 4);
if (offset == -2047) /* unspecified offset */
offset = 0;
- }
- else
+ } else
offset = 0;
- if ((src.year < EPOCH_YEAR) ||
- (src.year >= EPOCH_YEAR+MAX_YEAR_SECONDS))
- {
- *dest = -1;
- *dest_usec = -1;
+ if ((year < EPOCH_YEAR) ||
+ (year >= EPOCH_YEAR + MAX_YEAR_SECONDS)) {
return NULL;
}
- *dest = year_seconds[src.year - EPOCH_YEAR];
- *dest -= offset * 60;
+ dest->tv_sec = year_seconds[year - EPOCH_YEAR];
+ dest->tv_sec -= offset * 60;
- yday = ((__mon_yday[__isleap (src.year)]
- [src.month-1]) + (src.day-1));
- *dest += ( ( (yday* 24) + src.hour ) * 60 + src.minute ) * 60 + src.second;
- *dest_usec = src.centiseconds * 10000 + src.hundredsOfMicroseconds * 100 + src.microseconds;
+ yday = ((__mon_yday[__isleap(year)][src.month - 1]) + src.day - 1);
+ dest->tv_sec += (((yday * 24) + src.hour) * 60 + src.minute) * 60 + src.second;
+ dest->tv_nsec = 1000 * (src.centiseconds * 10000 +
+ src.hundredsOfMicroseconds * 100 + src.microseconds);
return dest;
}
-
-kernel_timestamp *
-udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts)
+struct timestamp *
+udf_time_to_disk_stamp(struct timestamp *dest, struct timespec ts)
{
long int days, rem, y;
const unsigned short int *ip;
@@ -132,7 +130,7 @@ udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts)
if (!dest)
return NULL;
- dest->typeAndTimezone = 0x1000 | (offset & 0x0FFF);
+ dest->typeAndTimezone = cpu_to_le16(0x1000 | (offset & 0x0FFF));
ts.tv_sec += offset * 60;
days = ts.tv_sec / SECS_PER_DAY;
@@ -143,31 +141,31 @@ udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts)
dest->second = rem % 60;
y = 1970;
-#define DIV(a,b) ((a) / (b) - ((a) % (b) < 0))
+#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
- while (days < 0 || days >= (__isleap(y) ? 366 : 365))
- {
+ while (days < 0 || days >= (__isleap(y) ? 366 : 365)) {
long int yg = y + days / 365 - (days % 365 < 0);
/* Adjust DAYS and Y to match the guessed year. */
days -= ((yg - y) * 365
- + LEAPS_THRU_END_OF (yg - 1)
- - LEAPS_THRU_END_OF (y - 1));
+ + LEAPS_THRU_END_OF(yg - 1)
+ - LEAPS_THRU_END_OF(y - 1));
y = yg;
}
- dest->year = y;
+ dest->year = cpu_to_le16(y);
ip = __mon_yday[__isleap(y)];
- for (y = 11; days < (long int) ip[y]; --y)
+ for (y = 11; days < (long int)ip[y]; --y)
continue;
days -= ip[y];
dest->month = y + 1;
dest->day = days + 1;
dest->centiseconds = ts.tv_nsec / 10000000;
- dest->hundredsOfMicroseconds = (ts.tv_nsec / 1000 - dest->centiseconds * 10000) / 100;
+ dest->hundredsOfMicroseconds = (ts.tv_nsec / 1000 -
+ dest->centiseconds * 10000) / 100;
dest->microseconds = (ts.tv_nsec / 1000 - dest->centiseconds * 10000 -
- dest->hundredsOfMicroseconds * 100);
+ dest->hundredsOfMicroseconds * 100);
return dest;
}
diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c
index 5a80efd8deb..44b815e57f9 100644
--- a/fs/udf/unicode.c
+++ b/fs/udf/unicode.c
@@ -11,11 +11,6 @@
* UTF-8 is explained in the IETF RFC XXXX.
* ftp://ftp.internic.net/rfc/rfcxxxx.txt
*
- * CONTACTS
- * E-mail regarding any portion of the Linux UDF file system should be
- * directed to the development team's mailing list (run by majordomo):
- * linux_udf@hpesjro.fc.hp.com
- *
* COPYRIGHT
* This file is distributed under the terms of the GNU General Public
* License (GPL). Copies of the GPL can be obtained from:
@@ -28,7 +23,8 @@
#include <linux/kernel.h>
#include <linux/string.h> /* for memset */
#include <linux/nls.h>
-#include <linux/udf_fs.h>
+#include <linux/crc-itu-t.h>
+#include <linux/slab.h>
#include "udf_sb.h"
@@ -36,12 +32,14 @@ static int udf_translate_to_linux(uint8_t *, uint8_t *, int, uint8_t *, int);
static int udf_char_to_ustr(struct ustr *dest, const uint8_t *src, int strlen)
{
- if ( (!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN-2) )
+ if ((!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN - 2))
return 0;
+
memset(dest, 0, sizeof(struct ustr));
memcpy(dest->u_name, src, strlen);
dest->u_cmpID = 0x08;
dest->u_len = strlen;
+
return strlen;
}
@@ -52,14 +50,17 @@ int udf_build_ustr(struct ustr *dest, dstring *ptr, int size)
{
int usesize;
- if ( (!dest) || (!ptr) || (!size) )
+ if (!dest || !ptr || !size)
return -1;
+ BUG_ON(size < 2);
+
+ usesize = min_t(size_t, ptr[size - 1], sizeof(dest->u_name));
+ usesize = min(usesize, size - 2);
+ dest->u_cmpID = ptr[0];
+ dest->u_len = usesize;
+ memcpy(dest->u_name, ptr + 1, usesize);
+ memset(dest->u_name + usesize, 0, sizeof(dest->u_name) - usesize);
- memset(dest, 0, sizeof(struct ustr));
- usesize= (size > UDF_NAME_LEN) ? UDF_NAME_LEN : size;
- dest->u_cmpID=ptr[0];
- dest->u_len=ptr[size-1];
- memcpy(dest->u_name, ptr+1, usesize-1);
return 0;
}
@@ -68,13 +69,14 @@ int udf_build_ustr(struct ustr *dest, dstring *ptr, int size)
*/
static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize)
{
- if ( (!dest) || (!ptr) || (!exactsize) )
+ if ((!dest) || (!ptr) || (!exactsize))
return -1;
memset(dest, 0, sizeof(struct ustr));
- dest->u_cmpID=ptr[0];
- dest->u_len=exactsize-1;
- memcpy(dest->u_name, ptr+1, exactsize-1);
+ dest->u_cmpID = ptr[0];
+ dest->u_len = exactsize - 1;
+ memcpy(dest->u_name, ptr + 1, exactsize - 1);
+
return 0;
}
@@ -84,9 +86,6 @@ static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize)
* PURPOSE
* Convert OSTA Compressed Unicode to the UTF-8 equivalent.
*
- * DESCRIPTION
- * This routine is only called by udf_filldir().
- *
* PRE-CONDITIONS
* utf Pointer to UTF-8 output buffer.
* ocu Pointer to OSTA Compressed Unicode input buffer
@@ -100,57 +99,54 @@ static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize)
* November 12, 1997 - Andrew E. Mileski
* Written, tested, and released.
*/
-int udf_CS0toUTF8(struct ustr *utf_o, struct ustr *ocu_i)
+int udf_CS0toUTF8(struct ustr *utf_o, const struct ustr *ocu_i)
{
- uint8_t *ocu;
- uint32_t c;
+ const uint8_t *ocu;
uint8_t cmp_id, ocu_len;
int i;
- ocu = ocu_i->u_name;
-
ocu_len = ocu_i->u_len;
- cmp_id = ocu_i->u_cmpID;
- utf_o->u_len = 0;
-
- if (ocu_len == 0)
- {
+ if (ocu_len == 0) {
memset(utf_o, 0, sizeof(struct ustr));
- utf_o->u_cmpID = 0;
- utf_o->u_len = 0;
return 0;
}
- if ((cmp_id != 8) && (cmp_id != 16))
- {
- printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name);
+ cmp_id = ocu_i->u_cmpID;
+ if (cmp_id != 8 && cmp_id != 16) {
+ memset(utf_o, 0, sizeof(struct ustr));
+ pr_err("unknown compression code (%d) stri=%s\n",
+ cmp_id, ocu_i->u_name);
return 0;
}
- for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN-3)) ;)
- {
+ ocu = ocu_i->u_name;
+ utf_o->u_len = 0;
+ for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) {
/* Expand OSTA compressed Unicode to Unicode */
- c = ocu[i++];
+ uint32_t c = ocu[i++];
if (cmp_id == 16)
c = (c << 8) | ocu[i++];
/* Compress Unicode to UTF-8 */
if (c < 0x80U)
utf_o->u_name[utf_o->u_len++] = (uint8_t)c;
- else if (c < 0x800U)
- {
- utf_o->u_name[utf_o->u_len++] = (uint8_t)(0xc0 | (c >> 6));
- utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | (c & 0x3f));
- }
- else
- {
- utf_o->u_name[utf_o->u_len++] = (uint8_t)(0xe0 | (c >> 12));
- utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | ((c >> 6) & 0x3f));
- utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | (c & 0x3f));
+ else if (c < 0x800U) {
+ utf_o->u_name[utf_o->u_len++] =
+ (uint8_t)(0xc0 | (c >> 6));
+ utf_o->u_name[utf_o->u_len++] =
+ (uint8_t)(0x80 | (c & 0x3f));
+ } else {
+ utf_o->u_name[utf_o->u_len++] =
+ (uint8_t)(0xe0 | (c >> 12));
+ utf_o->u_name[utf_o->u_len++] =
+ (uint8_t)(0x80 |
+ ((c >> 6) & 0x3f));
+ utf_o->u_name[utf_o->u_len++] =
+ (uint8_t)(0x80 | (c & 0x3f));
}
}
- utf_o->u_cmpID=8;
+ utf_o->u_cmpID = 8;
return utf_o->u_len;
}
@@ -191,61 +187,46 @@ try_again:
u_len = 0U;
utf_char = 0U;
utf_cnt = 0U;
- for (i = 0U; i < utf->u_len; i++)
- {
+ for (i = 0U; i < utf->u_len; i++) {
c = (uint8_t)utf->u_name[i];
/* Complete a multi-byte UTF-8 character */
- if (utf_cnt)
- {
+ if (utf_cnt) {
utf_char = (utf_char << 6) | (c & 0x3fU);
if (--utf_cnt)
continue;
- }
- else
- {
+ } else {
/* Check for a multi-byte UTF-8 character */
- if (c & 0x80U)
- {
+ if (c & 0x80U) {
/* Start a multi-byte UTF-8 character */
- if ((c & 0xe0U) == 0xc0U)
- {
+ if ((c & 0xe0U) == 0xc0U) {
utf_char = c & 0x1fU;
utf_cnt = 1;
- }
- else if ((c & 0xf0U) == 0xe0U)
- {
+ } else if ((c & 0xf0U) == 0xe0U) {
utf_char = c & 0x0fU;
utf_cnt = 2;
- }
- else if ((c & 0xf8U) == 0xf0U)
- {
+ } else if ((c & 0xf8U) == 0xf0U) {
utf_char = c & 0x07U;
utf_cnt = 3;
- }
- else if ((c & 0xfcU) == 0xf8U)
- {
+ } else if ((c & 0xfcU) == 0xf8U) {
utf_char = c & 0x03U;
utf_cnt = 4;
- }
- else if ((c & 0xfeU) == 0xfcU)
- {
+ } else if ((c & 0xfeU) == 0xfcU) {
utf_char = c & 0x01U;
utf_cnt = 5;
- }
- else
+ } else {
goto error_out;
+ }
continue;
- } else
+ } else {
/* Single byte UTF-8 character (most common) */
utf_char = c;
+ }
}
/* Choose no compression if necessary */
- if (utf_char > max_val)
- {
- if ( 0xffU == max_val )
- {
+ if (utf_char > max_val) {
+ if (max_val == 0xffU) {
max_val = 0xffffU;
ocu[0] = (uint8_t)0x10U;
goto try_again;
@@ -254,69 +235,69 @@ try_again:
}
if (max_val == 0xffffU)
- {
ocu[++u_len] = (uint8_t)(utf_char >> 8);
- }
ocu[++u_len] = (uint8_t)(utf_char & 0xffU);
}
-
- if (utf_cnt)
- {
+ if (utf_cnt) {
error_out:
ocu[++u_len] = '?';
- printk(KERN_DEBUG "udf: bad UTF-8 character\n");
+ printk(KERN_DEBUG pr_fmt("bad UTF-8 character\n"));
}
ocu[length - 1] = (uint8_t)u_len + 1;
+
return u_len + 1;
}
-static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, struct ustr *ocu_i)
+static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o,
+ const struct ustr *ocu_i)
{
- uint8_t *ocu;
- uint32_t c;
+ const uint8_t *ocu;
uint8_t cmp_id, ocu_len;
- int i;
+ int i, len;
- ocu = ocu_i->u_name;
ocu_len = ocu_i->u_len;
- cmp_id = ocu_i->u_cmpID;
- utf_o->u_len = 0;
-
- if (ocu_len == 0)
- {
+ if (ocu_len == 0) {
memset(utf_o, 0, sizeof(struct ustr));
- utf_o->u_cmpID = 0;
- utf_o->u_len = 0;
return 0;
}
- if ((cmp_id != 8) && (cmp_id != 16))
- {
- printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name);
+ cmp_id = ocu_i->u_cmpID;
+ if (cmp_id != 8 && cmp_id != 16) {
+ memset(utf_o, 0, sizeof(struct ustr));
+ pr_err("unknown compression code (%d) stri=%s\n",
+ cmp_id, ocu_i->u_name);
return 0;
}
- for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN-3)) ;)
- {
+ ocu = ocu_i->u_name;
+ utf_o->u_len = 0;
+ for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) {
/* Expand OSTA compressed Unicode to Unicode */
- c = ocu[i++];
+ uint32_t c = ocu[i++];
if (cmp_id == 16)
c = (c << 8) | ocu[i++];
- utf_o->u_len += nls->uni2char(c, &utf_o->u_name[utf_o->u_len],
- UDF_NAME_LEN - utf_o->u_len);
+ len = nls->uni2char(c, &utf_o->u_name[utf_o->u_len],
+ UDF_NAME_LEN - utf_o->u_len);
+ /* Valid character? */
+ if (len >= 0)
+ utf_o->u_len += len;
+ else
+ utf_o->u_name[utf_o->u_len++] = '?';
}
- utf_o->u_cmpID=8;
+ utf_o->u_cmpID = 8;
return utf_o->u_len;
}
-static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni, int length)
+static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni,
+ int length)
{
- unsigned len, i, max_val;
+ int len;
+ unsigned i, max_val;
uint16_t uni_char;
int u_len;
@@ -326,19 +307,22 @@ static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni, i
try_again:
u_len = 0U;
- for (i = 0U; i < uni->u_len; i++)
- {
- len = nls->char2uni(&uni->u_name[i], uni->u_len-i, &uni_char);
- if (len <= 0)
+ for (i = 0U; i < uni->u_len; i++) {
+ len = nls->char2uni(&uni->u_name[i], uni->u_len - i, &uni_char);
+ if (!len)
continue;
+ /* Invalid character, deal with it */
+ if (len < 0) {
+ len = 1;
+ uni_char = '?';
+ }
- if (uni_char > max_val)
- {
+ if (uni_char > max_val) {
max_val = 0xffffU;
ocu[0] = (uint8_t)0x10U;
goto try_again;
}
-
+
if (max_val == 0xffffU)
ocu[++u_len] = (uint8_t)(uni_char >> 8);
ocu[++u_len] = (uint8_t)(uni_char & 0xffU);
@@ -349,112 +333,108 @@ try_again:
return u_len + 1;
}
-int udf_get_filename(struct super_block *sb, uint8_t *sname, uint8_t *dname, int flen)
+int udf_get_filename(struct super_block *sb, uint8_t *sname, uint8_t *dname,
+ int flen)
{
- struct ustr filename, unifilename;
- int len;
+ struct ustr *filename, *unifilename;
+ int len = 0;
- if (udf_build_ustr_exact(&unifilename, sname, flen))
- {
+ filename = kmalloc(sizeof(struct ustr), GFP_NOFS);
+ if (!filename)
return 0;
- }
- if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8))
- {
- if (!udf_CS0toUTF8(&filename, &unifilename) )
- {
- udf_debug("Failed in udf_get_filename: sname = %s\n", sname);
- return 0;
+ unifilename = kmalloc(sizeof(struct ustr), GFP_NOFS);
+ if (!unifilename)
+ goto out1;
+
+ if (udf_build_ustr_exact(unifilename, sname, flen))
+ goto out2;
+
+ if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) {
+ if (!udf_CS0toUTF8(filename, unifilename)) {
+ udf_debug("Failed in udf_get_filename: sname = %s\n",
+ sname);
+ goto out2;
}
- }
- else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
- {
- if (!udf_CS0toNLS(UDF_SB(sb)->s_nls_map, &filename, &unifilename) )
- {
- udf_debug("Failed in udf_get_filename: sname = %s\n", sname);
- return 0;
+ } else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) {
+ if (!udf_CS0toNLS(UDF_SB(sb)->s_nls_map, filename,
+ unifilename)) {
+ udf_debug("Failed in udf_get_filename: sname = %s\n",
+ sname);
+ goto out2;
}
- }
- else
- return 0;
-
- if ((len = udf_translate_to_linux(dname, filename.u_name, filename.u_len,
- unifilename.u_name, unifilename.u_len)))
- {
- return len;
- }
- return 0;
+ } else
+ goto out2;
+
+ len = udf_translate_to_linux(dname, filename->u_name, filename->u_len,
+ unifilename->u_name, unifilename->u_len);
+out2:
+ kfree(unifilename);
+out1:
+ kfree(filename);
+ return len;
}
-int udf_put_filename(struct super_block *sb, const uint8_t *sname, uint8_t *dname, int flen)
+int udf_put_filename(struct super_block *sb, const uint8_t *sname,
+ uint8_t *dname, int flen)
{
struct ustr unifilename;
int namelen;
- if ( !(udf_char_to_ustr(&unifilename, sname, flen)) )
- {
+ if (!udf_char_to_ustr(&unifilename, sname, flen))
return 0;
- }
- if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8))
- {
- if ( !(namelen = udf_UTF8toCS0(dname, &unifilename, UDF_NAME_LEN)) )
- {
+ if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) {
+ namelen = udf_UTF8toCS0(dname, &unifilename, UDF_NAME_LEN);
+ if (!namelen)
return 0;
- }
- }
- else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
- {
- if ( !(namelen = udf_NLStoCS0(UDF_SB(sb)->s_nls_map, dname, &unifilename, UDF_NAME_LEN)) )
- {
+ } else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) {
+ namelen = udf_NLStoCS0(UDF_SB(sb)->s_nls_map, dname,
+ &unifilename, UDF_NAME_LEN);
+ if (!namelen)
return 0;
- }
- }
- else
+ } else
return 0;
return namelen;
}
#define ILLEGAL_CHAR_MARK '_'
-#define EXT_MARK '.'
-#define CRC_MARK '#'
-#define EXT_SIZE 5
+#define EXT_MARK '.'
+#define CRC_MARK '#'
+#define EXT_SIZE 5
-static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, int udfLen, uint8_t *fidName, int fidNameLen)
+static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName,
+ int udfLen, uint8_t *fidName,
+ int fidNameLen)
{
- int index, newIndex = 0, needsCRC = 0;
+ int index, newIndex = 0, needsCRC = 0;
int extIndex = 0, newExtIndex = 0, hasExt = 0;
unsigned short valueCRC;
uint8_t curr;
const uint8_t hexChar[] = "0123456789ABCDEF";
- if (udfName[0] == '.' && (udfLen == 1 ||
- (udfLen == 2 && udfName[1] == '.')))
- {
+ if (udfName[0] == '.' &&
+ (udfLen == 1 || (udfLen == 2 && udfName[1] == '.'))) {
needsCRC = 1;
newIndex = udfLen;
memcpy(newName, udfName, udfLen);
- }
- else
- {
- for (index = 0; index < udfLen; index++)
- {
+ } else {
+ for (index = 0; index < udfLen; index++) {
curr = udfName[index];
- if (curr == '/' || curr == 0)
- {
+ if (curr == '/' || curr == 0) {
needsCRC = 1;
curr = ILLEGAL_CHAR_MARK;
- while (index+1 < udfLen && (udfName[index+1] == '/' ||
- udfName[index+1] == 0))
+ while (index + 1 < udfLen &&
+ (udfName[index + 1] == '/' ||
+ udfName[index + 1] == 0))
index++;
}
- if (curr == EXT_MARK && (udfLen - index - 1) <= EXT_SIZE)
- {
+ if (curr == EXT_MARK &&
+ (udfLen - index - 1) <= EXT_SIZE) {
if (udfLen == index + 1)
hasExt = 0;
- else
- {
+ else {
hasExt = 1;
extIndex = index;
newExtIndex = newIndex;
@@ -466,26 +446,24 @@ static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, int udfLen
needsCRC = 1;
}
}
- if (needsCRC)
- {
+ if (needsCRC) {
uint8_t ext[EXT_SIZE];
int localExtIndex = 0;
- if (hasExt)
- {
+ if (hasExt) {
int maxFilenameLen;
- for(index = 0; index<EXT_SIZE && extIndex + index +1 < udfLen;
- index++ )
- {
+ for (index = 0;
+ index < EXT_SIZE && extIndex + index + 1 < udfLen;
+ index++) {
curr = udfName[extIndex + index + 1];
- if (curr == '/' || curr == 0)
- {
+ if (curr == '/' || curr == 0) {
needsCRC = 1;
curr = ILLEGAL_CHAR_MARK;
- while(extIndex + index + 2 < udfLen && (index + 1 < EXT_SIZE
- && (udfName[extIndex + index + 2] == '/' ||
- udfName[extIndex + index + 2] == 0)))
+ while (extIndex + index + 2 < udfLen &&
+ (index + 1 < EXT_SIZE &&
+ (udfName[extIndex + index + 2] == '/' ||
+ udfName[extIndex + index + 2] == 0)))
index++;
}
ext[localExtIndex++] = curr;
@@ -495,22 +473,21 @@ static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, int udfLen
newIndex = maxFilenameLen;
else
newIndex = newExtIndex;
- }
- else if (newIndex > 250)
+ } else if (newIndex > 250)
newIndex = 250;
newName[newIndex++] = CRC_MARK;
- valueCRC = udf_crc(fidName, fidNameLen, 0);
+ valueCRC = crc_itu_t(0, fidName, fidNameLen);
newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12];
newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8];
newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4];
newName[newIndex++] = hexChar[(valueCRC & 0x000f)];
- if (hasExt)
- {
+ if (hasExt) {
newName[newIndex++] = EXT_MARK;
- for (index = 0;index < localExtIndex ;index++ )
+ for (index = 0; index < localExtIndex; index++)
newName[newIndex++] = ext[index];
}
}
+
return newIndex;
}