On Wed, 2004-05-05 at 04:48, Alexander Kordecki wrote:
> Hi !
> 
> I have some JFS partitions on my HD and every time I activate EVMS on this
> machine I got the following kernel message:

Try this patch.  I investigated a similar problem recently, but I
haven't pushed the fix into the mainline kernel yet.

diff -Nurp linux-2.6.5/fs/jfs/jfs_metapage.c linux/fs/jfs/jfs_metapage.c
--- linux-2.6.5/fs/jfs/jfs_metapage.c   2004-04-16 09:51:16.000000000 -0500
+++ linux/fs/jfs/jfs_metapage.c 2004-04-18 21:55:23.714616048 -0500
@@ -228,31 +228,36 @@ struct metapage *__get_metapage(struct i
        else
                mapping = inode->i_mapping;
 
-       spin_lock(&meta_lock);
        hash_ptr = meta_hash(mapping, lblock);
+again:
+       spin_lock(&meta_lock);
        mp = search_hash(hash_ptr, mapping, lblock);
        if (mp) {
              page_found:
+               mp->count++;
+               lock_metapage(mp);
+               spin_unlock(&meta_lock);
+               if (test_bit(META_stale, &mp->flag)) {
+                       release_metapage(mp);
+                       goto again;
+               }
                if (test_bit(META_discard, &mp->flag)) {
                        if (!new) {
-                               spin_unlock(&meta_lock);
                                jfs_error(inode->i_sb,
                                          "__get_metapage: using a "
                                          "discarded metapage");
+                               release_metapage(mp);
                                return NULL;
                        }
                        clear_bit(META_discard, &mp->flag);
                }
-               mp->count++;
                jfs_info("__get_metapage: found 0x%p, in hash", mp);
                if (mp->logical_size != size) {
-                       spin_unlock(&meta_lock);
                        jfs_error(inode->i_sb,
                                  "__get_metapage: mp->logical_size != size");
+                       release_metapage(mp);
                        return NULL;
                }
-               lock_metapage(mp);
-               spin_unlock(&meta_lock);
        } else {
                l2bsize = inode->i_blkbits;
                l2BlocksPerPage = PAGE_CACHE_SHIFT - l2bsize;
@@ -451,46 +456,57 @@ void release_metapage(struct metapage * 
        if (--mp->count || atomic_read(&mp->nohomeok)) {
                unlock_metapage(mp);
                spin_unlock(&meta_lock);
-       } else {
-               remove_from_hash(mp, meta_hash(mp->mapping, mp->index));
-               spin_unlock(&meta_lock);
-
-               if (mp->page) {
-                       kunmap(mp->page);
-                       mp->data = 0;
-                       if (test_bit(META_dirty, &mp->flag))
-                               __write_metapage(mp);
-                       if (test_bit(META_sync, &mp->flag)) {
-                               sync_metapage(mp);
-                               clear_bit(META_sync, &mp->flag);
-                       }
-
-                       if (test_bit(META_discard, &mp->flag)) {
-                               lock_page(mp->page);
-                               block_invalidatepage(mp->page, 0);
-                               unlock_page(mp->page);
-                       }
+               return;
+       }
 
-                       page_cache_release(mp->page);
-                       INCREMENT(mpStat.pagefree);
+       if (mp->page) {
+               /* Releasing spinlock, we have to check mp->count later */
+               set_bit(META_stale, &mp->flag);
+               spin_unlock(&meta_lock);
+               kunmap(mp->page);
+               mp->data = 0;
+               if (test_bit(META_dirty, &mp->flag))
+                       __write_metapage(mp);
+               if (test_bit(META_sync, &mp->flag)) {
+                       sync_metapage(mp);
+                       clear_bit(META_sync, &mp->flag);
                }
 
-               if (mp->lsn) {
-                       /*
-                        * Remove metapage from logsynclist.
-                        */
-                       log = mp->log;
-                       LOGSYNC_LOCK(log);
-                       mp->log = 0;
-                       mp->lsn = 0;
-                       mp->clsn = 0;
-                       log->count--;
-                       list_del(&mp->synclist);
-                       LOGSYNC_UNLOCK(log);
+               if (test_bit(META_discard, &mp->flag)) {
+                       lock_page(mp->page);
+                       block_invalidatepage(mp->page, 0);
+                       unlock_page(mp->page);
                }
 
-               free_metapage(mp);
+               page_cache_release(mp->page);
+               mp->page = NULL;
+               INCREMENT(mpStat.pagefree);
+               spin_lock(&meta_lock);
+       }
+
+       if (mp->lsn) {
+               /*
+                * Remove metapage from logsynclist.
+                */
+               log = mp->log;
+               LOGSYNC_LOCK(log);
+               mp->log = 0;
+               mp->lsn = 0;
+               mp->clsn = 0;
+               log->count--;
+               list_del(&mp->synclist);
+               LOGSYNC_UNLOCK(log);
        }
+       if (mp->count) {
+               /* Someone else is trying to get this metpage */
+               unlock_metapage(mp);
+               spin_unlock(&meta_lock);
+               return;
+       }
+       remove_from_hash(mp, meta_hash(mp->mapping, mp->index));
+       spin_unlock(&meta_lock);
+
+       free_metapage(mp);
 }
 
 void __invalidate_metapages(struct inode *ip, s64 addr, int len)
@@ -510,9 +526,20 @@ void __invalidate_metapages(struct inode
        for (lblock = addr; lblock < addr + len;
             lblock += 1 << l2BlocksPerPage) {
                hash_ptr = meta_hash(mapping, lblock);
+again:
                spin_lock(&meta_lock);
                mp = search_hash(hash_ptr, mapping, lblock);
                if (mp) {
+                       if (test_bit(META_stale, &mp->flag)) {
+                               /* Racing with release_metapage */
+                               mp->count++;
+                               lock_metapage(mp);
+                               spin_unlock(&meta_lock);
+                               /* racing release_metapage should be done now */
+                               release_metapage(mp);
+                               goto again;
+                       }
+
                        set_bit(META_discard, &mp->flag);
                        spin_unlock(&meta_lock);
                } else {
diff -Nurp linux-2.6.5/fs/jfs/jfs_metapage.h linux/fs/jfs/jfs_metapage.h
--- linux-2.6.5/fs/jfs/jfs_metapage.h   2004-04-16 10:05:50.000000000 -0500
+++ linux/fs/jfs/jfs_metapage.h 2004-04-16 10:06:25.000000000 -0500
@@ -64,6 +64,7 @@ struct metapage {
 #define META_sync      4
 #define META_discard   5
 #define META_forced    6
+#define META_stale     7
 
 #define mark_metapage_dirty(mp) set_bit(META_dirty, &(mp)->flag)
 

-- 
David Kleikamp
IBM Linux Technology Center

_______________________________________________
Jfs-discussion mailing list
[EMAIL PROTECTED]
http://www-124.ibm.com/developerworks/oss/mailman/listinfo/jfs-discussion

Reply via email to