From ed2ae6f69148dcf9da725364e17184f27ba04dc2 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 4 Nov 2010 20:08:04 -0700 Subject: fs/udf: Use vzalloc Signed-off-by: Joe Perches Signed-off-by: Jan Kara --- fs/udf/super.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'fs/udf') diff --git a/fs/udf/super.c b/fs/udf/super.c index 4a5c7c61836a..f99ff5dbd741 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -959,9 +959,9 @@ static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index) (sizeof(struct buffer_head *) * nr_groups); if (size <= PAGE_SIZE) - bitmap = kmalloc(size, GFP_KERNEL); + bitmap = kzalloc(size, GFP_KERNEL); else - bitmap = vmalloc(size); /* TODO: get rid of vmalloc */ + bitmap = vzalloc(size); /* TODO: get rid of vzalloc */ if (bitmap == NULL) { udf_error(sb, __func__, @@ -970,7 +970,6 @@ static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index) return NULL; } - memset(bitmap, 0x00, size); bitmap->s_block_bitmap = (struct buffer_head **)(bitmap + 1); bitmap->s_nr_groups = nr_groups; return bitmap; -- cgit v1.2.3 From fab3c8581fc49998f8d0d349b70813d9712fb405 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 10 Nov 2010 15:46:18 -0800 Subject: fs/udf: Add printf format/argument verification Add __attribute__((format... to udf_warning. All arguments matched formats, no other changes necessary. Signed-off-by: Joe Perches Signed-off-by: Jan Kara --- fs/udf/udfdecl.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'fs/udf') diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 6995ab1f4305..74d58c08ebac 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -111,6 +111,8 @@ struct extent_position { }; /* super.c */ + +__attribute__((format(printf, 3, 4))) extern void udf_warning(struct super_block *, const char *, const char *, ...); static inline void udf_updated_lvid(struct super_block *sb) { -- cgit v1.2.3 From f2a6cc1f146465e13f31d9163d542d1facf4e203 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 20 Oct 2010 17:25:59 +0200 Subject: udf: Convert UDF_SB(sb)->s_flags to use bitops Use atomic bitops to manipulate with sb flags to make manipulation safe without any locking. Signed-off-by: Jan Kara --- fs/udf/udf_sb.h | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'fs/udf') diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h index d113b72c2768..9f38a6ca4fd5 100644 --- a/fs/udf/udf_sb.h +++ b/fs/udf/udf_sb.h @@ -2,6 +2,7 @@ #define __LINUX_UDF_SB_H #include +#include /* Since UDF 2.01 is ISO 13346 based... */ #define UDF_SUPER_MAGIC 0x15013346 @@ -139,7 +140,7 @@ struct udf_sb_info { __u16 s_udfrev; /* Miscellaneous flags */ - __u32 s_flags; + unsigned long s_flags; /* Encoding info */ struct nls_table *s_nls_map; @@ -161,8 +162,19 @@ struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct udf_sb_info *sbi); int udf_compute_nr_groups(struct super_block *sb, u32 partition); -#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) ) ) +static inline int UDF_QUERY_FLAG(struct super_block *sb, int flag) +{ + 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 */ -- cgit v1.2.3 From 49521de119d326d04fb3736ab827e12e1de966d0 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 20 Oct 2010 17:42:44 +0200 Subject: udf: Remove BKL from udf_update_inode udf_update_inode() does not need BKL since on-disk inode modifications are protected by the buffer lock and reading of values of in-memory inode is safe without any lock. In some cases we can write inconsistent inode state to disk but in that case inode will be marked dirty and overwritten later. Also make unnecessarily global udf_sync_inode() static. Signed-off-by: Jan Kara --- fs/udf/inode.c | 13 +++---------- fs/udf/udfdecl.h | 1 - 2 files changed, 3 insertions(+), 11 deletions(-) (limited to 'fs/udf') diff --git a/fs/udf/inode.c b/fs/udf/inode.c index fc48f37aa2dd..9656907f4b81 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -51,6 +51,7 @@ MODULE_LICENSE("GPL"); static mode_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 int udf_sync_inode(struct inode *inode); static int udf_alloc_i_data(struct inode *inode, size_t size); static struct buffer_head *inode_getblk(struct inode *, sector_t, int *, sector_t *, int *); @@ -79,9 +80,7 @@ void udf_evict_inode(struct inode *inode) want_delete = 1; inode->i_size = 0; udf_truncate(inode); - lock_kernel(); udf_update_inode(inode, IS_SYNC(inode)); - unlock_kernel(); } invalidate_inode_buffers(inode); end_writeback(inode); @@ -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 ret; - - lock_kernel(); - ret = udf_update_inode(inode, wbc->sync_mode == WB_SYNC_ALL); - 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); } diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 74d58c08ebac..f25e57e8a777 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -135,7 +135,6 @@ extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *, extern long udf_ioctl(struct file *, unsigned int, unsigned long); /* inode.c */ 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 struct buffer_head *udf_expand_dir_adinicb(struct inode *, int *, int *); extern struct buffer_head *udf_bread(struct inode *, int, int, int *); -- cgit v1.2.3 From d664b6af609ecf5e7dcedf92f0bf188e3a29b3e0 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 20 Oct 2010 18:28:46 +0200 Subject: udf: Move handling of uniqueID into a helper function and protect it by a s_alloc_mutex uniqueID handling has been duplicated in three places. Move it into a common helper. Since we modify an LVID buffer with uniqueID update, we take sbi->s_alloc_mutex to protect agaist other modifications of the structure. Signed-off-by: Jan Kara --- fs/udf/ialloc.c | 21 ++++++--------------- fs/udf/namei.c | 51 +++++++++++++-------------------------------------- fs/udf/super.c | 27 +++++++++++++++++++++++++++ fs/udf/udfdecl.h | 1 + 4 files changed, 47 insertions(+), 53 deletions(-) (limited to 'fs/udf') diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c index 75d9304d0dc3..6fb7e0adcda0 100644 --- a/fs/udf/ialloc.c +++ b/fs/udf/ialloc.c @@ -92,28 +92,19 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err) return NULL; } - mutex_lock(&sbi->s_alloc_mutex); if (sbi->s_lvid_bh) { - struct logicalVolIntegrityDesc *lvid = - (struct logicalVolIntegrityDesc *) - sbi->s_lvid_bh->b_data; - struct logicalVolIntegrityDescImpUse *lvidiu = - udf_sb_lvidiu(sbi); - struct logicalVolHeaderDesc *lvhd; - uint64_t uniqueID; - lvhd = (struct logicalVolHeaderDesc *) - (lvid->logicalVolContentsUse); + struct logicalVolIntegrityDescImpUse *lvidiu; + + iinfo->i_unique = lvid_get_unique_id(sb); + mutex_lock(&sbi->s_alloc_mutex); + lvidiu = udf_sb_lvidiu(sbi); if (S_ISDIR(mode)) le32_add_cpu(&lvidiu->numDirs, 1); else 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); + mutex_unlock(&sbi->s_alloc_mutex); } - mutex_unlock(&sbi->s_alloc_mutex); inode_init_owner(inode, dir, mode); diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 6d8dc02baebb..701fcda18415 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -890,8 +890,8 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, int block; unsigned char *name = NULL; int namelen; - struct buffer_head *bh; struct udf_inode_info *iinfo; + struct super_block *sb = dir->i_sb; lock_kernel(); inode = udf_new_inode(dir, S_IFLNK | S_IRWXUGO, &err); @@ -912,7 +912,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, struct kernel_lb_addr eloc; uint32_t bsize; - block = udf_new_block(inode->i_sb, inode, + block = udf_new_block(sb, inode, iinfo->i_location.partitionReferenceNum, iinfo->i_location.logicalBlockNum, &err); if (!block) @@ -923,17 +923,17 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, eloc.logicalBlockNum = block; eloc.partitionReferenceNum = iinfo->i_location.partitionReferenceNum; - bsize = inode->i_sb->s_blocksize; + bsize = sb->s_blocksize; iinfo->i_lenExtents = bsize; udf_add_aext(inode, &epos, &eloc, bsize, 0); brelse(epos.bh); - block = udf_get_pblock(inode->i_sb, block, + block = udf_get_pblock(sb, block, iinfo->i_location.partitionReferenceNum, 0); - epos.bh = udf_tgetblk(inode->i_sb, block); + epos.bh = udf_tgetblk(sb, block); lock_buffer(epos.bh); - memset(epos.bh->b_data, 0x00, inode->i_sb->s_blocksize); + memset(epos.bh->b_data, 0x00, bsize); set_buffer_uptodate(epos.bh); unlock_buffer(epos.bh); mark_buffer_dirty_inode(epos.bh, inode); @@ -941,7 +941,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, } else ea = iinfo->i_ext.i_data + iinfo->i_lenEAttr; - eoffset = inode->i_sb->s_blocksize - udf_ext0_offset(inode); + eoffset = sb->s_blocksize - udf_ext0_offset(inode); pc = (struct pathComponent *)ea; if (*symname == '/') { @@ -981,7 +981,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, } if (pc->componentType == 5) { - namelen = udf_put_filename(inode->i_sb, compstart, name, + namelen = udf_put_filename(sb, compstart, name, symname - compstart); if (!namelen) goto out_no_entry; @@ -1015,23 +1015,11 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, 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.extLength = cpu_to_le32(sb->s_blocksize); cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location); - bh = UDF_SB(inode->i_sb)->s_lvid_bh; - if (bh) { - struct logicalVolIntegrityDesc *lvid = - (struct logicalVolIntegrityDesc *)bh->b_data; - struct logicalVolHeaderDesc *lvhd; - uint64_t uniqueID; - lvhd = (struct logicalVolHeaderDesc *) - lvid->logicalVolContentsUse; - uniqueID = le64_to_cpu(lvhd->uniqueID); + 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(bh); + cpu_to_le32(lvid_get_unique_id(sb)); } udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL); if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) @@ -1060,7 +1048,6 @@ static int udf_link(struct dentry *old_dentry, struct inode *dir, struct udf_fileident_bh fibh; struct fileIdentDesc cfi, *fi; int err; - struct buffer_head *bh; lock_kernel(); if (inode->i_nlink >= (256 << sizeof(inode->i_nlink)) - 1) { @@ -1075,21 +1062,9 @@ static int udf_link(struct dentry *old_dentry, struct inode *dir, } cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); cfi.icb.extLocation = cpu_to_lelb(UDF_I(inode)->i_location); - bh = UDF_SB(inode->i_sb)->s_lvid_bh; - if (bh) { - struct logicalVolIntegrityDesc *lvid = - (struct logicalVolIntegrityDesc *)bh->b_data; - struct logicalVolHeaderDesc *lvhd; - uint64_t uniqueID; - lvhd = (struct logicalVolHeaderDesc *) - (lvid->logicalVolContentsUse); - uniqueID = le64_to_cpu(lvhd->uniqueID); + 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(bh); + cpu_to_le32(lvid_get_unique_id(inode->i_sb)); } udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL); if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) diff --git a/fs/udf/super.c b/fs/udf/super.c index f99ff5dbd741..948e1aca0f34 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1823,6 +1823,33 @@ static void udf_close_lvid(struct super_block *sb) sbi->s_lvid_dirty = 0; } +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) { int i; diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index f25e57e8a777..eba48209f9f3 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -125,6 +125,7 @@ static inline void udf_updated_lvid(struct super_block *sb) sb->s_dirt = 1; UDF_SB(sb)->s_lvid_dirty = 1; } +extern u64 lvid_get_unique_id(struct super_block *sb); /* namei.c */ extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *, -- cgit v1.2.3 From 949f4a7c08bc4a050eae7aeeac3e6d019d1feafb Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 20 Oct 2010 18:49:20 +0200 Subject: udf: Protect all modifications of LVID with s_alloc_mutex udf_open_lvid() and udf_close_lvid() were modifying LVID without s_alloc_mutex. Since they can be called from remount, the modification could race with other filesystem modifications of LVID so protect them by s_alloc_mutex just to be sure. Signed-off-by: Jan Kara --- fs/udf/super.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'fs/udf') diff --git a/fs/udf/super.c b/fs/udf/super.c index 948e1aca0f34..e54960c0e960 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1773,6 +1773,8 @@ static void udf_open_lvid(struct super_block *sb) if (!bh) return; + + mutex_lock(&sbi->s_alloc_mutex); lvid = (struct logicalVolIntegrityDesc *)bh->b_data; lvidiu = udf_sb_lvidiu(sbi); @@ -1789,6 +1791,7 @@ static void udf_open_lvid(struct super_block *sb) lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); mark_buffer_dirty(bh); sbi->s_lvid_dirty = 0; + mutex_unlock(&sbi->s_alloc_mutex); } static void udf_close_lvid(struct super_block *sb) @@ -1801,6 +1804,7 @@ static void udf_close_lvid(struct super_block *sb) if (!bh) return; + mutex_lock(&sbi->s_alloc_mutex); lvid = (struct logicalVolIntegrityDesc *)bh->b_data; lvidiu = udf_sb_lvidiu(sbi); lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; @@ -1821,6 +1825,7 @@ static void udf_close_lvid(struct super_block *sb) lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); mark_buffer_dirty(bh); sbi->s_lvid_dirty = 0; + mutex_unlock(&sbi->s_alloc_mutex); } u64 lvid_get_unique_id(struct super_block *sb) -- cgit v1.2.3 From c03cad241af63445b751781a09faf08b3a5b77c1 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 20 Oct 2010 22:17:28 +0200 Subject: udf: Protect default inode credentials by rwlock Superblock carries credentials (uid, gid, etc.) which are used as default values in __udf_read_inode() when media does not provide these. These credentials can change during remount so we protect them by a rwlock so that each inode gets a consistent set of credentials. Signed-off-by: Jan Kara --- fs/udf/inode.c | 16 +++++++++------- fs/udf/super.c | 3 +++ fs/udf/udf_sb.h | 2 ++ 3 files changed, 14 insertions(+), 7 deletions(-) (limited to 'fs/udf') diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 9656907f4b81..fa3c1541151c 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1201,6 +1201,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) return; } + read_lock(&sbi->s_cred_lock); inode->i_uid = le32_to_cpu(fe->uid); if (inode->i_uid == -1 || UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_IGNORE) || @@ -1213,13 +1214,6 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_GID_SET)) 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 && sbi->s_fmode != UDF_INVALID_MODE) inode->i_mode = sbi->s_fmode; @@ -1229,6 +1223,14 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) else inode->i_mode = udf_convert_permissions(fe); 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) { inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) << diff --git a/fs/udf/super.c b/fs/udf/super.c index e54960c0e960..f06cc67cf864 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -568,12 +568,14 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options) return -EINVAL; lock_kernel(); + 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 (sbi->s_lvid_bh) { int write_rev = le16_to_cpu(udf_sb_lvidiu(sbi)->minUDFWriteRev); @@ -1960,6 +1962,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) 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); diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h index 9f38a6ca4fd5..4858c191242b 100644 --- a/fs/udf/udf_sb.h +++ b/fs/udf/udf_sb.h @@ -129,6 +129,8 @@ struct udf_sb_info { uid_t s_uid; mode_t s_fmode; mode_t s_dmode; + /* Lock protecting consistency of above permission settings */ + rwlock_t s_cred_lock; /* Root Info */ struct timespec s_record_time; -- cgit v1.2.3 From 0484b1cedc053cf88a046da5f08bc00747e533cb Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 20 Oct 2010 22:22:57 +0200 Subject: udf: Remove BKL from udf_put_super() and udf_remount_fs() udf_put_super() does not need BKL because the filesystem is shut down so there's nothing to race with. The credential changes in udf_remount_fs() and LVID changes are now protected by dedicated locks so we can remove BKL from this function as well. Signed-off-by: Jan Kara --- fs/udf/super.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'fs/udf') diff --git a/fs/udf/super.c b/fs/udf/super.c index f06cc67cf864..4cf6121ab41a 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -567,7 +567,6 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options) if (!udf_parse_options(options, &uopt, true)) return -EINVAL; - lock_kernel(); write_lock(&sbi->s_cred_lock); sbi->s_flags = uopt.flags; sbi->s_uid = uopt.uid; @@ -592,7 +591,6 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options) udf_open_lvid(sb); out_unlock: - unlock_kernel(); return error; } @@ -2132,8 +2130,6 @@ static void udf_put_super(struct super_block *sb) sbi = UDF_SB(sb); - lock_kernel(); - if (sbi->s_vat_inode) iput(sbi->s_vat_inode); if (sbi->s_partitions) @@ -2149,8 +2145,6 @@ static void udf_put_super(struct super_block *sb) kfree(sbi->s_partmaps); kfree(sb->s_fs_info); sb->s_fs_info = NULL; - - unlock_kernel(); } static int udf_sync_fs(struct super_block *sb, int wait) -- cgit v1.2.3 From 7abc2e45e48ca04206949682402d5d55bc64a16b Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 20 Oct 2010 22:32:02 +0200 Subject: udf: Call udf_add_free_space() for more blocks at once in udf_free_blocks() There's no need to call udf_add_free_space() for one block at a time. It saves us noticeable amount of work and yields different result from the original code only if the filesystem is corrupted and bitmap bit is already cleared. In such case counter of free blocks is probably wrong anyways so the change does not matter. Signed-off-by: Jan Kara --- fs/udf/balloc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'fs/udf') diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c index b608efaa4cee..306ee39ef2c3 100644 --- a/fs/udf/balloc.c +++ b/fs/udf/balloc.c @@ -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("byte=%2x\n", ((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); if (overflow) { block += count; -- cgit v1.2.3 From d1668fe390c1e84580575965684a8fa7e4626dee Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 20 Oct 2010 23:24:12 +0200 Subject: udf: Remove BKL from free space counting functions udf_count_free_bitmap() does not need BKL because bitmaps are in a fixed place on disk and so we can count set bits without serialization. udf_count_free_table() is now protected by s_alloc_mutex instead of BKL to get a consistent view of free space extents. Signed-off-by: Jan Kara --- fs/udf/super.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'fs/udf') diff --git a/fs/udf/super.c b/fs/udf/super.c index 4cf6121ab41a..d2ec9f31e843 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -2207,8 +2207,6 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb, uint16_t ident; struct spaceBitmapDesc *bm; - lock_kernel(); - loc.logicalBlockNum = bitmap->s_extPosition; loc.partitionReferenceNum = UDF_SB(sb)->s_partition; bh = udf_read_ptagged(sb, &loc, 0, &ident); @@ -2245,10 +2243,7 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb, } } brelse(bh); - out: - unlock_kernel(); - return accum; } @@ -2261,8 +2256,7 @@ static unsigned int udf_count_free_table(struct super_block *sb, int8_t etype; 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; @@ -2271,8 +2265,7 @@ static unsigned int udf_count_free_table(struct super_block *sb, accum += (elen >> table->i_sb->s_blocksize_bits); brelse(epos.bh); - - unlock_kernel(); + mutex_unlock(&UDF_SB(sb)->s_alloc_mutex); return accum; } -- cgit v1.2.3 From 4d0fb621d35007c19a396f2bb629e5aeaacef2d0 Mon Sep 17 00:00:00 2001 From: Alessio Igor Bogani Date: Tue, 16 Nov 2010 18:40:47 +0100 Subject: udf: Replace bkl with the UDF_I(inode)->i_data_sem for protect udf_inode_info struct Replace bkl with the UDF_I(inode)->i_data_sem rw semaphore in udf_release_file(), udf_symlink(), udf_symlink_filler(), udf_get_block(), udf_block_map(), and udf_setattr(). The rule now is that any operation on regular file's or symlink's extents (or generally allocation information including goal block) needs to hold i_data_sem. This work was supported by a hardware donation from the CE Linux Forum. Signed-off-by: Alessio Igor Bogani Signed-off-by: Jan Kara --- fs/udf/file.c | 4 ++-- fs/udf/inode.c | 19 ++++++++++--------- fs/udf/namei.c | 7 ++++--- fs/udf/super.c | 1 + fs/udf/symlink.c | 12 +++++++----- fs/udf/udf_i.h | 13 +++++++++++++ 6 files changed, 37 insertions(+), 19 deletions(-) (limited to 'fs/udf') diff --git a/fs/udf/file.c b/fs/udf/file.c index 66b9e7e7e4c5..df0c5561cc7e 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -204,10 +204,10 @@ static int udf_release_file(struct inode *inode, struct file *filp) { if (filp->f_mode & FMODE_WRITE) { mutex_lock(&inode->i_mutex); - lock_kernel(); + down_write(&UDF_I(inode)->i_data_sem); udf_discard_prealloc(inode); udf_truncate_tail_extent(inode); - unlock_kernel(); + up_write(&UDF_I(inode)->i_data_sem); mutex_unlock(&inode->i_mutex); } return 0; diff --git a/fs/udf/inode.c b/fs/udf/inode.c index fa3c1541151c..b2fe4d7f20eb 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -301,10 +301,9 @@ static int udf_get_block(struct inode *inode, sector_t block, err = -EIO; new = 0; bh = NULL; - - lock_kernel(); - iinfo = UDF_I(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++; @@ -323,7 +322,7 @@ static int udf_get_block(struct inode *inode, sector_t block, map_bh(bh_result, inode->i_sb, phys); abort: - unlock_kernel(); + up_write(&iinfo->i_data_sem); return err; } @@ -1021,16 +1020,16 @@ void udf_truncate(struct inode *inode) if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) return; - lock_kernel(); iinfo = UDF_I(inode); if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { + down_write(&iinfo->i_data_sem); 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 (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { inode->i_size = iinfo->i_lenAlloc; - unlock_kernel(); + up_write(&iinfo->i_data_sem); return; } else udf_truncate_extents(inode); @@ -1041,10 +1040,13 @@ void udf_truncate(struct inode *inode) offset - udf_file_entry_alloc_offset(inode)); iinfo->i_lenAlloc = inode->i_size; } + up_write(&iinfo->i_data_sem); } else { block_truncate_page(inode->i_mapping, inode->i_size, udf_get_block); + down_write(&iinfo->i_data_sem); udf_truncate_extents(inode); + up_write(&iinfo->i_data_sem); } inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb); @@ -1052,7 +1054,6 @@ void udf_truncate(struct inode *inode) udf_sync_inode(inode); else mark_inode_dirty(inode); - unlock_kernel(); } static void __udf_read_inode(struct inode *inode) @@ -2043,7 +2044,7 @@ long udf_block_map(struct inode *inode, sector_t block) struct extent_position epos = {}; int ret; - lock_kernel(); + down_read(&UDF_I(inode)->i_data_sem); if (inode_bmap(inode, block, &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) @@ -2051,7 +2052,7 @@ long udf_block_map(struct inode *inode, sector_t block) else ret = 0; - unlock_kernel(); + up_read(&UDF_I(inode)->i_data_sem); brelse(epos.bh); if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_VARCONV)) diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 701fcda18415..d5eb000ddddd 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -893,18 +893,18 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, struct udf_inode_info *iinfo; struct super_block *sb = dir->i_sb; - lock_kernel(); inode = udf_new_inode(dir, S_IFLNK | S_IRWXUGO, &err); if (!inode) goto out; + 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; } - iinfo = UDF_I(inode); inode->i_data.a_ops = &udf_symlink_aops; inode->i_op = &udf_symlink_inode_operations; @@ -1024,6 +1024,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL); if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) mark_inode_dirty(dir); + up_write(&iinfo->i_data_sem); if (fibh.sbh != fibh.ebh) brelse(fibh.ebh); brelse(fibh.sbh); @@ -1032,10 +1033,10 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, out: kfree(name); - unlock_kernel(); return err; out_no_entry: + up_write(&iinfo->i_data_sem); inode_dec_link_count(inode); iput(inode); goto out; diff --git a/fs/udf/super.c b/fs/udf/super.c index d2ec9f31e843..441b892cf85e 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -135,6 +135,7 @@ static struct inode *udf_alloc_inode(struct super_block *sb) ei->i_next_alloc_block = 0; ei->i_next_alloc_goal = 0; ei->i_strat4096 = 0; + init_rwsem(&ei->i_data_sem); return &ei->vfs_inode; } diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c index 16064787d2b7..b1d4488b0f14 100644 --- a/fs/udf/symlink.c +++ b/fs/udf/symlink.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include "udf_i.h" @@ -78,13 +77,16 @@ static int udf_symlink_filler(struct file *file, struct page *page) int err = -EIO; unsigned char *p = kmap(page); struct udf_inode_info *iinfo; + uint32_t pos; - lock_kernel(); 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, udf_block_map(inode, 0)); + bh = sb_bread(inode->i_sb, pos); if (!bh) goto out; @@ -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); 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); diff --git a/fs/udf/udf_i.h b/fs/udf/udf_i.h index e58d1de41073..d1bd31ea724e 100644 --- a/fs/udf/udf_i.h +++ b/fs/udf/udf_i.h @@ -1,6 +1,18 @@ #ifndef _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 timespec i_crtime; /* Physical address of inode */ @@ -21,6 +33,7 @@ struct udf_inode_info { struct long_ad *i_lad; __u8 *i_data; } i_ext; + struct rw_semaphore i_data_sem; struct inode vfs_inode; }; -- cgit v1.2.3 From 7db09be629033b79792a1bf18f505f5f15914395 Mon Sep 17 00:00:00 2001 From: Alessio Igor Bogani Date: Tue, 16 Nov 2010 18:40:48 +0100 Subject: udf: Use of s_alloc_mutex to serialize udf_relocate_blocks() execution This work was supported by a hardware donation from the CE Linux Forum. Signed-off-by: Alessio Igor Bogani Signed-off-by: Jan Kara --- fs/udf/partition.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'fs/udf') diff --git a/fs/udf/partition.c b/fs/udf/partition.c index 745eb209be0c..a71090ea0e07 100644 --- a/fs/udf/partition.c +++ b/fs/udf/partition.c @@ -25,6 +25,7 @@ #include #include #include +#include uint32_t udf_get_pblock(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset) @@ -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); 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 && @@ -175,8 +178,10 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block) break; } - if (!st) - return 1; + if (!st) { + ret = 1; + goto out; + } reallocationTableLen = le16_to_cpu(st->reallocationTableLen); @@ -207,14 +212,16 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block) ((old_block - map->s_partition_root) & (sdata->s_packet_len - 1)); - return 0; + 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)); - return 0; + ret = 0; + goto out; } else if (origLoc > packet) break; } @@ -251,20 +258,24 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block) st->mapEntry[k].mappedLocation) + ((old_block - map->s_partition_root) & (sdata->s_packet_len - 1)); - return 0; + ret = 0; + goto out; } - return 1; + ret = 1; + goto out; } /* if old_block */ } if (i == sbi->s_partitions) { /* outside of partitions */ /* 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, -- cgit v1.2.3 From 9db9f9e31d7661dff35a75ed01ff9fc0d6acdaf8 Mon Sep 17 00:00:00 2001 From: Alessio Igor Bogani Date: Tue, 16 Nov 2010 18:40:49 +0100 Subject: udf: Remove unnecessary bkl usages The udf_readdir(), udf_lookup(), udf_create(), udf_mknod(), udf_mkdir(), udf_rmdir(), udf_link(), udf_get_parent() and udf_unlink() seems already adequately protected by i_mutex held by VFS invoking calls. The udf_rename() instead should be already protected by lock_rename again by VFS. The udf_ioctl(), udf_fill_super() and udf_evict_inode() don't requires any further protection. This work was supported by a hardware donation from the CE Linux Forum. Signed-off-by: Alessio Igor Bogani Signed-off-by: Jan Kara --- fs/udf/dir.c | 5 ----- fs/udf/file.c | 4 ---- fs/udf/inode.c | 3 --- fs/udf/namei.c | 27 --------------------------- fs/udf/super.c | 9 +-------- 5 files changed, 1 insertion(+), 47 deletions(-) (limited to 'fs/udf') diff --git a/fs/udf/dir.c b/fs/udf/dir.c index 51552bf50225..eb8bfe2b89a5 100644 --- a/fs/udf/dir.c +++ b/fs/udf/dir.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include "udf_i.h" @@ -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; 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; } diff --git a/fs/udf/file.c b/fs/udf/file.c index df0c5561cc7e..4e3bbd81b57b 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -32,7 +32,6 @@ #include /* memset */ #include #include -#include #include #include #include @@ -149,8 +148,6 @@ long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) long old_block, new_block; int result = -EINVAL; - lock_kernel(); - if (file_permission(filp, MAY_READ) != 0) { udf_debug("no permission to access inode %lu\n", inode->i_ino); result = -EPERM; @@ -196,7 +193,6 @@ long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } out: - unlock_kernel(); return result; } diff --git a/fs/udf/inode.c b/fs/udf/inode.c index b2fe4d7f20eb..c6a2e782b97b 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -31,7 +31,6 @@ #include "udfdecl.h" #include -#include #include #include #include @@ -96,9 +95,7 @@ void udf_evict_inode(struct inode *inode) kfree(iinfo->i_ext.i_data); iinfo->i_ext.i_data = NULL; if (want_delete) { - lock_kernel(); udf_free_inode(inode); - unlock_kernel(); } } diff --git a/fs/udf/namei.c b/fs/udf/namei.c index d5eb000ddddd..26815a25379d 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -263,7 +262,6 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry, 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)) { @@ -275,7 +273,6 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry, }; inode = udf_iget(dir->i_sb, lb); if (!inode) { - unlock_kernel(); return ERR_PTR(-EACCES); } } else @@ -291,11 +288,9 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry, loc = lelb_to_cpu(cfi.icb.extLocation); inode = udf_iget(dir->i_sb, &loc); if (!inode) { - unlock_kernel(); return ERR_PTR(-EACCES); } } - unlock_kernel(); return d_splice_alias(inode, dentry); } @@ -562,10 +557,8 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode, int err; struct udf_inode_info *iinfo; - lock_kernel(); inode = udf_new_inode(dir, mode, &err); if (!inode) { - unlock_kernel(); return err; } @@ -583,7 +576,6 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode, inode->i_nlink--; mark_inode_dirty(inode); iput(inode); - unlock_kernel(); return err; } cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); @@ -596,7 +588,6 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode, if (fibh.sbh != fibh.ebh) brelse(fibh.ebh); brelse(fibh.sbh); - unlock_kernel(); d_instantiate(dentry, inode); return 0; @@ -614,7 +605,6 @@ static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode, if (!old_valid_dev(rdev)) return -EINVAL; - lock_kernel(); err = -EIO; inode = udf_new_inode(dir, mode, &err); if (!inode) @@ -627,7 +617,6 @@ static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode, inode->i_nlink--; mark_inode_dirty(inode); iput(inode); - unlock_kernel(); return err; } cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); @@ -646,7 +635,6 @@ static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode, err = 0; out: - unlock_kernel(); return err; } @@ -659,7 +647,6 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode) struct udf_inode_info *dinfo = UDF_I(dir); struct udf_inode_info *iinfo; - lock_kernel(); err = -EMLINK; if (dir->i_nlink >= (256 << sizeof(dir->i_nlink)) - 1) goto out; @@ -712,7 +699,6 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode) err = 0; out: - unlock_kernel(); return err; } @@ -794,7 +780,6 @@ static int udf_rmdir(struct inode *dir, struct dentry *dentry) struct kernel_lb_addr tloc; retval = -ENOENT; - lock_kernel(); fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi); if (!fi) goto out; @@ -826,7 +811,6 @@ end_rmdir: brelse(fibh.sbh); out: - unlock_kernel(); return retval; } @@ -840,7 +824,6 @@ static int udf_unlink(struct inode *dir, struct dentry *dentry) struct kernel_lb_addr tloc; retval = -ENOENT; - lock_kernel(); fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi); if (!fi) goto out; @@ -870,7 +853,6 @@ end_unlink: brelse(fibh.sbh); out: - unlock_kernel(); return retval; } @@ -1050,15 +1032,12 @@ static int udf_link(struct dentry *old_dentry, struct inode *dir, struct fileIdentDesc cfi, *fi; int err; - lock_kernel(); if (inode->i_nlink >= (256 << sizeof(inode->i_nlink)) - 1) { - unlock_kernel(); return -EMLINK; } fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err); if (!fi) { - unlock_kernel(); return err; } cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); @@ -1079,7 +1058,6 @@ static int udf_link(struct dentry *old_dentry, struct inode *dir, mark_inode_dirty(inode); ihold(inode); d_instantiate(dentry, inode); - unlock_kernel(); return 0; } @@ -1100,7 +1078,6 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry, struct kernel_lb_addr tloc; struct udf_inode_info *old_iinfo = UDF_I(old_inode); - lock_kernel(); ofi = udf_find_entry(old_dir, &old_dentry->d_name, &ofibh, &ocfi); if (ofi) { if (ofibh.sbh != ofibh.ebh) @@ -1224,7 +1201,6 @@ end_rename: brelse(nfibh.ebh); brelse(nfibh.sbh); } - unlock_kernel(); return retval; } @@ -1237,7 +1213,6 @@ static struct dentry *udf_get_parent(struct dentry *child) struct fileIdentDesc cfi; struct udf_fileident_bh fibh; - lock_kernel(); if (!udf_find_entry(child->d_inode, &dotdot, &fibh, &cfi)) goto out_unlock; @@ -1249,11 +1224,9 @@ static struct dentry *udf_get_parent(struct dentry *child) inode = udf_iget(child->d_inode->i_sb, &tloc); if (!inode) goto out_unlock; - unlock_kernel(); return d_obtain_alias(inode); out_unlock: - unlock_kernel(); return ERR_PTR(-EACCES); } diff --git a/fs/udf/super.c b/fs/udf/super.c index 441b892cf85e..536f89da4af2 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -48,7 +48,6 @@ #include #include #include -#include #include #include #include @@ -1911,8 +1910,6 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) struct kernel_lb_addr rootdir, fileset; struct udf_sb_info *sbi; - lock_kernel(); - uopt.flags = (1 << UDF_FLAG_USE_AD_IN_ICB) | (1 << UDF_FLAG_STRICT); uopt.uid = -1; uopt.gid = -1; @@ -1921,10 +1918,8 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) uopt.dmode = UDF_INVALID_MODE; sbi = kzalloc(sizeof(struct udf_sb_info), GFP_KERNEL); - if (!sbi) { - unlock_kernel(); + if (!sbi) return -ENOMEM; - } sb->s_fs_info = sbi; @@ -2071,7 +2066,6 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) goto error_out; } sb->s_maxbytes = MAX_LFS_FILESIZE; - unlock_kernel(); return 0; error_out: @@ -2092,7 +2086,6 @@ error_out: kfree(sbi); sb->s_fs_info = NULL; - unlock_kernel(); return -EINVAL; } -- cgit v1.2.3 From 8754a3f718f08dc21b3c5eccd044f612d4bc1ab1 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 16 Nov 2010 14:33:48 +0100 Subject: udf: Protect udf_file_aio_write from possible races Code doing conversion from INICB file to a normal file in udf_file_aio_write() is not protected by any lock from other code modifying the inode. Use i_alloc_sem for that. Reported-by: Alessio Igor Bogani Signed-off-by: Jan Kara --- fs/udf/file.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'fs/udf') diff --git a/fs/udf/file.c b/fs/udf/file.c index 4e3bbd81b57b..89c78486cbbe 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -113,6 +113,7 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, size_t count = iocb->ki_left; 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 (file->f_flags & O_APPEND) pos = inode->i_size; @@ -125,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); if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { udf_debug("udf_expand_adinicb: err=%d\n", err); + up_write(&iinfo->i_data_sem); return err; } } else { @@ -134,6 +136,7 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, iinfo->i_lenAlloc = inode->i_size; } } + up_write(&iinfo->i_data_sem); retval = generic_file_aio_write(iocb, iov, nr_segs, ppos); if (retval > 0) -- cgit v1.2.3 From 4651c5900e7a3c84d4b70412f8bbc40c1bcb50cf Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 25 Nov 2010 03:56:24 +0100 Subject: udf: Fix directory corruption after extent merging If udf_bread() called from udf_add_entry() managed to merge created extent to an already existing one (or if previous extents could be merged), the code truncating the last extent to proper size would just overwrite the freshly allocated extent with an extent that used to be in that place. This obviously results in a directory corruption. Fix the problem by properly reloading the last extent. Signed-off-by: Jan Kara --- fs/udf/namei.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'fs/udf') diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 26815a25379d..a2974f7563a2 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -471,15 +471,19 @@ add: 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) { - if (udf_next_aext(dir, &epos, &eloc, &elen, 1) == - (EXT_RECORDED_ALLOCATED >> 30)) { - block = eloc.logicalBlockNum + ((elen - 1) >> + /* Find the freshly allocated block */ + while (udf_next_aext(dir, &epos, &eloc, &elen, 1) == + (EXT_RECORDED_ALLOCATED >> 30)) + ; + block = eloc.logicalBlockNum + ((elen - 1) >> dir->i_sb->s_blocksize_bits); - } else - block++; - brelse(fibh->sbh); fibh->sbh = fibh->ebh; fi = (struct fileIdentDesc *)(fibh->sbh->b_data); -- cgit v1.2.3 From a4264b3f4049ae7aeeb0017f8158119e22fa354f Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 12 Dec 2010 23:18:15 +0100 Subject: UDF: Close small mem leak in udf_find_entry() Hi, There's a small memory leak in fs/udf/namei.c::udf_find_entry(). We dynamically allocate memory for 'fname' with kmalloc() and in most situations we free it before we leave the function, but there is one situation where we do not (but should). This patch closes the leak by jumping to the 'out_ok' label which does the correct cleanup rather than doing half the cleanup and returning directly. Signed-off-by: Jesper Juhl Signed-off-by: Jan Kara --- fs/udf/namei.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'fs/udf') diff --git a/fs/udf/namei.c b/fs/udf/namei.c index a2974f7563a2..2be0f9eb86d2 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -227,10 +227,8 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, } if ((cfi->fileCharacteristics & FID_FILE_CHAR_PARENT) && - isdotdot) { - brelse(epos.bh); - return fi; - } + isdotdot) + goto out_ok; if (!lfi) continue; -- cgit v1.2.3