Commit 7c955fca authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-udf-2.6

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-udf-2.6:
  UDF: Close small mem leak in udf_find_entry()
  udf: Fix directory corruption after extent merging
  udf: Protect udf_file_aio_write from possible races
  udf: Remove unnecessary bkl usages
  udf: Use of s_alloc_mutex to serialize udf_relocate_blocks() execution
  udf: Replace bkl with the UDF_I(inode)->i_data_sem for protect udf_inode_info struct
  udf: Remove BKL from free space counting functions
  udf: Call udf_add_free_space() for more blocks at once in udf_free_blocks()
  udf: Remove BKL from udf_put_super() and udf_remount_fs()
  udf: Protect default inode credentials by rwlock
  udf: Protect all modifications of LVID with s_alloc_mutex
  udf: Move handling of uniqueID into a helper function and protect it by a s_alloc_mutex
  udf: Remove BKL from udf_update_inode
  udf: Convert UDF_SB(sb)->s_flags to use bitops
  fs/udf: Add printf format/argument verification
  fs/udf: Use vzalloc

(Evil merge: this also removes the BKL dependency from the Kconfig file)
parents e9688f6a a4264b3f
config UDF_FS config UDF_FS
tristate "UDF file system support" tristate "UDF file system support"
depends on BKL # needs serious work to remove
select CRC_ITU_T select CRC_ITU_T
help help
This is the new file system used on some CD-ROMs and DVDs. Say Y if This is the new file system used on some CD-ROMs and DVDs. Say Y if
......
...@@ -157,10 +157,9 @@ static void udf_bitmap_free_blocks(struct super_block *sb, ...@@ -157,10 +157,9 @@ static void udf_bitmap_free_blocks(struct super_block *sb,
udf_debug("bit %ld already set\n", bit + i); udf_debug("bit %ld already set\n", bit + i);
udf_debug("byte=%2x\n", udf_debug("byte=%2x\n",
((char *)bh->b_data)[(bit + i) >> 3]); ((char *)bh->b_data)[(bit + i) >> 3]);
} else {
udf_add_free_space(sb, sbi->s_partition, 1);
} }
} }
udf_add_free_space(sb, sbi->s_partition, count);
mark_buffer_dirty(bh); mark_buffer_dirty(bh);
if (overflow) { if (overflow) {
block += count; block += count;
......
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include "udf_i.h" #include "udf_i.h"
...@@ -190,18 +189,14 @@ static int udf_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -190,18 +189,14 @@ static int udf_readdir(struct file *filp, void *dirent, filldir_t filldir)
struct inode *dir = filp->f_path.dentry->d_inode; struct inode *dir = filp->f_path.dentry->d_inode;
int result; int result;
lock_kernel();
if (filp->f_pos == 0) { if (filp->f_pos == 0) {
if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR) < 0) { if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR) < 0) {
unlock_kernel();
return 0; return 0;
} }
filp->f_pos++; filp->f_pos++;
} }
result = do_udf_readdir(dir, filp, filldir, dirent); result = do_udf_readdir(dir, filp, filldir, dirent);
unlock_kernel();
return result; return result;
} }
......
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
#include <linux/string.h> /* memset */ #include <linux/string.h> /* memset */
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/smp_lock.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/aio.h> #include <linux/aio.h>
...@@ -114,6 +113,7 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, ...@@ -114,6 +113,7 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
size_t count = iocb->ki_left; size_t count = iocb->ki_left;
struct udf_inode_info *iinfo = UDF_I(inode); struct udf_inode_info *iinfo = UDF_I(inode);
down_write(&iinfo->i_data_sem);
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
if (file->f_flags & O_APPEND) if (file->f_flags & O_APPEND)
pos = inode->i_size; pos = inode->i_size;
...@@ -126,6 +126,7 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, ...@@ -126,6 +126,7 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
udf_expand_file_adinicb(inode, pos + count, &err); udf_expand_file_adinicb(inode, pos + count, &err);
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
udf_debug("udf_expand_adinicb: err=%d\n", err); udf_debug("udf_expand_adinicb: err=%d\n", err);
up_write(&iinfo->i_data_sem);
return err; return err;
} }
} else { } else {
...@@ -135,6 +136,7 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, ...@@ -135,6 +136,7 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
iinfo->i_lenAlloc = inode->i_size; iinfo->i_lenAlloc = inode->i_size;
} }
} }
up_write(&iinfo->i_data_sem);
retval = generic_file_aio_write(iocb, iov, nr_segs, ppos); retval = generic_file_aio_write(iocb, iov, nr_segs, ppos);
if (retval > 0) if (retval > 0)
...@@ -149,8 +151,6 @@ long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -149,8 +151,6 @@ long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
long old_block, new_block; long old_block, new_block;
int result = -EINVAL; int result = -EINVAL;
lock_kernel();
if (file_permission(filp, MAY_READ) != 0) { if (file_permission(filp, MAY_READ) != 0) {
udf_debug("no permission to access inode %lu\n", inode->i_ino); udf_debug("no permission to access inode %lu\n", inode->i_ino);
result = -EPERM; result = -EPERM;
...@@ -196,7 +196,6 @@ long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -196,7 +196,6 @@ long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
} }
out: out:
unlock_kernel();
return result; return result;
} }
...@@ -204,10 +203,10 @@ static int udf_release_file(struct inode *inode, struct file *filp) ...@@ -204,10 +203,10 @@ static int udf_release_file(struct inode *inode, struct file *filp)
{ {
if (filp->f_mode & FMODE_WRITE) { if (filp->f_mode & FMODE_WRITE) {
mutex_lock(&inode->i_mutex); mutex_lock(&inode->i_mutex);
lock_kernel(); down_write(&UDF_I(inode)->i_data_sem);
udf_discard_prealloc(inode); udf_discard_prealloc(inode);
udf_truncate_tail_extent(inode); udf_truncate_tail_extent(inode);
unlock_kernel(); up_write(&UDF_I(inode)->i_data_sem);
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
} }
return 0; return 0;
......
...@@ -92,28 +92,19 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err) ...@@ -92,28 +92,19 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err)
return NULL; return NULL;
} }
mutex_lock(&sbi->s_alloc_mutex);
if (sbi->s_lvid_bh) { if (sbi->s_lvid_bh) {
struct logicalVolIntegrityDesc *lvid = struct logicalVolIntegrityDescImpUse *lvidiu;
(struct logicalVolIntegrityDesc *)
sbi->s_lvid_bh->b_data; iinfo->i_unique = lvid_get_unique_id(sb);
struct logicalVolIntegrityDescImpUse *lvidiu = mutex_lock(&sbi->s_alloc_mutex);
udf_sb_lvidiu(sbi); lvidiu = udf_sb_lvidiu(sbi);
struct logicalVolHeaderDesc *lvhd;
uint64_t uniqueID;
lvhd = (struct logicalVolHeaderDesc *)
(lvid->logicalVolContentsUse);
if (S_ISDIR(mode)) if (S_ISDIR(mode))
le32_add_cpu(&lvidiu->numDirs, 1); le32_add_cpu(&lvidiu->numDirs, 1);
else else
le32_add_cpu(&lvidiu->numFiles, 1); le32_add_cpu(&lvidiu->numFiles, 1);
iinfo->i_unique = uniqueID = le64_to_cpu(lvhd->uniqueID);
if (!(++uniqueID & 0x00000000FFFFFFFFUL))
uniqueID += 16;
lvhd->uniqueID = cpu_to_le64(uniqueID);
udf_updated_lvid(sb); udf_updated_lvid(sb);
mutex_unlock(&sbi->s_alloc_mutex);
} }
mutex_unlock(&sbi->s_alloc_mutex);
inode_init_owner(inode, dir, mode); inode_init_owner(inode, dir, mode);
......
...@@ -31,7 +31,6 @@ ...@@ -31,7 +31,6 @@
#include "udfdecl.h" #include "udfdecl.h"
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/smp_lock.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
...@@ -51,6 +50,7 @@ MODULE_LICENSE("GPL"); ...@@ -51,6 +50,7 @@ MODULE_LICENSE("GPL");
static mode_t udf_convert_permissions(struct fileEntry *); static mode_t udf_convert_permissions(struct fileEntry *);
static int udf_update_inode(struct inode *, int); static int udf_update_inode(struct inode *, int);
static void udf_fill_inode(struct inode *, struct buffer_head *); static void udf_fill_inode(struct inode *, struct buffer_head *);
static int udf_sync_inode(struct inode *inode);
static int udf_alloc_i_data(struct inode *inode, size_t size); static int udf_alloc_i_data(struct inode *inode, size_t size);
static struct buffer_head *inode_getblk(struct inode *, sector_t, int *, static struct buffer_head *inode_getblk(struct inode *, sector_t, int *,
sector_t *, int *); sector_t *, int *);
...@@ -79,9 +79,7 @@ void udf_evict_inode(struct inode *inode) ...@@ -79,9 +79,7 @@ void udf_evict_inode(struct inode *inode)
want_delete = 1; want_delete = 1;
inode->i_size = 0; inode->i_size = 0;
udf_truncate(inode); udf_truncate(inode);
lock_kernel();
udf_update_inode(inode, IS_SYNC(inode)); udf_update_inode(inode, IS_SYNC(inode));
unlock_kernel();
} }
invalidate_inode_buffers(inode); invalidate_inode_buffers(inode);
end_writeback(inode); end_writeback(inode);
...@@ -97,9 +95,7 @@ void udf_evict_inode(struct inode *inode) ...@@ -97,9 +95,7 @@ void udf_evict_inode(struct inode *inode)
kfree(iinfo->i_ext.i_data); kfree(iinfo->i_ext.i_data);
iinfo->i_ext.i_data = NULL; iinfo->i_ext.i_data = NULL;
if (want_delete) { if (want_delete) {
lock_kernel();
udf_free_inode(inode); udf_free_inode(inode);
unlock_kernel();
} }
} }
...@@ -302,10 +298,9 @@ static int udf_get_block(struct inode *inode, sector_t block, ...@@ -302,10 +298,9 @@ static int udf_get_block(struct inode *inode, sector_t block,
err = -EIO; err = -EIO;
new = 0; new = 0;
bh = NULL; bh = NULL;
lock_kernel();
iinfo = UDF_I(inode); iinfo = UDF_I(inode);
down_write(&iinfo->i_data_sem);
if (block == iinfo->i_next_alloc_block + 1) { if (block == iinfo->i_next_alloc_block + 1) {
iinfo->i_next_alloc_block++; iinfo->i_next_alloc_block++;
iinfo->i_next_alloc_goal++; iinfo->i_next_alloc_goal++;
...@@ -324,7 +319,7 @@ static int udf_get_block(struct inode *inode, sector_t block, ...@@ -324,7 +319,7 @@ static int udf_get_block(struct inode *inode, sector_t block,
map_bh(bh_result, inode->i_sb, phys); map_bh(bh_result, inode->i_sb, phys);
abort: abort:
unlock_kernel(); up_write(&iinfo->i_data_sem);
return err; return err;
} }
...@@ -1022,16 +1017,16 @@ void udf_truncate(struct inode *inode) ...@@ -1022,16 +1017,16 @@ void udf_truncate(struct inode *inode)
if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
return; return;
lock_kernel();
iinfo = UDF_I(inode); iinfo = UDF_I(inode);
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
down_write(&iinfo->i_data_sem);
if (inode->i_sb->s_blocksize < if (inode->i_sb->s_blocksize <
(udf_file_entry_alloc_offset(inode) + (udf_file_entry_alloc_offset(inode) +
inode->i_size)) { inode->i_size)) {
udf_expand_file_adinicb(inode, inode->i_size, &err); udf_expand_file_adinicb(inode, inode->i_size, &err);
if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
inode->i_size = iinfo->i_lenAlloc; inode->i_size = iinfo->i_lenAlloc;
unlock_kernel(); up_write(&iinfo->i_data_sem);
return; return;
} else } else
udf_truncate_extents(inode); udf_truncate_extents(inode);
...@@ -1042,10 +1037,13 @@ void udf_truncate(struct inode *inode) ...@@ -1042,10 +1037,13 @@ void udf_truncate(struct inode *inode)
offset - udf_file_entry_alloc_offset(inode)); offset - udf_file_entry_alloc_offset(inode));
iinfo->i_lenAlloc = inode->i_size; iinfo->i_lenAlloc = inode->i_size;
} }
up_write(&iinfo->i_data_sem);
} else { } else {
block_truncate_page(inode->i_mapping, inode->i_size, block_truncate_page(inode->i_mapping, inode->i_size,
udf_get_block); udf_get_block);
down_write(&iinfo->i_data_sem);
udf_truncate_extents(inode); udf_truncate_extents(inode);
up_write(&iinfo->i_data_sem);
} }
inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb); inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb);
...@@ -1053,7 +1051,6 @@ void udf_truncate(struct inode *inode) ...@@ -1053,7 +1051,6 @@ void udf_truncate(struct inode *inode)
udf_sync_inode(inode); udf_sync_inode(inode);
else else
mark_inode_dirty(inode); mark_inode_dirty(inode);
unlock_kernel();
} }
static void __udf_read_inode(struct inode *inode) static void __udf_read_inode(struct inode *inode)
...@@ -1202,6 +1199,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) ...@@ -1202,6 +1199,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
return; return;
} }
read_lock(&sbi->s_cred_lock);
inode->i_uid = le32_to_cpu(fe->uid); inode->i_uid = le32_to_cpu(fe->uid);
if (inode->i_uid == -1 || if (inode->i_uid == -1 ||
UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_IGNORE) || UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_IGNORE) ||
...@@ -1214,13 +1212,6 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) ...@@ -1214,13 +1212,6 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_GID_SET)) UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_GID_SET))
inode->i_gid = UDF_SB(inode->i_sb)->s_gid; inode->i_gid = UDF_SB(inode->i_sb)->s_gid;
inode->i_nlink = le16_to_cpu(fe->fileLinkCount);
if (!inode->i_nlink)
inode->i_nlink = 1;
inode->i_size = le64_to_cpu(fe->informationLength);
iinfo->i_lenExtents = inode->i_size;
if (fe->icbTag.fileType != ICBTAG_FILE_TYPE_DIRECTORY && if (fe->icbTag.fileType != ICBTAG_FILE_TYPE_DIRECTORY &&
sbi->s_fmode != UDF_INVALID_MODE) sbi->s_fmode != UDF_INVALID_MODE)
inode->i_mode = sbi->s_fmode; inode->i_mode = sbi->s_fmode;
...@@ -1230,6 +1221,14 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) ...@@ -1230,6 +1221,14 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
else else
inode->i_mode = udf_convert_permissions(fe); inode->i_mode = udf_convert_permissions(fe);
inode->i_mode &= ~sbi->s_umask; inode->i_mode &= ~sbi->s_umask;
read_unlock(&sbi->s_cred_lock);
inode->i_nlink = le16_to_cpu(fe->fileLinkCount);
if (!inode->i_nlink)
inode->i_nlink = 1;
inode->i_size = le64_to_cpu(fe->informationLength);
iinfo->i_lenExtents = inode->i_size;
if (iinfo->i_efe == 0) { if (iinfo->i_efe == 0) {
inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) << inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) <<
...@@ -1373,16 +1372,10 @@ static mode_t udf_convert_permissions(struct fileEntry *fe) ...@@ -1373,16 +1372,10 @@ static mode_t udf_convert_permissions(struct fileEntry *fe)
int udf_write_inode(struct inode *inode, struct writeback_control *wbc) int udf_write_inode(struct inode *inode, struct writeback_control *wbc)
{ {
int ret; return udf_update_inode(inode, wbc->sync_mode == WB_SYNC_ALL);
lock_kernel();
ret = udf_update_inode(inode, wbc->sync_mode == WB_SYNC_ALL);
unlock_kernel();
return ret;
} }
int udf_sync_inode(struct inode *inode) static int udf_sync_inode(struct inode *inode)
{ {
return udf_update_inode(inode, 1); return udf_update_inode(inode, 1);
} }
...@@ -2048,7 +2041,7 @@ long udf_block_map(struct inode *inode, sector_t block) ...@@ -2048,7 +2041,7 @@ long udf_block_map(struct inode *inode, sector_t block)
struct extent_position epos = {}; struct extent_position epos = {};
int ret; int ret;
lock_kernel(); down_read(&UDF_I(inode)->i_data_sem);
if (inode_bmap(inode, block, &epos, &eloc, &elen, &offset) == if (inode_bmap(inode, block, &epos, &eloc, &elen, &offset) ==
(EXT_RECORDED_ALLOCATED >> 30)) (EXT_RECORDED_ALLOCATED >> 30))
...@@ -2056,7 +2049,7 @@ long udf_block_map(struct inode *inode, sector_t block) ...@@ -2056,7 +2049,7 @@ long udf_block_map(struct inode *inode, sector_t block)
else else
ret = 0; ret = 0;
unlock_kernel(); up_read(&UDF_I(inode)->i_data_sem);
brelse(epos.bh); brelse(epos.bh);
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_VARCONV)) if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_VARCONV))
......
This diff is collapsed.
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/mutex.h>
uint32_t udf_get_pblock(struct super_block *sb, uint32_t block, uint32_t udf_get_pblock(struct super_block *sb, uint32_t block,
uint16_t partition, uint32_t offset) uint16_t partition, uint32_t offset)
...@@ -159,7 +160,9 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block) ...@@ -159,7 +160,9 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
struct udf_sb_info *sbi = UDF_SB(sb); struct udf_sb_info *sbi = UDF_SB(sb);
u16 reallocationTableLen; u16 reallocationTableLen;
struct buffer_head *bh; struct buffer_head *bh;
int ret = 0;
mutex_lock(&sbi->s_alloc_mutex);
for (i = 0; i < sbi->s_partitions; i++) { for (i = 0; i < sbi->s_partitions; i++) {
struct udf_part_map *map = &sbi->s_partmaps[i]; struct udf_part_map *map = &sbi->s_partmaps[i];
if (old_block > map->s_partition_root && if (old_block > map->s_partition_root &&
...@@ -175,8 +178,10 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block) ...@@ -175,8 +178,10 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
break; break;
} }
if (!st) if (!st) {
return 1; ret = 1;
goto out;
}
reallocationTableLen = reallocationTableLen =
le16_to_cpu(st->reallocationTableLen); le16_to_cpu(st->reallocationTableLen);
...@@ -207,14 +212,16 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block) ...@@ -207,14 +212,16 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
((old_block - ((old_block -
map->s_partition_root) & map->s_partition_root) &
(sdata->s_packet_len - 1)); (sdata->s_packet_len - 1));
return 0; ret = 0;
goto out;
} else if (origLoc == packet) { } else if (origLoc == packet) {
*new_block = le32_to_cpu( *new_block = le32_to_cpu(
entry->mappedLocation) + entry->mappedLocation) +
((old_block - ((old_block -
map->s_partition_root) & map->s_partition_root) &
(sdata->s_packet_len - 1)); (sdata->s_packet_len - 1));
return 0; ret = 0;
goto out;
} else if (origLoc > packet) } else if (origLoc > packet)
break; break;
} }
...@@ -251,20 +258,24 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block) ...@@ -251,20 +258,24 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
st->mapEntry[k].mappedLocation) + st->mapEntry[k].mappedLocation) +
((old_block - map->s_partition_root) & ((old_block - map->s_partition_root) &
(sdata->s_packet_len - 1)); (sdata->s_packet_len - 1));
return 0; ret = 0;
goto out;
} }
return 1; ret = 1;
goto out;
} /* if old_block */ } /* if old_block */
} }
if (i == sbi->s_partitions) { if (i == sbi->s_partitions) {
/* outside of partitions */ /* outside of partitions */
/* for now, fail =) */ /* for now, fail =) */
return 1; ret = 1;
} }
return 0; out:
mutex_unlock(&sbi->s_alloc_mutex);
return ret;
} }
static uint32_t udf_try_read_meta(struct inode *inode, uint32_t block, static uint32_t udf_try_read_meta(struct inode *inode, uint32_t block,
......
...@@ -48,7 +48,6 @@ ...@@ -48,7 +48,6 @@
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/cdrom.h> #include <linux/cdrom.h>
#include <linux/nls.h> #include <linux/nls.h>
#include <linux/smp_lock.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/vfs.h> #include <linux/vfs.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
...@@ -135,6 +134,7 @@ static struct inode *udf_alloc_inode(struct super_block *sb) ...@@ -135,6 +134,7 @@ static struct inode *udf_alloc_inode(struct super_block *sb)
ei->i_next_alloc_block = 0; ei->i_next_alloc_block = 0;
ei->i_next_alloc_goal = 0; ei->i_next_alloc_goal = 0;
ei->i_strat4096 = 0; ei->i_strat4096 = 0;
init_rwsem(&ei->i_data_sem);
return &ei->vfs_inode; return &ei->vfs_inode;
} }
...@@ -574,13 +574,14 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options) ...@@ -574,13 +574,14 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
if (!udf_parse_options(options, &uopt, true)) if (!udf_parse_options(options, &uopt, true))
return -EINVAL; return -EINVAL;
lock_kernel(); write_lock(&sbi->s_cred_lock);
sbi->s_flags = uopt.flags; sbi->s_flags = uopt.flags;
sbi->s_uid = uopt.uid; sbi->s_uid = uopt.uid;
sbi->s_gid = uopt.gid; sbi->s_gid = uopt.gid;
sbi->s_umask = uopt.umask; sbi->s_umask = uopt.umask;
sbi->s_fmode = uopt.fmode; sbi->s_fmode = uopt.fmode;
sbi->s_dmode = uopt.dmode; sbi->s_dmode = uopt.dmode;
write_unlock(&sbi->s_cred_lock);
if (sbi->s_lvid_bh) { if (sbi->s_lvid_bh) {
int write_rev = le16_to_cpu(udf_sb_lvidiu(sbi)->minUDFWriteRev); int write_rev = le16_to_cpu(udf_sb_lvidiu(sbi)->minUDFWriteRev);
...@@ -597,7 +598,6 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options) ...@@ -597,7 +598,6 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
udf_open_lvid(sb); udf_open_lvid(sb);
out_unlock: out_unlock:
unlock_kernel();
return error; return error;
} }
...@@ -966,9 +966,9 @@ static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index) ...@@ -966,9 +966,9 @@ static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index)
(sizeof(struct buffer_head *) * nr_groups); (sizeof(struct buffer_head *) * nr_groups);
if (size <= PAGE_SIZE) if (size <= PAGE_SIZE)
bitmap = kmalloc(size, GFP_KERNEL); bitmap = kzalloc(size, GFP_KERNEL);
else else
bitmap = vmalloc(size); /* TODO: get rid of vmalloc */ bitmap = vzalloc(size); /* TODO: get rid of vzalloc */
if (bitmap == NULL) { if (bitmap == NULL) {
udf_error(sb, __func__, udf_error(sb, __func__,
...@@ -977,7 +977,6 @@ static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index) ...@@ -977,7 +977,6 @@ static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index)
return NULL; return NULL;
} }
memset(bitmap, 0x00, size);
bitmap->s_block_bitmap = (struct buffer_head **)(bitmap + 1); bitmap->s_block_bitmap = (struct buffer_head **)(bitmap + 1);
bitmap->s_nr_groups = nr_groups; bitmap->s_nr_groups = nr_groups;
return bitmap; return bitmap;
...@@ -1781,6 +1780,8 @@ static void udf_open_lvid(struct super_block *sb) ...@@ -1781,6 +1780,8 @@ static void udf_open_lvid(struct super_block *sb)
if (!bh) if (!bh)
return; return;
mutex_lock(&sbi->s_alloc_mutex);
lvid = (struct logicalVolIntegrityDesc *)bh->b_data; lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
lvidiu = udf_sb_lvidiu(sbi); lvidiu = udf_sb_lvidiu(sbi);
...@@ -1797,6 +1798,7 @@ static void udf_open_lvid(struct super_block *sb) ...@@ -1797,6 +1798,7 @@ static void udf_open_lvid(struct super_block *sb)
lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag);
mark_buffer_dirty(bh); mark_buffer_dirty(bh);
sbi->s_lvid_dirty = 0; sbi->s_lvid_dirty = 0;
mutex_unlock(&sbi->s_alloc_mutex);
} }
static void udf_close_lvid(struct super_block *sb) static void udf_close_lvid(struct super_block *sb)
...@@ -1809,6 +1811,7 @@ static void udf_close_lvid(struct super_block *sb) ...@@ -1809,6 +1811,7 @@ static void udf_close_lvid(struct super_block *sb)
if (!bh) if (!bh)
return; return;
mutex_lock(&sbi->s_alloc_mutex);
lvid = (struct logicalVolIntegrityDesc *)bh->b_data; lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
lvidiu = udf_sb_lvidiu(sbi); lvidiu = udf_sb_lvidiu(sbi);
lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
...@@ -1829,6 +1832,34 @@ static void udf_close_lvid(struct super_block *sb) ...@@ -1829,6 +1832,34 @@ static void udf_close_lvid(struct super_block *sb)
lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag);
mark_buffer_dirty(bh); mark_buffer_dirty(bh);
sbi->s_lvid_dirty = 0; sbi->s_lvid_dirty = 0;
mutex_unlock(&sbi->s_alloc_mutex);
}
u64 lvid_get_unique_id(struct super_block *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;
} }
static void udf_sb_free_bitmap(struct udf_bitmap *bitmap) static void udf_sb_free_bitmap(struct udf_bitmap *bitmap)
...@@ -1886,8 +1917,6 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -1886,8 +1917,6 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
struct kernel_lb_addr rootdir, fileset; struct kernel_lb_addr rootdir, fileset;
struct udf_sb_info *sbi; struct udf_sb_info *sbi;
lock_kernel();
uopt.flags = (1 << UDF_FLAG_USE_AD_IN_ICB) | (1 << UDF_FLAG_STRICT); uopt.flags = (1 << UDF_FLAG_USE_AD_IN_ICB) | (1 << UDF_FLAG_STRICT);
uopt.uid = -1; uopt.uid = -1;
uopt.gid = -1; uopt.gid = -1;
...@@ -1896,10 +1925,8 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -1896,10 +1925,8 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
uopt.dmode = UDF_INVALID_MODE; uopt.dmode = UDF_INVALID_MODE;
sbi = kzalloc(sizeof(struct udf_sb_info), GFP_KERNEL); sbi = kzalloc(sizeof(struct udf_sb_info), GFP_KERNEL);
if (!sbi) { if (!sbi)
unlock_kernel();
return -ENOMEM; return -ENOMEM;
}
sb->s_fs_info = sbi; sb->s_fs_info = sbi;
...@@ -1936,6 +1963,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -1936,6 +1963,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
sbi->s_fmode = uopt.fmode; sbi->s_fmode = uopt.fmode;
sbi->s_dmode = uopt.dmode; sbi->s_dmode = uopt.dmode;
sbi->s_nls_map = uopt.nls_map; sbi->s_nls_map = uopt.nls_map;
rwlock_init(&sbi->s_cred_lock);
if (uopt.session == 0xFFFFFFFF) if (uopt.session == 0xFFFFFFFF)
sbi->s_session = udf_get_last_session(sb); sbi->s_session = udf_get_last_session(sb);
...@@ -2045,7 +2073,6 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -2045,7 +2073,6 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
goto error_out; goto error_out;
} }
sb->s_maxbytes = MAX_LFS_FILESIZE; sb->s_maxbytes = MAX_LFS_FILESIZE;
unlock_kernel();
return 0; return 0;
error_out: error_out:
...@@ -2066,7 +2093,6 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -2066,7 +2093,6 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
kfree(sbi); kfree(sbi);
sb->s_fs_info = NULL; sb->s_fs_info = NULL;
unlock_kernel();
return -EINVAL; return -EINVAL;
} }
...@@ -2105,8 +2131,6 @@ static void udf_put_super(struct super_block *sb) ...@@ -2105,8 +2131,6 @@ static void udf_put_super(struct super_block *sb)
sbi = UDF_SB(sb); sbi = UDF_SB(sb);
lock_kernel();
if (sbi->s_vat_inode) if (sbi->s_vat_inode)
iput(sbi->s_vat_inode); iput(sbi->s_vat_inode);
if (sbi->s_partitions) if (sbi->s_partitions)
...@@ -2122,8 +2146,6 @@ static void udf_put_super(struct super_block *sb) ...@@ -2122,8 +2146,6 @@ static void udf_put_super(struct super_block *sb)
kfree(sbi->s_partmaps); kfree(sbi->s_partmaps);
kfree(sb->s_fs_info); kfree(sb->s_fs_info);
sb->s_fs_info = NULL; sb->s_fs_info = NULL;
unlock_kernel();
} }
static int udf_sync_fs(struct super_block *sb, int wait) static int udf_sync_fs(struct super_block *sb, int wait)
...@@ -2186,8 +2208,6 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb, ...@@ -2186,8 +2208,6 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb,
uint16_t ident; uint16_t ident;
struct spaceBitmapDesc *bm; struct spaceBitmapDesc *bm;
lock_kernel();
loc.logicalBlockNum = bitmap->s_extPosition; loc.logicalBlockNum = bitmap->s_extPosition;
loc.partitionReferenceNum = UDF_SB(sb)->s_partition; loc.partitionReferenceNum = UDF_SB(sb)->s_partition;
bh = udf_read_ptagged(sb, &loc, 0, &ident); bh = udf_read_ptagged(sb, &loc, 0, &ident);
...@@ -2224,10 +2244,7 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb, ...@@ -2224,10 +2244,7 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb,
} }
} }
brelse(bh); brelse(bh);
out: out:
unlock_kernel();
return accum; return accum;
} }
...@@ -2240,8 +2257,7 @@ static unsigned int udf_count_free_table(struct super_block *sb, ...@@ -2240,8 +2257,7 @@ static unsigned int udf_count_free_table(struct super_block *sb,
int8_t etype; int8_t etype;
struct extent_position epos; struct extent_position epos;
lock_kernel(); mutex_lock(&UDF_SB(sb)->s_alloc_mutex);
epos.block = UDF_I(table)->i_location; epos.block = UDF_I(table)->i_location;
epos.offset = sizeof(struct unallocSpaceEntry); epos.offset = sizeof(struct unallocSpaceEntry);
epos.bh = NULL; epos.bh = NULL;
...@@ -2250,8 +2266,7 @@ static unsigned int udf_count_free_table(struct super_block *sb, ...@@ -2250,8 +2266,7 @@ static unsigned int udf_count_free_table(struct super_block *sb,
accum += (elen >> table->i_sb->s_blocksize_bits); accum += (elen >> table->i_sb->s_blocksize_bits);
brelse(epos.bh); brelse(epos.bh);
mutex_unlock(&UDF_SB(sb)->s_alloc_mutex);
unlock_kernel();
return accum; return accum;
} }
......
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/smp_lock.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include "udf_i.h" #include "udf_i.h"
...@@ -78,13 +77,16 @@ static int udf_symlink_filler(struct file *file, struct page *page) ...@@ -78,13 +77,16 @@ static int udf_symlink_filler(struct file *file, struct page *page)
int err = -EIO; int err = -EIO;
unsigned char *p = kmap(page); unsigned char *p = kmap(page);
struct udf_inode_info *iinfo; struct udf_inode_info *iinfo;
uint32_t pos;
lock_kernel();
iinfo = UDF_I(inode); 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) { if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
symlink = iinfo->i_ext.i_data + iinfo->i_lenEAttr; symlink = iinfo->i_ext.i_data + iinfo->i_lenEAttr;
} else { } else {
bh = sb_bread(inode->i_sb, udf_block_map(inode, 0)); bh = sb_bread(inode->i_sb, pos);
if (!bh) if (!bh)
goto out; goto out;
...@@ -95,14 +97,14 @@ static int udf_symlink_filler(struct file *file, struct page *page) ...@@ -95,14 +97,14 @@ static int udf_symlink_filler(struct file *file, struct page *page)
udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p); udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p);
brelse(bh); brelse(bh);
unlock_kernel(); up_read(&iinfo->i_data_sem);
SetPageUptodate(page); SetPageUptodate(page);
kunmap(page); kunmap(page);
unlock_page(page); unlock_page(page);
return 0; return 0;
out: out:
unlock_kernel(); up_read(&iinfo->i_data_sem);
SetPageError(page); SetPageError(page);
kunmap(page); kunmap(page);
unlock_page(page); unlock_page(page);
......
#ifndef _UDF_I_H #ifndef _UDF_I_H
#define _UDF_I_H #define _UDF_I_H
/*
* 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 udf_inode_info {
struct timespec i_crtime; struct timespec i_crtime;
/* Physical address of inode */ /* Physical address of inode */
...@@ -21,6 +33,7 @@ struct udf_inode_info { ...@@ -21,6 +33,7 @@ struct udf_inode_info {
struct long_ad *i_lad; struct long_ad *i_lad;
__u8 *i_data; __u8 *i_data;
} i_ext; } i_ext;
struct rw_semaphore i_data_sem;
struct inode vfs_inode; struct inode vfs_inode;
}; };
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#define __LINUX_UDF_SB_H #define __LINUX_UDF_SB_H
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/bitops.h>
/* Since UDF 2.01 is ISO 13346 based... */ /* Since UDF 2.01 is ISO 13346 based... */
#define UDF_SUPER_MAGIC 0x15013346 #define UDF_SUPER_MAGIC 0x15013346
...@@ -128,6 +129,8 @@ struct udf_sb_info { ...@@ -128,6 +129,8 @@ struct udf_sb_info {
uid_t s_uid; uid_t s_uid;
mode_t s_fmode; mode_t s_fmode;
mode_t s_dmode; mode_t s_dmode;
/* Lock protecting consistency of above permission settings */
rwlock_t s_cred_lock;
/* Root Info */ /* Root Info */
struct timespec s_record_time; struct timespec s_record_time;
...@@ -139,7 +142,7 @@ struct udf_sb_info { ...@@ -139,7 +142,7 @@ struct udf_sb_info {
__u16 s_udfrev; __u16 s_udfrev;
/* Miscellaneous flags */ /* Miscellaneous flags */
__u32 s_flags; unsigned long s_flags;
/* Encoding info */ /* Encoding info */
struct nls_table *s_nls_map; struct nls_table *s_nls_map;
...@@ -161,8 +164,19 @@ struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct udf_sb_info *sbi); ...@@ -161,8 +164,19 @@ struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct udf_sb_info *sbi);
int udf_compute_nr_groups(struct super_block *sb, u32 partition); int udf_compute_nr_groups(struct super_block *sb, u32 partition);
#define UDF_QUERY_FLAG(X,Y) ( UDF_SB(X)->s_flags & ( 1 << (Y) ) ) static inline int UDF_QUERY_FLAG(struct super_block *sb, int flag)
#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) ) ) return test_bit(flag, &UDF_SB(sb)->s_flags);
}
static inline void UDF_SET_FLAG(struct super_block *sb, int flag)
{
set_bit(flag, &UDF_SB(sb)->s_flags);
}
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 */ #endif /* __LINUX_UDF_SB_H */
...@@ -111,6 +111,8 @@ struct extent_position { ...@@ -111,6 +111,8 @@ struct extent_position {
}; };
/* super.c */ /* super.c */
__attribute__((format(printf, 3, 4)))
extern void udf_warning(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) static inline void udf_updated_lvid(struct super_block *sb)
{ {
...@@ -123,6 +125,7 @@ static inline void udf_updated_lvid(struct super_block *sb) ...@@ -123,6 +125,7 @@ static inline void udf_updated_lvid(struct super_block *sb)
sb->s_dirt = 1; sb->s_dirt = 1;
UDF_SB(sb)->s_lvid_dirty = 1; UDF_SB(sb)->s_lvid_dirty = 1;
} }
extern u64 lvid_get_unique_id(struct super_block *sb);
/* namei.c */ /* namei.c */
extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *, extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *,
...@@ -133,7 +136,6 @@ extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *, ...@@ -133,7 +136,6 @@ extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *,
extern long udf_ioctl(struct file *, unsigned int, unsigned long); extern long udf_ioctl(struct file *, unsigned int, unsigned long);
/* inode.c */ /* inode.c */
extern struct inode *udf_iget(struct super_block *, struct kernel_lb_addr *); extern struct inode *udf_iget(struct super_block *, struct kernel_lb_addr *);
extern int udf_sync_inode(struct inode *);
extern void udf_expand_file_adinicb(struct inode *, int, int *); 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_expand_dir_adinicb(struct inode *, int *, int *);
extern struct buffer_head *udf_bread(struct inode *, int, int, int *); extern struct buffer_head *udf_bread(struct inode *, int, int, int *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment