Commit 59345374 authored by Ingo Molnar's avatar Ingo Molnar Committed by Linus Torvalds

[PATCH] lockdep: annotate NTFS locking rules

NTFS uses lots of type-opaque objects which acquire their true identity
runtime - so the lock validator needs to be helped in a couple of places to
figure out object types.

Many thanks to Anton Altaparmakov for giving lots of explanations about NTFS
locking rules.

Has no effect on non-lockdep kernels.
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarAnton Altaparmakov <aia21@cantab.net>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent c6573c29
...@@ -367,6 +367,12 @@ static void ntfs_destroy_extent_inode(ntfs_inode *ni) ...@@ -367,6 +367,12 @@ static void ntfs_destroy_extent_inode(ntfs_inode *ni)
kmem_cache_free(ntfs_inode_cache, ni); kmem_cache_free(ntfs_inode_cache, ni);
} }
/*
* The attribute runlist lock has separate locking rules from the
* normal runlist lock, so split the two lock-classes:
*/
static struct lock_class_key attr_list_rl_lock_class;
/** /**
* __ntfs_init_inode - initialize ntfs specific part of an inode * __ntfs_init_inode - initialize ntfs specific part of an inode
* @sb: super block of mounted volume * @sb: super block of mounted volume
...@@ -394,6 +400,8 @@ void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni) ...@@ -394,6 +400,8 @@ void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni)
ni->attr_list_size = 0; ni->attr_list_size = 0;
ni->attr_list = NULL; ni->attr_list = NULL;
ntfs_init_runlist(&ni->attr_list_rl); ntfs_init_runlist(&ni->attr_list_rl);
lockdep_set_class(&ni->attr_list_rl.lock,
&attr_list_rl_lock_class);
ni->itype.index.bmp_ino = NULL; ni->itype.index.bmp_ino = NULL;
ni->itype.index.block_size = 0; ni->itype.index.block_size = 0;
ni->itype.index.vcn_size = 0; ni->itype.index.vcn_size = 0;
...@@ -405,6 +413,13 @@ void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni) ...@@ -405,6 +413,13 @@ void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni)
ni->ext.base_ntfs_ino = NULL; ni->ext.base_ntfs_ino = NULL;
} }
/*
* Extent inodes get MFT-mapped in a nested way, while the base inode
* is still mapped. Teach this nesting to the lock validator by creating
* a separate class for nested inode's mrec_lock's:
*/
static struct lock_class_key extent_inode_mrec_lock_key;
inline ntfs_inode *ntfs_new_extent_inode(struct super_block *sb, inline ntfs_inode *ntfs_new_extent_inode(struct super_block *sb,
unsigned long mft_no) unsigned long mft_no)
{ {
...@@ -413,6 +428,7 @@ inline ntfs_inode *ntfs_new_extent_inode(struct super_block *sb, ...@@ -413,6 +428,7 @@ inline ntfs_inode *ntfs_new_extent_inode(struct super_block *sb,
ntfs_debug("Entering."); ntfs_debug("Entering.");
if (likely(ni != NULL)) { if (likely(ni != NULL)) {
__ntfs_init_inode(sb, ni); __ntfs_init_inode(sb, ni);
lockdep_set_class(&ni->mrec_lock, &extent_inode_mrec_lock_key);
ni->mft_no = mft_no; ni->mft_no = mft_no;
ni->type = AT_UNUSED; ni->type = AT_UNUSED;
ni->name = NULL; ni->name = NULL;
...@@ -1722,6 +1738,15 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi) ...@@ -1722,6 +1738,15 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
return err; return err;
} }
/*
* The MFT inode has special locking, so teach the lock validator
* about this by splitting off the locking rules of the MFT from
* the locking rules of other inodes. The MFT inode can never be
* accessed from the VFS side (or even internally), only by the
* map_mft functions.
*/
static struct lock_class_key mft_ni_runlist_lock_key, mft_ni_mrec_lock_key;
/** /**
* ntfs_read_inode_mount - special read_inode for mount time use only * ntfs_read_inode_mount - special read_inode for mount time use only
* @vi: inode to read * @vi: inode to read
...@@ -2148,6 +2173,14 @@ int ntfs_read_inode_mount(struct inode *vi) ...@@ -2148,6 +2173,14 @@ int ntfs_read_inode_mount(struct inode *vi)
ntfs_attr_put_search_ctx(ctx); ntfs_attr_put_search_ctx(ctx);
ntfs_debug("Done."); ntfs_debug("Done.");
ntfs_free(m); ntfs_free(m);
/*
* Split the locking rules of the MFT inode from the
* locking rules of other inodes:
*/
lockdep_set_class(&ni->runlist.lock, &mft_ni_runlist_lock_key);
lockdep_set_class(&ni->mrec_lock, &mft_ni_mrec_lock_key);
return 0; return 0;
em_put_err_out: em_put_err_out:
......
...@@ -1724,6 +1724,14 @@ static BOOL load_and_init_upcase(ntfs_volume *vol) ...@@ -1724,6 +1724,14 @@ static BOOL load_and_init_upcase(ntfs_volume *vol)
return FALSE; return FALSE;
} }
/*
* The lcn and mft bitmap inodes are NTFS-internal inodes with
* their own special locking rules:
*/
static struct lock_class_key
lcnbmp_runlist_lock_key, lcnbmp_mrec_lock_key,
mftbmp_runlist_lock_key, mftbmp_mrec_lock_key;
/** /**
* load_system_files - open the system files using normal functions * load_system_files - open the system files using normal functions
* @vol: ntfs super block describing device whose system files to load * @vol: ntfs super block describing device whose system files to load
...@@ -1780,6 +1788,10 @@ static BOOL load_system_files(ntfs_volume *vol) ...@@ -1780,6 +1788,10 @@ static BOOL load_system_files(ntfs_volume *vol)
ntfs_error(sb, "Failed to load $MFT/$BITMAP attribute."); ntfs_error(sb, "Failed to load $MFT/$BITMAP attribute.");
goto iput_mirr_err_out; goto iput_mirr_err_out;
} }
lockdep_set_class(&NTFS_I(vol->mftbmp_ino)->runlist.lock,
&mftbmp_runlist_lock_key);
lockdep_set_class(&NTFS_I(vol->mftbmp_ino)->mrec_lock,
&mftbmp_mrec_lock_key);
/* Read upcase table and setup @vol->upcase and @vol->upcase_len. */ /* Read upcase table and setup @vol->upcase and @vol->upcase_len. */
if (!load_and_init_upcase(vol)) if (!load_and_init_upcase(vol))
goto iput_mftbmp_err_out; goto iput_mftbmp_err_out;
...@@ -1802,6 +1814,11 @@ static BOOL load_system_files(ntfs_volume *vol) ...@@ -1802,6 +1814,11 @@ static BOOL load_system_files(ntfs_volume *vol)
iput(vol->lcnbmp_ino); iput(vol->lcnbmp_ino);
goto bitmap_failed; goto bitmap_failed;
} }
lockdep_set_class(&NTFS_I(vol->lcnbmp_ino)->runlist.lock,
&lcnbmp_runlist_lock_key);
lockdep_set_class(&NTFS_I(vol->lcnbmp_ino)->mrec_lock,
&lcnbmp_mrec_lock_key);
NInoSetSparseDisabled(NTFS_I(vol->lcnbmp_ino)); NInoSetSparseDisabled(NTFS_I(vol->lcnbmp_ino));
if ((vol->nr_clusters + 7) >> 3 > i_size_read(vol->lcnbmp_ino)) { if ((vol->nr_clusters + 7) >> 3 > i_size_read(vol->lcnbmp_ino)) {
iput(vol->lcnbmp_ino); iput(vol->lcnbmp_ino);
...@@ -2743,6 +2760,17 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) ...@@ -2743,6 +2760,17 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
struct inode *tmp_ino; struct inode *tmp_ino;
int blocksize, result; int blocksize, result;
/*
* We do a pretty difficult piece of bootstrap by reading the
* MFT (and other metadata) from disk into memory. We'll only
* release this metadata during umount, so the locking patterns
* observed during bootstrap do not count. So turn off the
* observation of locking patterns (strictly for this context
* only) while mounting NTFS. [The validator is still active
* otherwise, even for this context: it will for example record
* lock class registrations.]
*/
lockdep_off();
ntfs_debug("Entering."); ntfs_debug("Entering.");
#ifndef NTFS_RW #ifndef NTFS_RW
sb->s_flags |= MS_RDONLY; sb->s_flags |= MS_RDONLY;
...@@ -2754,6 +2782,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) ...@@ -2754,6 +2782,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
if (!silent) if (!silent)
ntfs_error(sb, "Allocation of NTFS volume structure " ntfs_error(sb, "Allocation of NTFS volume structure "
"failed. Aborting mount..."); "failed. Aborting mount...");
lockdep_on();
return -ENOMEM; return -ENOMEM;
} }
/* Initialize ntfs_volume structure. */ /* Initialize ntfs_volume structure. */
...@@ -2940,6 +2969,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) ...@@ -2940,6 +2969,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
mutex_unlock(&ntfs_lock); mutex_unlock(&ntfs_lock);
sb->s_export_op = &ntfs_export_ops; sb->s_export_op = &ntfs_export_ops;
lock_kernel(); lock_kernel();
lockdep_on();
return 0; return 0;
} }
ntfs_error(sb, "Failed to allocate root directory."); ntfs_error(sb, "Failed to allocate root directory.");
...@@ -3059,6 +3089,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) ...@@ -3059,6 +3089,7 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent)
sb->s_fs_info = NULL; sb->s_fs_info = NULL;
kfree(vol); kfree(vol);
ntfs_debug("Failed, returning -EINVAL."); ntfs_debug("Failed, returning -EINVAL.");
lockdep_on();
return -EINVAL; return -EINVAL;
} }
......
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