diff options
Diffstat (limited to 'fs/jfs')
-rw-r--r-- | fs/jfs/inode.c | 31 | ||||
-rw-r--r-- | fs/jfs/jfs_dmap.c | 12 | ||||
-rw-r--r-- | fs/jfs/jfs_imap.c | 14 | ||||
-rw-r--r-- | fs/jfs/jfs_incore.h | 1 | ||||
-rw-r--r-- | fs/jfs/jfs_logmgr.c | 71 | ||||
-rw-r--r-- | fs/jfs/jfs_logmgr.h | 5 | ||||
-rw-r--r-- | fs/jfs/jfs_metapage.c | 908 | ||||
-rw-r--r-- | fs/jfs/jfs_metapage.h | 80 | ||||
-rw-r--r-- | fs/jfs/jfs_mount.c | 5 | ||||
-rw-r--r-- | fs/jfs/jfs_txnmgr.c | 89 | ||||
-rw-r--r-- | fs/jfs/jfs_umount.c | 16 | ||||
-rw-r--r-- | fs/jfs/resize.c | 3 | ||||
-rw-r--r-- | fs/jfs/super.c | 33 |
13 files changed, 806 insertions, 462 deletions
diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index 7bc906677b0d..6c04f5eda135 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c | |||
@@ -175,31 +175,22 @@ jfs_get_blocks(struct inode *ip, sector_t lblock, unsigned long max_blocks, | |||
175 | { | 175 | { |
176 | s64 lblock64 = lblock; | 176 | s64 lblock64 = lblock; |
177 | int rc = 0; | 177 | int rc = 0; |
178 | int take_locks; | ||
179 | xad_t xad; | 178 | xad_t xad; |
180 | s64 xaddr; | 179 | s64 xaddr; |
181 | int xflag; | 180 | int xflag; |
182 | s32 xlen; | 181 | s32 xlen; |
183 | 182 | ||
184 | /* | 183 | /* |
185 | * If this is a special inode (imap, dmap) | ||
186 | * the lock should already be taken | ||
187 | */ | ||
188 | take_locks = (JFS_IP(ip)->fileset != AGGREGATE_I); | ||
189 | |||
190 | /* | ||
191 | * Take appropriate lock on inode | 184 | * Take appropriate lock on inode |
192 | */ | 185 | */ |
193 | if (take_locks) { | 186 | if (create) |
194 | if (create) | 187 | IWRITE_LOCK(ip); |
195 | IWRITE_LOCK(ip); | 188 | else |
196 | else | 189 | IREAD_LOCK(ip); |
197 | IREAD_LOCK(ip); | ||
198 | } | ||
199 | 190 | ||
200 | if (((lblock64 << ip->i_sb->s_blocksize_bits) < ip->i_size) && | 191 | if (((lblock64 << ip->i_sb->s_blocksize_bits) < ip->i_size) && |
201 | (xtLookup(ip, lblock64, max_blocks, &xflag, &xaddr, &xlen, 0) | 192 | (!xtLookup(ip, lblock64, max_blocks, &xflag, &xaddr, &xlen, 0)) && |
202 | == 0) && xlen) { | 193 | xlen) { |
203 | if (xflag & XAD_NOTRECORDED) { | 194 | if (xflag & XAD_NOTRECORDED) { |
204 | if (!create) | 195 | if (!create) |
205 | /* | 196 | /* |
@@ -258,12 +249,10 @@ jfs_get_blocks(struct inode *ip, sector_t lblock, unsigned long max_blocks, | |||
258 | /* | 249 | /* |
259 | * Release lock on inode | 250 | * Release lock on inode |
260 | */ | 251 | */ |
261 | if (take_locks) { | 252 | if (create) |
262 | if (create) | 253 | IWRITE_UNLOCK(ip); |
263 | IWRITE_UNLOCK(ip); | 254 | else |
264 | else | 255 | IREAD_UNLOCK(ip); |
265 | IREAD_UNLOCK(ip); | ||
266 | } | ||
267 | return rc; | 256 | return rc; |
268 | } | 257 | } |
269 | 258 | ||
diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index d86e467c6e42..69007fd546ef 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c | |||
@@ -471,6 +471,7 @@ dbUpdatePMap(struct inode *ipbmap, | |||
471 | struct metapage *mp; | 471 | struct metapage *mp; |
472 | struct jfs_log *log; | 472 | struct jfs_log *log; |
473 | int lsn, difft, diffp; | 473 | int lsn, difft, diffp; |
474 | unsigned long flags; | ||
474 | 475 | ||
475 | /* the blocks better be within the mapsize. */ | 476 | /* the blocks better be within the mapsize. */ |
476 | if (blkno + nblocks > bmp->db_mapsize) { | 477 | if (blkno + nblocks > bmp->db_mapsize) { |
@@ -504,6 +505,7 @@ dbUpdatePMap(struct inode *ipbmap, | |||
504 | 0); | 505 | 0); |
505 | if (mp == NULL) | 506 | if (mp == NULL) |
506 | return -EIO; | 507 | return -EIO; |
508 | metapage_wait_for_io(mp); | ||
507 | } | 509 | } |
508 | dp = (struct dmap *) mp->data; | 510 | dp = (struct dmap *) mp->data; |
509 | 511 | ||
@@ -578,34 +580,32 @@ dbUpdatePMap(struct inode *ipbmap, | |||
578 | if (mp->lsn != 0) { | 580 | if (mp->lsn != 0) { |
579 | /* inherit older/smaller lsn */ | 581 | /* inherit older/smaller lsn */ |
580 | logdiff(diffp, mp->lsn, log); | 582 | logdiff(diffp, mp->lsn, log); |
583 | LOGSYNC_LOCK(log, flags); | ||
581 | if (difft < diffp) { | 584 | if (difft < diffp) { |
582 | mp->lsn = lsn; | 585 | mp->lsn = lsn; |
583 | 586 | ||
584 | /* move bp after tblock in logsync list */ | 587 | /* move bp after tblock in logsync list */ |
585 | LOGSYNC_LOCK(log); | ||
586 | list_move(&mp->synclist, &tblk->synclist); | 588 | list_move(&mp->synclist, &tblk->synclist); |
587 | LOGSYNC_UNLOCK(log); | ||
588 | } | 589 | } |
589 | 590 | ||
590 | /* inherit younger/larger clsn */ | 591 | /* inherit younger/larger clsn */ |
591 | LOGSYNC_LOCK(log); | ||
592 | logdiff(difft, tblk->clsn, log); | 592 | logdiff(difft, tblk->clsn, log); |
593 | logdiff(diffp, mp->clsn, log); | 593 | logdiff(diffp, mp->clsn, log); |
594 | if (difft > diffp) | 594 | if (difft > diffp) |
595 | mp->clsn = tblk->clsn; | 595 | mp->clsn = tblk->clsn; |
596 | LOGSYNC_UNLOCK(log); | 596 | LOGSYNC_UNLOCK(log, flags); |
597 | } else { | 597 | } else { |
598 | mp->log = log; | 598 | mp->log = log; |
599 | mp->lsn = lsn; | 599 | mp->lsn = lsn; |
600 | 600 | ||
601 | /* insert bp after tblock in logsync list */ | 601 | /* insert bp after tblock in logsync list */ |
602 | LOGSYNC_LOCK(log); | 602 | LOGSYNC_LOCK(log, flags); |
603 | 603 | ||
604 | log->count++; | 604 | log->count++; |
605 | list_add(&mp->synclist, &tblk->synclist); | 605 | list_add(&mp->synclist, &tblk->synclist); |
606 | 606 | ||
607 | mp->clsn = tblk->clsn; | 607 | mp->clsn = tblk->clsn; |
608 | LOGSYNC_UNLOCK(log); | 608 | LOGSYNC_UNLOCK(log, flags); |
609 | } | 609 | } |
610 | } | 610 | } |
611 | 611 | ||
diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c index 6a0aa7e2cbef..7acff2ce3c80 100644 --- a/fs/jfs/jfs_imap.c +++ b/fs/jfs/jfs_imap.c | |||
@@ -502,7 +502,7 @@ struct inode *diReadSpecial(struct super_block *sb, ino_t inum, int secondary) | |||
502 | 502 | ||
503 | } | 503 | } |
504 | 504 | ||
505 | ip->i_mapping->a_ops = &jfs_aops; | 505 | ip->i_mapping->a_ops = &jfs_metapage_aops; |
506 | mapping_set_gfp_mask(ip->i_mapping, GFP_NOFS); | 506 | mapping_set_gfp_mask(ip->i_mapping, GFP_NOFS); |
507 | 507 | ||
508 | /* Allocations to metadata inodes should not affect quotas */ | 508 | /* Allocations to metadata inodes should not affect quotas */ |
@@ -2791,6 +2791,7 @@ diUpdatePMap(struct inode *ipimap, | |||
2791 | u32 mask; | 2791 | u32 mask; |
2792 | struct jfs_log *log; | 2792 | struct jfs_log *log; |
2793 | int lsn, difft, diffp; | 2793 | int lsn, difft, diffp; |
2794 | unsigned long flags; | ||
2794 | 2795 | ||
2795 | imap = JFS_IP(ipimap)->i_imap; | 2796 | imap = JFS_IP(ipimap)->i_imap; |
2796 | /* get the iag number containing the inode */ | 2797 | /* get the iag number containing the inode */ |
@@ -2807,6 +2808,7 @@ diUpdatePMap(struct inode *ipimap, | |||
2807 | IREAD_UNLOCK(ipimap); | 2808 | IREAD_UNLOCK(ipimap); |
2808 | if (rc) | 2809 | if (rc) |
2809 | return (rc); | 2810 | return (rc); |
2811 | metapage_wait_for_io(mp); | ||
2810 | iagp = (struct iag *) mp->data; | 2812 | iagp = (struct iag *) mp->data; |
2811 | /* get the inode number and extent number of the inode within | 2813 | /* get the inode number and extent number of the inode within |
2812 | * the iag and the inode number within the extent. | 2814 | * the iag and the inode number within the extent. |
@@ -2870,30 +2872,28 @@ diUpdatePMap(struct inode *ipimap, | |||
2870 | /* inherit older/smaller lsn */ | 2872 | /* inherit older/smaller lsn */ |
2871 | logdiff(difft, lsn, log); | 2873 | logdiff(difft, lsn, log); |
2872 | logdiff(diffp, mp->lsn, log); | 2874 | logdiff(diffp, mp->lsn, log); |
2875 | LOGSYNC_LOCK(log, flags); | ||
2873 | if (difft < diffp) { | 2876 | if (difft < diffp) { |
2874 | mp->lsn = lsn; | 2877 | mp->lsn = lsn; |
2875 | /* move mp after tblock in logsync list */ | 2878 | /* move mp after tblock in logsync list */ |
2876 | LOGSYNC_LOCK(log); | ||
2877 | list_move(&mp->synclist, &tblk->synclist); | 2879 | list_move(&mp->synclist, &tblk->synclist); |
2878 | LOGSYNC_UNLOCK(log); | ||
2879 | } | 2880 | } |
2880 | /* inherit younger/larger clsn */ | 2881 | /* inherit younger/larger clsn */ |
2881 | LOGSYNC_LOCK(log); | ||
2882 | assert(mp->clsn); | 2882 | assert(mp->clsn); |
2883 | logdiff(difft, tblk->clsn, log); | 2883 | logdiff(difft, tblk->clsn, log); |
2884 | logdiff(diffp, mp->clsn, log); | 2884 | logdiff(diffp, mp->clsn, log); |
2885 | if (difft > diffp) | 2885 | if (difft > diffp) |
2886 | mp->clsn = tblk->clsn; | 2886 | mp->clsn = tblk->clsn; |
2887 | LOGSYNC_UNLOCK(log); | 2887 | LOGSYNC_UNLOCK(log, flags); |
2888 | } else { | 2888 | } else { |
2889 | mp->log = log; | 2889 | mp->log = log; |
2890 | mp->lsn = lsn; | 2890 | mp->lsn = lsn; |
2891 | /* insert mp after tblock in logsync list */ | 2891 | /* insert mp after tblock in logsync list */ |
2892 | LOGSYNC_LOCK(log); | 2892 | LOGSYNC_LOCK(log, flags); |
2893 | log->count++; | 2893 | log->count++; |
2894 | list_add(&mp->synclist, &tblk->synclist); | 2894 | list_add(&mp->synclist, &tblk->synclist); |
2895 | mp->clsn = tblk->clsn; | 2895 | mp->clsn = tblk->clsn; |
2896 | LOGSYNC_UNLOCK(log); | 2896 | LOGSYNC_UNLOCK(log, flags); |
2897 | } | 2897 | } |
2898 | write_metapage(mp); | 2898 | write_metapage(mp); |
2899 | return (0); | 2899 | return (0); |
diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h index ebd77c1bed66..c0fd7b3eadc6 100644 --- a/fs/jfs/jfs_incore.h +++ b/fs/jfs/jfs_incore.h | |||
@@ -165,6 +165,7 @@ struct jfs_sb_info { | |||
165 | /* Formerly in ipbmap */ | 165 | /* Formerly in ipbmap */ |
166 | struct bmap *bmap; /* incore bmap descriptor */ | 166 | struct bmap *bmap; /* incore bmap descriptor */ |
167 | struct nls_table *nls_tab; /* current codepage */ | 167 | struct nls_table *nls_tab; /* current codepage */ |
168 | struct inode *direct_inode; /* metadata inode */ | ||
168 | uint state; /* mount/recovery state */ | 169 | uint state; /* mount/recovery state */ |
169 | unsigned long flag; /* mount time flags */ | 170 | unsigned long flag; /* mount time flags */ |
170 | uint p_state; /* state prior to going no integrity */ | 171 | uint p_state; /* state prior to going no integrity */ |
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index e0f867ddfd10..cfcdad3459dd 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c | |||
@@ -234,6 +234,7 @@ int lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, | |||
234 | int lsn; | 234 | int lsn; |
235 | int diffp, difft; | 235 | int diffp, difft; |
236 | struct metapage *mp = NULL; | 236 | struct metapage *mp = NULL; |
237 | unsigned long flags; | ||
237 | 238 | ||
238 | jfs_info("lmLog: log:0x%p tblk:0x%p, lrd:0x%p tlck:0x%p", | 239 | jfs_info("lmLog: log:0x%p tblk:0x%p, lrd:0x%p tlck:0x%p", |
239 | log, tblk, lrd, tlck); | 240 | log, tblk, lrd, tlck); |
@@ -254,7 +255,7 @@ int lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, | |||
254 | */ | 255 | */ |
255 | lsn = log->lsn; | 256 | lsn = log->lsn; |
256 | 257 | ||
257 | LOGSYNC_LOCK(log); | 258 | LOGSYNC_LOCK(log, flags); |
258 | 259 | ||
259 | /* | 260 | /* |
260 | * initialize page lsn if first log write of the page | 261 | * initialize page lsn if first log write of the page |
@@ -310,7 +311,7 @@ int lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, | |||
310 | } | 311 | } |
311 | } | 312 | } |
312 | 313 | ||
313 | LOGSYNC_UNLOCK(log); | 314 | LOGSYNC_UNLOCK(log, flags); |
314 | 315 | ||
315 | /* | 316 | /* |
316 | * write the log record | 317 | * write the log record |
@@ -334,7 +335,6 @@ int lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, | |||
334 | return lsn; | 335 | return lsn; |
335 | } | 336 | } |
336 | 337 | ||
337 | |||
338 | /* | 338 | /* |
339 | * NAME: lmWriteRecord() | 339 | * NAME: lmWriteRecord() |
340 | * | 340 | * |
@@ -945,6 +945,15 @@ static int lmLogSync(struct jfs_log * log, int nosyncwait) | |||
945 | struct lrd lrd; | 945 | struct lrd lrd; |
946 | int lsn; | 946 | int lsn; |
947 | struct logsyncblk *lp; | 947 | struct logsyncblk *lp; |
948 | struct jfs_sb_info *sbi; | ||
949 | unsigned long flags; | ||
950 | |||
951 | /* push dirty metapages out to disk */ | ||
952 | list_for_each_entry(sbi, &log->sb_list, log_list) { | ||
953 | filemap_flush(sbi->ipbmap->i_mapping); | ||
954 | filemap_flush(sbi->ipimap->i_mapping); | ||
955 | filemap_flush(sbi->direct_inode->i_mapping); | ||
956 | } | ||
948 | 957 | ||
949 | /* | 958 | /* |
950 | * forward syncpt | 959 | * forward syncpt |
@@ -954,10 +963,7 @@ static int lmLogSync(struct jfs_log * log, int nosyncwait) | |||
954 | */ | 963 | */ |
955 | 964 | ||
956 | if (log->sync == log->syncpt) { | 965 | if (log->sync == log->syncpt) { |
957 | LOGSYNC_LOCK(log); | 966 | LOGSYNC_LOCK(log, flags); |
958 | /* ToDo: push dirty metapages out to disk */ | ||
959 | // bmLogSync(log); | ||
960 | |||
961 | if (list_empty(&log->synclist)) | 967 | if (list_empty(&log->synclist)) |
962 | log->sync = log->lsn; | 968 | log->sync = log->lsn; |
963 | else { | 969 | else { |
@@ -965,7 +971,7 @@ static int lmLogSync(struct jfs_log * log, int nosyncwait) | |||
965 | struct logsyncblk, synclist); | 971 | struct logsyncblk, synclist); |
966 | log->sync = lp->lsn; | 972 | log->sync = lp->lsn; |
967 | } | 973 | } |
968 | LOGSYNC_UNLOCK(log); | 974 | LOGSYNC_UNLOCK(log, flags); |
969 | 975 | ||
970 | } | 976 | } |
971 | 977 | ||
@@ -974,27 +980,6 @@ static int lmLogSync(struct jfs_log * log, int nosyncwait) | |||
974 | * reset syncpt = sync | 980 | * reset syncpt = sync |
975 | */ | 981 | */ |
976 | if (log->sync != log->syncpt) { | 982 | if (log->sync != log->syncpt) { |
977 | struct jfs_sb_info *sbi; | ||
978 | |||
979 | /* | ||
980 | * We need to make sure all of the "written" metapages | ||
981 | * actually make it to disk | ||
982 | */ | ||
983 | list_for_each_entry(sbi, &log->sb_list, log_list) { | ||
984 | if (sbi->flag & JFS_NOINTEGRITY) | ||
985 | continue; | ||
986 | filemap_fdatawrite(sbi->ipbmap->i_mapping); | ||
987 | filemap_fdatawrite(sbi->ipimap->i_mapping); | ||
988 | filemap_fdatawrite(sbi->sb->s_bdev->bd_inode->i_mapping); | ||
989 | } | ||
990 | list_for_each_entry(sbi, &log->sb_list, log_list) { | ||
991 | if (sbi->flag & JFS_NOINTEGRITY) | ||
992 | continue; | ||
993 | filemap_fdatawait(sbi->ipbmap->i_mapping); | ||
994 | filemap_fdatawait(sbi->ipimap->i_mapping); | ||
995 | filemap_fdatawait(sbi->sb->s_bdev->bd_inode->i_mapping); | ||
996 | } | ||
997 | |||
998 | lrd.logtid = 0; | 983 | lrd.logtid = 0; |
999 | lrd.backchain = 0; | 984 | lrd.backchain = 0; |
1000 | lrd.type = cpu_to_le16(LOG_SYNCPT); | 985 | lrd.type = cpu_to_le16(LOG_SYNCPT); |
@@ -1547,6 +1532,7 @@ void jfs_flush_journal(struct jfs_log *log, int wait) | |||
1547 | { | 1532 | { |
1548 | int i; | 1533 | int i; |
1549 | struct tblock *target = NULL; | 1534 | struct tblock *target = NULL; |
1535 | struct jfs_sb_info *sbi; | ||
1550 | 1536 | ||
1551 | /* jfs_write_inode may call us during read-only mount */ | 1537 | /* jfs_write_inode may call us during read-only mount */ |
1552 | if (!log) | 1538 | if (!log) |
@@ -1608,12 +1594,18 @@ void jfs_flush_journal(struct jfs_log *log, int wait) | |||
1608 | if (wait < 2) | 1594 | if (wait < 2) |
1609 | return; | 1595 | return; |
1610 | 1596 | ||
1597 | list_for_each_entry(sbi, &log->sb_list, log_list) { | ||
1598 | filemap_fdatawrite(sbi->ipbmap->i_mapping); | ||
1599 | filemap_fdatawrite(sbi->ipimap->i_mapping); | ||
1600 | filemap_fdatawrite(sbi->direct_inode->i_mapping); | ||
1601 | } | ||
1602 | |||
1611 | /* | 1603 | /* |
1612 | * If there was recent activity, we may need to wait | 1604 | * If there was recent activity, we may need to wait |
1613 | * for the lazycommit thread to catch up | 1605 | * for the lazycommit thread to catch up |
1614 | */ | 1606 | */ |
1615 | if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist)) { | 1607 | if ((!list_empty(&log->cqueue)) || !list_empty(&log->synclist)) { |
1616 | for (i = 0; i < 800; i++) { /* Too much? */ | 1608 | for (i = 0; i < 200; i++) { /* Too much? */ |
1617 | msleep(250); | 1609 | msleep(250); |
1618 | if (list_empty(&log->cqueue) && | 1610 | if (list_empty(&log->cqueue) && |
1619 | list_empty(&log->synclist)) | 1611 | list_empty(&log->synclist)) |
@@ -1621,7 +1613,24 @@ void jfs_flush_journal(struct jfs_log *log, int wait) | |||
1621 | } | 1613 | } |
1622 | } | 1614 | } |
1623 | assert(list_empty(&log->cqueue)); | 1615 | assert(list_empty(&log->cqueue)); |
1624 | assert(list_empty(&log->synclist)); | 1616 | if (!list_empty(&log->synclist)) { |
1617 | struct logsyncblk *lp; | ||
1618 | |||
1619 | list_for_each_entry(lp, &log->synclist, synclist) { | ||
1620 | if (lp->xflag & COMMIT_PAGE) { | ||
1621 | struct metapage *mp = (struct metapage *)lp; | ||
1622 | dump_mem("orphan metapage", lp, | ||
1623 | sizeof(struct metapage)); | ||
1624 | dump_mem("page", mp->page, sizeof(struct page)); | ||
1625 | } | ||
1626 | else | ||
1627 | dump_mem("orphan tblock", lp, | ||
1628 | sizeof(struct tblock)); | ||
1629 | } | ||
1630 | // current->state = TASK_INTERRUPTIBLE; | ||
1631 | // schedule(); | ||
1632 | } | ||
1633 | //assert(list_empty(&log->synclist)); | ||
1625 | clear_bit(log_FLUSH, &log->flag); | 1634 | clear_bit(log_FLUSH, &log->flag); |
1626 | } | 1635 | } |
1627 | 1636 | ||
diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h index f67146684b7f..f4c121098d4f 100644 --- a/fs/jfs/jfs_logmgr.h +++ b/fs/jfs/jfs_logmgr.h | |||
@@ -490,8 +490,9 @@ struct logsyncblk { | |||
490 | */ | 490 | */ |
491 | 491 | ||
492 | #define LOGSYNC_LOCK_INIT(log) spin_lock_init(&(log)->synclock) | 492 | #define LOGSYNC_LOCK_INIT(log) spin_lock_init(&(log)->synclock) |
493 | #define LOGSYNC_LOCK(log) spin_lock(&(log)->synclock) | 493 | #define LOGSYNC_LOCK(log, flags) spin_lock_irqsave(&(log)->synclock, flags) |
494 | #define LOGSYNC_UNLOCK(log) spin_unlock(&(log)->synclock) | 494 | #define LOGSYNC_UNLOCK(log, flags) \ |
495 | spin_unlock_irqrestore(&(log)->synclock, flags) | ||
495 | 496 | ||
496 | /* compute the difference in bytes of lsn from sync point */ | 497 | /* compute the difference in bytes of lsn from sync point */ |
497 | #define logdiff(diff, lsn, log)\ | 498 | #define logdiff(diff, lsn, log)\ |
diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index 4c0a3ac75c08..41bf078dce05 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) International Business Machines Corp., 2000-2003 | 2 | * Copyright (C) International Business Machines Corp., 2000-2005 |
3 | * Portions Copyright (C) Christoph Hellwig, 2001-2002 | 3 | * Portions Copyright (C) Christoph Hellwig, 2001-2002 |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
@@ -18,10 +18,11 @@ | |||
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
21 | #include <linux/mm.h> | ||
22 | #include <linux/bio.h> | ||
21 | #include <linux/init.h> | 23 | #include <linux/init.h> |
22 | #include <linux/buffer_head.h> | 24 | #include <linux/buffer_head.h> |
23 | #include <linux/mempool.h> | 25 | #include <linux/mempool.h> |
24 | #include <linux/delay.h> | ||
25 | #include "jfs_incore.h" | 26 | #include "jfs_incore.h" |
26 | #include "jfs_superblock.h" | 27 | #include "jfs_superblock.h" |
27 | #include "jfs_filsys.h" | 28 | #include "jfs_filsys.h" |
@@ -29,8 +30,6 @@ | |||
29 | #include "jfs_txnmgr.h" | 30 | #include "jfs_txnmgr.h" |
30 | #include "jfs_debug.h" | 31 | #include "jfs_debug.h" |
31 | 32 | ||
32 | static DEFINE_SPINLOCK(meta_lock); | ||
33 | |||
34 | #ifdef CONFIG_JFS_STATISTICS | 33 | #ifdef CONFIG_JFS_STATISTICS |
35 | static struct { | 34 | static struct { |
36 | uint pagealloc; /* # of page allocations */ | 35 | uint pagealloc; /* # of page allocations */ |
@@ -39,22 +38,8 @@ static struct { | |||
39 | } mpStat; | 38 | } mpStat; |
40 | #endif | 39 | #endif |
41 | 40 | ||
42 | 41 | #define metapage_locked(mp) test_bit(META_locked, &(mp)->flag) | |
43 | #define HASH_BITS 10 /* This makes hash_table 1 4K page */ | 42 | #define trylock_metapage(mp) test_and_set_bit(META_locked, &(mp)->flag) |
44 | #define HASH_SIZE (1 << HASH_BITS) | ||
45 | static struct metapage **hash_table = NULL; | ||
46 | static unsigned long hash_order; | ||
47 | |||
48 | |||
49 | static inline int metapage_locked(struct metapage *mp) | ||
50 | { | ||
51 | return test_bit(META_locked, &mp->flag); | ||
52 | } | ||
53 | |||
54 | static inline int trylock_metapage(struct metapage *mp) | ||
55 | { | ||
56 | return test_and_set_bit(META_locked, &mp->flag); | ||
57 | } | ||
58 | 43 | ||
59 | static inline void unlock_metapage(struct metapage *mp) | 44 | static inline void unlock_metapage(struct metapage *mp) |
60 | { | 45 | { |
@@ -62,26 +47,26 @@ static inline void unlock_metapage(struct metapage *mp) | |||
62 | wake_up(&mp->wait); | 47 | wake_up(&mp->wait); |
63 | } | 48 | } |
64 | 49 | ||
65 | static void __lock_metapage(struct metapage *mp) | 50 | static inline void __lock_metapage(struct metapage *mp) |
66 | { | 51 | { |
67 | DECLARE_WAITQUEUE(wait, current); | 52 | DECLARE_WAITQUEUE(wait, current); |
68 | |||
69 | INCREMENT(mpStat.lockwait); | 53 | INCREMENT(mpStat.lockwait); |
70 | |||
71 | add_wait_queue_exclusive(&mp->wait, &wait); | 54 | add_wait_queue_exclusive(&mp->wait, &wait); |
72 | do { | 55 | do { |
73 | set_current_state(TASK_UNINTERRUPTIBLE); | 56 | set_current_state(TASK_UNINTERRUPTIBLE); |
74 | if (metapage_locked(mp)) { | 57 | if (metapage_locked(mp)) { |
75 | spin_unlock(&meta_lock); | 58 | unlock_page(mp->page); |
76 | schedule(); | 59 | schedule(); |
77 | spin_lock(&meta_lock); | 60 | lock_page(mp->page); |
78 | } | 61 | } |
79 | } while (trylock_metapage(mp)); | 62 | } while (trylock_metapage(mp)); |
80 | __set_current_state(TASK_RUNNING); | 63 | __set_current_state(TASK_RUNNING); |
81 | remove_wait_queue(&mp->wait, &wait); | 64 | remove_wait_queue(&mp->wait, &wait); |
82 | } | 65 | } |
83 | 66 | ||
84 | /* needs meta_lock */ | 67 | /* |
68 | * Must have mp->page locked | ||
69 | */ | ||
85 | static inline void lock_metapage(struct metapage *mp) | 70 | static inline void lock_metapage(struct metapage *mp) |
86 | { | 71 | { |
87 | if (trylock_metapage(mp)) | 72 | if (trylock_metapage(mp)) |
@@ -92,6 +77,110 @@ static inline void lock_metapage(struct metapage *mp) | |||
92 | static kmem_cache_t *metapage_cache; | 77 | static kmem_cache_t *metapage_cache; |
93 | static mempool_t *metapage_mempool; | 78 | static mempool_t *metapage_mempool; |
94 | 79 | ||
80 | #define MPS_PER_PAGE (PAGE_CACHE_SIZE >> L2PSIZE) | ||
81 | |||
82 | #if MPS_PER_PAGE > 1 | ||
83 | |||
84 | struct meta_anchor { | ||
85 | int mp_count; | ||
86 | atomic_t io_count; | ||
87 | struct metapage *mp[MPS_PER_PAGE]; | ||
88 | }; | ||
89 | #define mp_anchor(page) ((struct meta_anchor *)page->private) | ||
90 | |||
91 | static inline struct metapage *page_to_mp(struct page *page, uint offset) | ||
92 | { | ||
93 | if (!PagePrivate(page)) | ||
94 | return NULL; | ||
95 | return mp_anchor(page)->mp[offset >> L2PSIZE]; | ||
96 | } | ||
97 | |||
98 | static inline int insert_metapage(struct page *page, struct metapage *mp) | ||
99 | { | ||
100 | struct meta_anchor *a; | ||
101 | int index; | ||
102 | int l2mp_blocks; /* log2 blocks per metapage */ | ||
103 | |||
104 | if (PagePrivate(page)) | ||
105 | a = mp_anchor(page); | ||
106 | else { | ||
107 | a = kmalloc(sizeof(struct meta_anchor), GFP_NOFS); | ||
108 | if (!a) | ||
109 | return -ENOMEM; | ||
110 | memset(a, 0, sizeof(struct meta_anchor)); | ||
111 | page->private = (unsigned long)a; | ||
112 | SetPagePrivate(page); | ||
113 | kmap(page); | ||
114 | } | ||
115 | |||
116 | if (mp) { | ||
117 | l2mp_blocks = L2PSIZE - page->mapping->host->i_blkbits; | ||
118 | index = (mp->index >> l2mp_blocks) & (MPS_PER_PAGE - 1); | ||
119 | a->mp_count++; | ||
120 | a->mp[index] = mp; | ||
121 | } | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static inline void remove_metapage(struct page *page, struct metapage *mp) | ||
127 | { | ||
128 | struct meta_anchor *a = mp_anchor(page); | ||
129 | int l2mp_blocks = L2PSIZE - page->mapping->host->i_blkbits; | ||
130 | int index; | ||
131 | |||
132 | index = (mp->index >> l2mp_blocks) & (MPS_PER_PAGE - 1); | ||
133 | |||
134 | BUG_ON(a->mp[index] != mp); | ||
135 | |||
136 | a->mp[index] = NULL; | ||
137 | if (--a->mp_count == 0) { | ||
138 | kfree(a); | ||
139 | page->private = 0; | ||
140 | ClearPagePrivate(page); | ||
141 | kunmap(page); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | static inline void inc_io(struct page *page) | ||
146 | { | ||
147 | atomic_inc(&mp_anchor(page)->io_count); | ||
148 | } | ||
149 | |||
150 | static inline void dec_io(struct page *page, void (*handler) (struct page *)) | ||
151 | { | ||
152 | if (atomic_dec_and_test(&mp_anchor(page)->io_count)) | ||
153 | handler(page); | ||
154 | } | ||
155 | |||
156 | #else | ||
157 | static inline struct metapage *page_to_mp(struct page *page, uint offset) | ||
158 | { | ||
159 | return PagePrivate(page) ? (struct metapage *)page->private : NULL; | ||
160 | } | ||
161 | |||
162 | static inline int insert_metapage(struct page *page, struct metapage *mp) | ||
163 | { | ||
164 | if (mp) { | ||
165 | page->private = (unsigned long)mp; | ||
166 | SetPagePrivate(page); | ||
167 | kmap(page); | ||
168 | } | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static inline void remove_metapage(struct page *page, struct metapage *mp) | ||
173 | { | ||
174 | page->private = 0; | ||
175 | ClearPagePrivate(page); | ||
176 | kunmap(page); | ||
177 | } | ||
178 | |||
179 | #define inc_io(page) do {} while(0) | ||
180 | #define dec_io(page, handler) handler(page) | ||
181 | |||
182 | #endif | ||
183 | |||
95 | static void init_once(void *foo, kmem_cache_t *cachep, unsigned long flags) | 184 | static void init_once(void *foo, kmem_cache_t *cachep, unsigned long flags) |
96 | { | 185 | { |
97 | struct metapage *mp = (struct metapage *)foo; | 186 | struct metapage *mp = (struct metapage *)foo; |
@@ -139,16 +228,6 @@ int __init metapage_init(void) | |||
139 | kmem_cache_destroy(metapage_cache); | 228 | kmem_cache_destroy(metapage_cache); |
140 | return -ENOMEM; | 229 | return -ENOMEM; |
141 | } | 230 | } |
142 | /* | ||
143 | * Now the hash list | ||
144 | */ | ||
145 | for (hash_order = 0; | ||
146 | ((PAGE_SIZE << hash_order) / sizeof(void *)) < HASH_SIZE; | ||
147 | hash_order++); | ||
148 | hash_table = | ||
149 | (struct metapage **) __get_free_pages(GFP_KERNEL, hash_order); | ||
150 | assert(hash_table); | ||
151 | memset(hash_table, 0, PAGE_SIZE << hash_order); | ||
152 | 231 | ||
153 | return 0; | 232 | return 0; |
154 | } | 233 | } |
@@ -159,73 +238,388 @@ void metapage_exit(void) | |||
159 | kmem_cache_destroy(metapage_cache); | 238 | kmem_cache_destroy(metapage_cache); |
160 | } | 239 | } |
161 | 240 | ||
241 | static inline void drop_metapage(struct page *page, struct metapage *mp) | ||
242 | { | ||
243 | if (mp->count || mp->nohomeok || test_bit(META_dirty, &mp->flag) || | ||
244 | test_bit(META_io, &mp->flag)) | ||
245 | return; | ||
246 | remove_metapage(page, mp); | ||
247 | INCREMENT(mpStat.pagefree); | ||
248 | free_metapage(mp); | ||
249 | } | ||
250 | |||
162 | /* | 251 | /* |
163 | * Basically same hash as in pagemap.h, but using our hash table | 252 | * Metapage address space operations |
164 | */ | 253 | */ |
165 | static struct metapage **meta_hash(struct address_space *mapping, | 254 | |
166 | unsigned long index) | 255 | static sector_t metapage_get_blocks(struct inode *inode, sector_t lblock, |
256 | unsigned int *len) | ||
167 | { | 257 | { |
168 | #define i (((unsigned long)mapping)/ \ | 258 | int rc = 0; |
169 | (sizeof(struct inode) & ~(sizeof(struct inode) -1 ))) | 259 | int xflag; |
170 | #define s(x) ((x) + ((x) >> HASH_BITS)) | 260 | s64 xaddr; |
171 | return hash_table + (s(i + index) & (HASH_SIZE - 1)); | 261 | sector_t file_blocks = (inode->i_size + inode->i_blksize - 1) >> |
172 | #undef i | 262 | inode->i_blkbits; |
173 | #undef s | 263 | |
264 | if (lblock >= file_blocks) | ||
265 | return 0; | ||
266 | if (lblock + *len > file_blocks) | ||
267 | *len = file_blocks - lblock; | ||
268 | |||
269 | if (inode->i_ino) { | ||
270 | rc = xtLookup(inode, (s64)lblock, *len, &xflag, &xaddr, len, 0); | ||
271 | if ((rc == 0) && *len) | ||
272 | lblock = (sector_t)xaddr; | ||
273 | else | ||
274 | lblock = 0; | ||
275 | } /* else no mapping */ | ||
276 | |||
277 | return lblock; | ||
174 | } | 278 | } |
175 | 279 | ||
176 | static struct metapage *search_hash(struct metapage ** hash_ptr, | 280 | static void last_read_complete(struct page *page) |
177 | struct address_space *mapping, | ||
178 | unsigned long index) | ||
179 | { | 281 | { |
180 | struct metapage *ptr; | 282 | if (!PageError(page)) |
283 | SetPageUptodate(page); | ||
284 | unlock_page(page); | ||
285 | } | ||
286 | |||
287 | static int metapage_read_end_io(struct bio *bio, unsigned int bytes_done, | ||
288 | int err) | ||
289 | { | ||
290 | struct page *page = bio->bi_private; | ||
291 | |||
292 | if (bio->bi_size) | ||
293 | return 1; | ||
181 | 294 | ||
182 | for (ptr = *hash_ptr; ptr; ptr = ptr->hash_next) { | 295 | if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) { |
183 | if ((ptr->mapping == mapping) && (ptr->index == index)) | 296 | printk(KERN_ERR "metapage_read_end_io: I/O error\n"); |
184 | return ptr; | 297 | SetPageError(page); |
185 | } | 298 | } |
186 | 299 | ||
187 | return NULL; | 300 | dec_io(page, last_read_complete); |
301 | bio_put(bio); | ||
302 | |||
303 | return 0; | ||
188 | } | 304 | } |
189 | 305 | ||
190 | static void add_to_hash(struct metapage * mp, struct metapage ** hash_ptr) | 306 | static void remove_from_logsync(struct metapage *mp) |
191 | { | 307 | { |
192 | if (*hash_ptr) | 308 | struct jfs_log *log = mp->log; |
193 | (*hash_ptr)->hash_prev = mp; | 309 | unsigned long flags; |
310 | /* | ||
311 | * This can race. Recheck that log hasn't been set to null, and after | ||
312 | * acquiring logsync lock, recheck lsn | ||
313 | */ | ||
314 | if (!log) | ||
315 | return; | ||
316 | |||
317 | LOGSYNC_LOCK(log, flags); | ||
318 | if (mp->lsn) { | ||
319 | mp->log = NULL; | ||
320 | mp->lsn = 0; | ||
321 | mp->clsn = 0; | ||
322 | log->count--; | ||
323 | list_del(&mp->synclist); | ||
324 | } | ||
325 | LOGSYNC_UNLOCK(log, flags); | ||
326 | } | ||
194 | 327 | ||
195 | mp->hash_prev = NULL; | 328 | static void last_write_complete(struct page *page) |
196 | mp->hash_next = *hash_ptr; | 329 | { |
197 | *hash_ptr = mp; | 330 | struct metapage *mp; |
331 | unsigned int offset; | ||
332 | |||
333 | for (offset = 0; offset < PAGE_CACHE_SIZE; offset += PSIZE) { | ||
334 | mp = page_to_mp(page, offset); | ||
335 | if (mp && test_bit(META_io, &mp->flag)) { | ||
336 | if (mp->lsn) | ||
337 | remove_from_logsync(mp); | ||
338 | clear_bit(META_io, &mp->flag); | ||
339 | } | ||
340 | /* | ||
341 | * I'd like to call drop_metapage here, but I don't think it's | ||
342 | * safe unless I have the page locked | ||
343 | */ | ||
344 | } | ||
345 | end_page_writeback(page); | ||
198 | } | 346 | } |
199 | 347 | ||
200 | static void remove_from_hash(struct metapage * mp, struct metapage ** hash_ptr) | 348 | static int metapage_write_end_io(struct bio *bio, unsigned int bytes_done, |
349 | int err) | ||
201 | { | 350 | { |
202 | if (mp->hash_prev) | 351 | struct page *page = bio->bi_private; |
203 | mp->hash_prev->hash_next = mp->hash_next; | 352 | |
204 | else { | 353 | BUG_ON(!PagePrivate(page)); |
205 | assert(*hash_ptr == mp); | 354 | |
206 | *hash_ptr = mp->hash_next; | 355 | if (bio->bi_size) |
356 | return 1; | ||
357 | |||
358 | if (! test_bit(BIO_UPTODATE, &bio->bi_flags)) { | ||
359 | printk(KERN_ERR "metapage_write_end_io: I/O error\n"); | ||
360 | SetPageError(page); | ||
361 | } | ||
362 | dec_io(page, last_write_complete); | ||
363 | bio_put(bio); | ||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | static int metapage_writepage(struct page *page, struct writeback_control *wbc) | ||
368 | { | ||
369 | struct bio *bio = NULL; | ||
370 | unsigned int block_offset; /* block offset of mp within page */ | ||
371 | struct inode *inode = page->mapping->host; | ||
372 | unsigned int blocks_per_mp = JFS_SBI(inode->i_sb)->nbperpage; | ||
373 | unsigned int len; | ||
374 | unsigned int xlen; | ||
375 | struct metapage *mp; | ||
376 | int redirty = 0; | ||
377 | sector_t lblock; | ||
378 | sector_t pblock; | ||
379 | sector_t next_block = 0; | ||
380 | sector_t page_start; | ||
381 | unsigned long bio_bytes = 0; | ||
382 | unsigned long bio_offset = 0; | ||
383 | unsigned int offset; | ||
384 | |||
385 | page_start = (sector_t)page->index << | ||
386 | (PAGE_CACHE_SHIFT - inode->i_blkbits); | ||
387 | BUG_ON(!PageLocked(page)); | ||
388 | BUG_ON(PageWriteback(page)); | ||
389 | |||
390 | for (offset = 0; offset < PAGE_CACHE_SIZE; offset += PSIZE) { | ||
391 | mp = page_to_mp(page, offset); | ||
392 | |||
393 | if (!mp || !test_bit(META_dirty, &mp->flag)) | ||
394 | continue; | ||
395 | |||
396 | if (mp->nohomeok && !test_bit(META_forcewrite, &mp->flag)) { | ||
397 | redirty = 1; | ||
398 | continue; | ||
399 | } | ||
400 | |||
401 | clear_bit(META_dirty, &mp->flag); | ||
402 | block_offset = offset >> inode->i_blkbits; | ||
403 | lblock = page_start + block_offset; | ||
404 | if (bio) { | ||
405 | if (xlen && lblock == next_block) { | ||
406 | /* Contiguous, in memory & on disk */ | ||
407 | len = min(xlen, blocks_per_mp); | ||
408 | xlen -= len; | ||
409 | bio_bytes += len << inode->i_blkbits; | ||
410 | set_bit(META_io, &mp->flag); | ||
411 | continue; | ||
412 | } | ||
413 | /* Not contiguous */ | ||
414 | if (bio_add_page(bio, page, bio_bytes, bio_offset) < | ||
415 | bio_bytes) | ||
416 | goto add_failed; | ||
417 | /* | ||
418 | * Increment counter before submitting i/o to keep | ||
419 | * count from hitting zero before we're through | ||
420 | */ | ||
421 | inc_io(page); | ||
422 | if (!bio->bi_size) | ||
423 | goto dump_bio; | ||
424 | submit_bio(WRITE, bio); | ||
425 | bio = NULL; | ||
426 | } else { | ||
427 | set_page_writeback(page); | ||
428 | inc_io(page); | ||
429 | } | ||
430 | xlen = (PAGE_CACHE_SIZE - offset) >> inode->i_blkbits; | ||
431 | pblock = metapage_get_blocks(inode, lblock, &xlen); | ||
432 | if (!pblock) { | ||
433 | /* Need better error handling */ | ||
434 | printk(KERN_ERR "JFS: metapage_get_blocks failed\n"); | ||
435 | dec_io(page, last_write_complete); | ||
436 | continue; | ||
437 | } | ||
438 | set_bit(META_io, &mp->flag); | ||
439 | len = min(xlen, (uint) JFS_SBI(inode->i_sb)->nbperpage); | ||
440 | |||
441 | bio = bio_alloc(GFP_NOFS, 1); | ||
442 | bio->bi_bdev = inode->i_sb->s_bdev; | ||
443 | bio->bi_sector = pblock << (inode->i_blkbits - 9); | ||
444 | bio->bi_end_io = metapage_write_end_io; | ||
445 | bio->bi_private = page; | ||
446 | |||
447 | /* Don't call bio_add_page yet, we may add to this vec */ | ||
448 | bio_offset = offset; | ||
449 | bio_bytes = len << inode->i_blkbits; | ||
450 | |||
451 | xlen -= len; | ||
452 | next_block = lblock + len; | ||
453 | } | ||
454 | if (bio) { | ||
455 | if (bio_add_page(bio, page, bio_bytes, bio_offset) < bio_bytes) | ||
456 | goto add_failed; | ||
457 | if (!bio->bi_size) | ||
458 | goto dump_bio; | ||
459 | |||
460 | submit_bio(WRITE, bio); | ||
461 | } | ||
462 | if (redirty) | ||
463 | redirty_page_for_writepage(wbc, page); | ||
464 | |||
465 | unlock_page(page); | ||
466 | |||
467 | return 0; | ||
468 | add_failed: | ||
469 | /* We should never reach here, since we're only adding one vec */ | ||
470 | printk(KERN_ERR "JFS: bio_add_page failed unexpectedly\n"); | ||
471 | goto skip; | ||
472 | dump_bio: | ||
473 | dump_mem("bio", bio, sizeof(*bio)); | ||
474 | skip: | ||
475 | bio_put(bio); | ||
476 | unlock_page(page); | ||
477 | dec_io(page, last_write_complete); | ||
478 | |||
479 | return -EIO; | ||
480 | } | ||
481 | |||
482 | static int metapage_readpage(struct file *fp, struct page *page) | ||
483 | { | ||
484 | struct inode *inode = page->mapping->host; | ||
485 | struct bio *bio = NULL; | ||
486 | unsigned int block_offset; | ||
487 | unsigned int blocks_per_page = PAGE_CACHE_SIZE >> inode->i_blkbits; | ||
488 | sector_t page_start; /* address of page in fs blocks */ | ||
489 | sector_t pblock; | ||
490 | unsigned int xlen; | ||
491 | unsigned int len; | ||
492 | unsigned int offset; | ||
493 | |||
494 | BUG_ON(!PageLocked(page)); | ||
495 | page_start = (sector_t)page->index << | ||
496 | (PAGE_CACHE_SHIFT - inode->i_blkbits); | ||
497 | |||
498 | block_offset = 0; | ||
499 | while (block_offset < blocks_per_page) { | ||
500 | xlen = blocks_per_page - block_offset; | ||
501 | pblock = metapage_get_blocks(inode, page_start + block_offset, | ||
502 | &xlen); | ||
503 | if (pblock) { | ||
504 | if (!PagePrivate(page)) | ||
505 | insert_metapage(page, NULL); | ||
506 | inc_io(page); | ||
507 | if (bio) | ||
508 | submit_bio(READ, bio); | ||
509 | |||
510 | bio = bio_alloc(GFP_NOFS, 1); | ||
511 | bio->bi_bdev = inode->i_sb->s_bdev; | ||
512 | bio->bi_sector = pblock << (inode->i_blkbits - 9); | ||
513 | bio->bi_end_io = metapage_read_end_io; | ||
514 | bio->bi_private = page; | ||
515 | len = xlen << inode->i_blkbits; | ||
516 | offset = block_offset << inode->i_blkbits; | ||
517 | if (bio_add_page(bio, page, len, offset) < len) | ||
518 | goto add_failed; | ||
519 | block_offset += xlen; | ||
520 | } else | ||
521 | block_offset++; | ||
207 | } | 522 | } |
523 | if (bio) | ||
524 | submit_bio(READ, bio); | ||
525 | else | ||
526 | unlock_page(page); | ||
527 | |||
528 | return 0; | ||
208 | 529 | ||
209 | if (mp->hash_next) | 530 | add_failed: |
210 | mp->hash_next->hash_prev = mp->hash_prev; | 531 | printk(KERN_ERR "JFS: bio_add_page failed unexpectedly\n"); |
532 | bio_put(bio); | ||
533 | dec_io(page, last_read_complete); | ||
534 | return -EIO; | ||
211 | } | 535 | } |
212 | 536 | ||
537 | static int metapage_releasepage(struct page *page, int gfp_mask) | ||
538 | { | ||
539 | struct metapage *mp; | ||
540 | int busy = 0; | ||
541 | unsigned int offset; | ||
542 | |||
543 | for (offset = 0; offset < PAGE_CACHE_SIZE; offset += PSIZE) { | ||
544 | mp = page_to_mp(page, offset); | ||
545 | |||
546 | if (!mp) | ||
547 | continue; | ||
548 | |||
549 | jfs_info("metapage_releasepage: mp = 0x%p", mp); | ||
550 | if (mp->count || mp->nohomeok) { | ||
551 | jfs_info("count = %ld, nohomeok = %d", mp->count, | ||
552 | mp->nohomeok); | ||
553 | busy = 1; | ||
554 | continue; | ||
555 | } | ||
556 | wait_on_page_writeback(page); | ||
557 | //WARN_ON(test_bit(META_dirty, &mp->flag)); | ||
558 | if (test_bit(META_dirty, &mp->flag)) { | ||
559 | dump_mem("dirty mp in metapage_releasepage", mp, | ||
560 | sizeof(struct metapage)); | ||
561 | dump_mem("page", page, sizeof(struct page)); | ||
562 | dump_stack(); | ||
563 | } | ||
564 | WARN_ON(mp->lsn); | ||
565 | if (mp->lsn) | ||
566 | remove_from_logsync(mp); | ||
567 | remove_metapage(page, mp); | ||
568 | INCREMENT(mpStat.pagefree); | ||
569 | free_metapage(mp); | ||
570 | } | ||
571 | if (busy) | ||
572 | return -1; | ||
573 | |||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | static int metapage_invalidatepage(struct page *page, unsigned long offset) | ||
578 | { | ||
579 | BUG_ON(offset); | ||
580 | |||
581 | if (PageWriteback(page)) | ||
582 | return 0; | ||
583 | |||
584 | return metapage_releasepage(page, 0); | ||
585 | } | ||
586 | |||
587 | struct address_space_operations jfs_metapage_aops = { | ||
588 | .readpage = metapage_readpage, | ||
589 | .writepage = metapage_writepage, | ||
590 | .sync_page = block_sync_page, | ||
591 | .releasepage = metapage_releasepage, | ||
592 | .invalidatepage = metapage_invalidatepage, | ||
593 | .set_page_dirty = __set_page_dirty_nobuffers, | ||
594 | }; | ||
595 | |||
213 | struct metapage *__get_metapage(struct inode *inode, unsigned long lblock, | 596 | struct metapage *__get_metapage(struct inode *inode, unsigned long lblock, |
214 | unsigned int size, int absolute, | 597 | unsigned int size, int absolute, |
215 | unsigned long new) | 598 | unsigned long new) |
216 | { | 599 | { |
217 | struct metapage **hash_ptr; | ||
218 | int l2BlocksPerPage; | 600 | int l2BlocksPerPage; |
219 | int l2bsize; | 601 | int l2bsize; |
220 | struct address_space *mapping; | 602 | struct address_space *mapping; |
221 | struct metapage *mp; | 603 | struct metapage *mp = NULL; |
604 | struct page *page; | ||
222 | unsigned long page_index; | 605 | unsigned long page_index; |
223 | unsigned long page_offset; | 606 | unsigned long page_offset; |
224 | 607 | ||
225 | jfs_info("__get_metapage: inode = 0x%p, lblock = 0x%lx", inode, lblock); | 608 | jfs_info("__get_metapage: ino = %ld, lblock = 0x%lx, abs=%d", |
226 | 609 | inode->i_ino, lblock, absolute); | |
610 | |||
611 | l2bsize = inode->i_blkbits; | ||
612 | l2BlocksPerPage = PAGE_CACHE_SHIFT - l2bsize; | ||
613 | page_index = lblock >> l2BlocksPerPage; | ||
614 | page_offset = (lblock - (page_index << l2BlocksPerPage)) << l2bsize; | ||
615 | if ((page_offset + size) > PAGE_CACHE_SIZE) { | ||
616 | jfs_err("MetaData crosses page boundary!!"); | ||
617 | jfs_err("lblock = %lx, size = %d", lblock, size); | ||
618 | dump_stack(); | ||
619 | return NULL; | ||
620 | } | ||
227 | if (absolute) | 621 | if (absolute) |
228 | mapping = inode->i_sb->s_bdev->bd_inode->i_mapping; | 622 | mapping = JFS_SBI(inode->i_sb)->direct_inode->i_mapping; |
229 | else { | 623 | else { |
230 | /* | 624 | /* |
231 | * If an nfs client tries to read an inode that is larger | 625 | * If an nfs client tries to read an inode that is larger |
@@ -237,312 +631,212 @@ struct metapage *__get_metapage(struct inode *inode, unsigned long lblock, | |||
237 | mapping = inode->i_mapping; | 631 | mapping = inode->i_mapping; |
238 | } | 632 | } |
239 | 633 | ||
240 | hash_ptr = meta_hash(mapping, lblock); | 634 | if (new && (PSIZE == PAGE_CACHE_SIZE)) { |
241 | again: | 635 | page = grab_cache_page(mapping, page_index); |
242 | spin_lock(&meta_lock); | 636 | if (!page) { |
243 | mp = search_hash(hash_ptr, mapping, lblock); | 637 | jfs_err("grab_cache_page failed!"); |
638 | return NULL; | ||
639 | } | ||
640 | SetPageUptodate(page); | ||
641 | } else { | ||
642 | page = read_cache_page(mapping, page_index, | ||
643 | (filler_t *)mapping->a_ops->readpage, NULL); | ||
644 | if (IS_ERR(page)) { | ||
645 | jfs_err("read_cache_page failed!"); | ||
646 | return NULL; | ||
647 | } | ||
648 | lock_page(page); | ||
649 | } | ||
650 | |||
651 | mp = page_to_mp(page, page_offset); | ||
244 | if (mp) { | 652 | if (mp) { |
245 | page_found: | 653 | if (mp->logical_size != size) { |
246 | if (test_bit(META_stale, &mp->flag)) { | 654 | jfs_error(inode->i_sb, |
247 | spin_unlock(&meta_lock); | 655 | "__get_metapage: mp->logical_size != size"); |
248 | msleep(1); | 656 | jfs_err("logical_size = %d, size = %d", |
249 | goto again; | 657 | mp->logical_size, size); |
658 | dump_stack(); | ||
659 | goto unlock; | ||
250 | } | 660 | } |
251 | mp->count++; | 661 | mp->count++; |
252 | lock_metapage(mp); | 662 | lock_metapage(mp); |
253 | spin_unlock(&meta_lock); | ||
254 | if (test_bit(META_discard, &mp->flag)) { | 663 | if (test_bit(META_discard, &mp->flag)) { |
255 | if (!new) { | 664 | if (!new) { |
256 | jfs_error(inode->i_sb, | 665 | jfs_error(inode->i_sb, |
257 | "__get_metapage: using a " | 666 | "__get_metapage: using a " |
258 | "discarded metapage"); | 667 | "discarded metapage"); |
259 | release_metapage(mp); | 668 | discard_metapage(mp); |
260 | return NULL; | 669 | goto unlock; |
261 | } | 670 | } |
262 | clear_bit(META_discard, &mp->flag); | 671 | clear_bit(META_discard, &mp->flag); |
263 | } | 672 | } |
264 | jfs_info("__get_metapage: found 0x%p, in hash", mp); | ||
265 | if (mp->logical_size != size) { | ||
266 | jfs_error(inode->i_sb, | ||
267 | "__get_metapage: mp->logical_size != size"); | ||
268 | release_metapage(mp); | ||
269 | return NULL; | ||
270 | } | ||
271 | } else { | 673 | } else { |
272 | l2bsize = inode->i_blkbits; | 674 | INCREMENT(mpStat.pagealloc); |
273 | l2BlocksPerPage = PAGE_CACHE_SHIFT - l2bsize; | 675 | mp = alloc_metapage(GFP_NOFS); |
274 | page_index = lblock >> l2BlocksPerPage; | 676 | mp->page = page; |
275 | page_offset = (lblock - (page_index << l2BlocksPerPage)) << | ||
276 | l2bsize; | ||
277 | if ((page_offset + size) > PAGE_CACHE_SIZE) { | ||
278 | spin_unlock(&meta_lock); | ||
279 | jfs_err("MetaData crosses page boundary!!"); | ||
280 | return NULL; | ||
281 | } | ||
282 | |||
283 | /* | ||
284 | * Locks held on aggregate inode pages are usually | ||
285 | * not held long, and they are taken in critical code | ||
286 | * paths (committing dirty inodes, txCommit thread) | ||
287 | * | ||
288 | * Attempt to get metapage without blocking, tapping into | ||
289 | * reserves if necessary. | ||
290 | */ | ||
291 | mp = NULL; | ||
292 | if (JFS_IP(inode)->fileset == AGGREGATE_I) { | ||
293 | mp = alloc_metapage(GFP_ATOMIC); | ||
294 | if (!mp) { | ||
295 | /* | ||
296 | * mempool is supposed to protect us from | ||
297 | * failing here. We will try a blocking | ||
298 | * call, but a deadlock is possible here | ||
299 | */ | ||
300 | printk(KERN_WARNING | ||
301 | "__get_metapage: atomic call to mempool_alloc failed.\n"); | ||
302 | printk(KERN_WARNING | ||
303 | "Will attempt blocking call\n"); | ||
304 | } | ||
305 | } | ||
306 | if (!mp) { | ||
307 | struct metapage *mp2; | ||
308 | |||
309 | spin_unlock(&meta_lock); | ||
310 | mp = alloc_metapage(GFP_NOFS); | ||
311 | spin_lock(&meta_lock); | ||
312 | |||
313 | /* we dropped the meta_lock, we need to search the | ||
314 | * hash again. | ||
315 | */ | ||
316 | mp2 = search_hash(hash_ptr, mapping, lblock); | ||
317 | if (mp2) { | ||
318 | free_metapage(mp); | ||
319 | mp = mp2; | ||
320 | goto page_found; | ||
321 | } | ||
322 | } | ||
323 | mp->flag = 0; | 677 | mp->flag = 0; |
324 | lock_metapage(mp); | ||
325 | if (absolute) | ||
326 | set_bit(META_absolute, &mp->flag); | ||
327 | mp->xflag = COMMIT_PAGE; | 678 | mp->xflag = COMMIT_PAGE; |
328 | mp->count = 1; | 679 | mp->count = 1; |
329 | atomic_set(&mp->nohomeok,0); | 680 | mp->nohomeok = 0; |
330 | mp->mapping = mapping; | ||
331 | mp->index = lblock; | ||
332 | mp->page = NULL; | ||
333 | mp->logical_size = size; | 681 | mp->logical_size = size; |
334 | add_to_hash(mp, hash_ptr); | 682 | mp->data = page_address(page) + page_offset; |
335 | spin_unlock(&meta_lock); | 683 | mp->index = lblock; |
336 | 684 | if (unlikely(insert_metapage(page, mp))) { | |
337 | if (new) { | 685 | free_metapage(mp); |
338 | jfs_info("__get_metapage: Calling grab_cache_page"); | 686 | goto unlock; |
339 | mp->page = grab_cache_page(mapping, page_index); | ||
340 | if (!mp->page) { | ||
341 | jfs_err("grab_cache_page failed!"); | ||
342 | goto freeit; | ||
343 | } else { | ||
344 | INCREMENT(mpStat.pagealloc); | ||
345 | unlock_page(mp->page); | ||
346 | } | ||
347 | } else { | ||
348 | jfs_info("__get_metapage: Calling read_cache_page"); | ||
349 | mp->page = read_cache_page(mapping, lblock, | ||
350 | (filler_t *)mapping->a_ops->readpage, NULL); | ||
351 | if (IS_ERR(mp->page)) { | ||
352 | jfs_err("read_cache_page failed!"); | ||
353 | goto freeit; | ||
354 | } else | ||
355 | INCREMENT(mpStat.pagealloc); | ||
356 | } | 687 | } |
357 | mp->data = kmap(mp->page) + page_offset; | 688 | lock_metapage(mp); |
358 | } | 689 | } |
359 | 690 | ||
360 | if (new) | 691 | if (new) { |
692 | jfs_info("zeroing mp = 0x%p", mp); | ||
361 | memset(mp->data, 0, PSIZE); | 693 | memset(mp->data, 0, PSIZE); |
694 | } | ||
362 | 695 | ||
363 | jfs_info("__get_metapage: returning = 0x%p", mp); | 696 | unlock_page(page); |
697 | jfs_info("__get_metapage: returning = 0x%p data = 0x%p", mp, mp->data); | ||
364 | return mp; | 698 | return mp; |
365 | 699 | ||
366 | freeit: | 700 | unlock: |
367 | spin_lock(&meta_lock); | 701 | unlock_page(page); |
368 | remove_from_hash(mp, hash_ptr); | ||
369 | free_metapage(mp); | ||
370 | spin_unlock(&meta_lock); | ||
371 | return NULL; | 702 | return NULL; |
372 | } | 703 | } |
373 | 704 | ||
374 | void hold_metapage(struct metapage * mp, int force) | 705 | void grab_metapage(struct metapage * mp) |
375 | { | 706 | { |
376 | spin_lock(&meta_lock); | 707 | jfs_info("grab_metapage: mp = 0x%p", mp); |
377 | 708 | page_cache_get(mp->page); | |
709 | lock_page(mp->page); | ||
378 | mp->count++; | 710 | mp->count++; |
379 | 711 | lock_metapage(mp); | |
380 | if (force) { | 712 | unlock_page(mp->page); |
381 | ASSERT (!(test_bit(META_forced, &mp->flag))); | ||
382 | if (trylock_metapage(mp)) | ||
383 | set_bit(META_forced, &mp->flag); | ||
384 | } else | ||
385 | lock_metapage(mp); | ||
386 | |||
387 | spin_unlock(&meta_lock); | ||
388 | } | 713 | } |
389 | 714 | ||
390 | static void __write_metapage(struct metapage * mp) | 715 | void force_metapage(struct metapage *mp) |
391 | { | 716 | { |
392 | int l2bsize = mp->mapping->host->i_blkbits; | 717 | struct page *page = mp->page; |
393 | int l2BlocksPerPage = PAGE_CACHE_SHIFT - l2bsize; | 718 | jfs_info("force_metapage: mp = 0x%p", mp); |
394 | unsigned long page_index; | 719 | set_bit(META_forcewrite, &mp->flag); |
395 | unsigned long page_offset; | 720 | clear_bit(META_sync, &mp->flag); |
396 | int rc; | 721 | page_cache_get(page); |
397 | 722 | lock_page(page); | |
398 | jfs_info("__write_metapage: mp = 0x%p", mp); | 723 | set_page_dirty(page); |
399 | 724 | write_one_page(page, 1); | |
400 | page_index = mp->page->index; | 725 | clear_bit(META_forcewrite, &mp->flag); |
401 | page_offset = | 726 | page_cache_release(page); |
402 | (mp->index - (page_index << l2BlocksPerPage)) << l2bsize; | 727 | } |
403 | 728 | ||
729 | extern void hold_metapage(struct metapage *mp) | ||
730 | { | ||
404 | lock_page(mp->page); | 731 | lock_page(mp->page); |
405 | rc = mp->mapping->a_ops->prepare_write(NULL, mp->page, page_offset, | 732 | } |
406 | page_offset + | 733 | |
407 | mp->logical_size); | 734 | extern void put_metapage(struct metapage *mp) |
408 | if (rc) { | 735 | { |
409 | jfs_err("prepare_write return %d!", rc); | 736 | if (mp->count || mp->nohomeok) { |
410 | ClearPageUptodate(mp->page); | 737 | /* Someone else will release this */ |
411 | unlock_page(mp->page); | 738 | unlock_page(mp->page); |
412 | clear_bit(META_dirty, &mp->flag); | ||
413 | return; | 739 | return; |
414 | } | 740 | } |
415 | rc = mp->mapping->a_ops->commit_write(NULL, mp->page, page_offset, | 741 | page_cache_get(mp->page); |
416 | page_offset + | 742 | mp->count++; |
417 | mp->logical_size); | 743 | lock_metapage(mp); |
418 | if (rc) { | ||
419 | jfs_err("commit_write returned %d", rc); | ||
420 | } | ||
421 | |||
422 | unlock_page(mp->page); | 744 | unlock_page(mp->page); |
423 | clear_bit(META_dirty, &mp->flag); | 745 | release_metapage(mp); |
424 | |||
425 | jfs_info("__write_metapage done"); | ||
426 | } | ||
427 | |||
428 | static inline void sync_metapage(struct metapage *mp) | ||
429 | { | ||
430 | struct page *page = mp->page; | ||
431 | |||
432 | page_cache_get(page); | ||
433 | lock_page(page); | ||
434 | |||
435 | /* we're done with this page - no need to check for errors */ | ||
436 | if (page_has_buffers(page)) | ||
437 | write_one_page(page, 1); | ||
438 | else | ||
439 | unlock_page(page); | ||
440 | page_cache_release(page); | ||
441 | } | 746 | } |
442 | 747 | ||
443 | void release_metapage(struct metapage * mp) | 748 | void release_metapage(struct metapage * mp) |
444 | { | 749 | { |
445 | struct jfs_log *log; | 750 | struct page *page = mp->page; |
446 | |||
447 | jfs_info("release_metapage: mp = 0x%p, flag = 0x%lx", mp, mp->flag); | 751 | jfs_info("release_metapage: mp = 0x%p, flag = 0x%lx", mp, mp->flag); |
448 | 752 | ||
449 | spin_lock(&meta_lock); | 753 | BUG_ON(!page); |
450 | if (test_bit(META_forced, &mp->flag)) { | 754 | |
451 | clear_bit(META_forced, &mp->flag); | 755 | lock_page(page); |
452 | mp->count--; | 756 | unlock_metapage(mp); |
453 | spin_unlock(&meta_lock); | ||
454 | return; | ||
455 | } | ||
456 | 757 | ||
457 | assert(mp->count); | 758 | assert(mp->count); |
458 | if (--mp->count || atomic_read(&mp->nohomeok)) { | 759 | if (--mp->count || mp->nohomeok) { |
459 | unlock_metapage(mp); | 760 | unlock_page(page); |
460 | spin_unlock(&meta_lock); | 761 | page_cache_release(page); |
461 | return; | 762 | return; |
462 | } | 763 | } |
463 | 764 | ||
464 | if (mp->page) { | 765 | if (test_bit(META_dirty, &mp->flag)) { |
465 | set_bit(META_stale, &mp->flag); | 766 | set_page_dirty(page); |
466 | spin_unlock(&meta_lock); | ||
467 | kunmap(mp->page); | ||
468 | mp->data = NULL; | ||
469 | if (test_bit(META_dirty, &mp->flag)) | ||
470 | __write_metapage(mp); | ||
471 | if (test_bit(META_sync, &mp->flag)) { | 767 | if (test_bit(META_sync, &mp->flag)) { |
472 | sync_metapage(mp); | ||
473 | clear_bit(META_sync, &mp->flag); | 768 | clear_bit(META_sync, &mp->flag); |
769 | write_one_page(page, 1); | ||
770 | lock_page(page); /* write_one_page unlocks the page */ | ||
474 | } | 771 | } |
772 | } else if (mp->lsn) /* discard_metapage doesn't remove it */ | ||
773 | remove_from_logsync(mp); | ||
475 | 774 | ||
476 | if (test_bit(META_discard, &mp->flag)) { | 775 | #if MPS_PER_PAGE == 1 |
477 | lock_page(mp->page); | 776 | /* |
478 | block_invalidatepage(mp->page, 0); | 777 | * If we know this is the only thing in the page, we can throw |
479 | unlock_page(mp->page); | 778 | * the page out of the page cache. If pages are larger, we |
480 | } | 779 | * don't want to do this. |
481 | 780 | */ | |
482 | page_cache_release(mp->page); | ||
483 | mp->page = NULL; | ||
484 | INCREMENT(mpStat.pagefree); | ||
485 | spin_lock(&meta_lock); | ||
486 | } | ||
487 | 781 | ||
488 | if (mp->lsn) { | 782 | /* Retest mp->count since we may have released page lock */ |
489 | /* | 783 | if (test_bit(META_discard, &mp->flag) && !mp->count) { |
490 | * Remove metapage from logsynclist. | 784 | clear_page_dirty(page); |
491 | */ | 785 | ClearPageUptodate(page); |
492 | log = mp->log; | 786 | #ifdef _NOT_YET |
493 | LOGSYNC_LOCK(log); | 787 | if (page->mapping) { |
494 | mp->log = NULL; | 788 | /* Remove from page cache and page cache reference */ |
495 | mp->lsn = 0; | 789 | remove_from_page_cache(page); |
496 | mp->clsn = 0; | 790 | page_cache_release(page); |
497 | log->count--; | 791 | metapage_releasepage(page, 0); |
498 | list_del(&mp->synclist); | 792 | } |
499 | LOGSYNC_UNLOCK(log); | 793 | #endif |
500 | } | 794 | } |
501 | remove_from_hash(mp, meta_hash(mp->mapping, mp->index)); | 795 | #else |
502 | spin_unlock(&meta_lock); | 796 | /* Try to keep metapages from using up too much memory */ |
503 | 797 | drop_metapage(page, mp); | |
504 | free_metapage(mp); | 798 | #endif |
799 | unlock_page(page); | ||
800 | page_cache_release(page); | ||
505 | } | 801 | } |
506 | 802 | ||
507 | void __invalidate_metapages(struct inode *ip, s64 addr, int len) | 803 | void __invalidate_metapages(struct inode *ip, s64 addr, int len) |
508 | { | 804 | { |
509 | struct metapage **hash_ptr; | 805 | sector_t lblock; |
510 | unsigned long lblock; | ||
511 | int l2BlocksPerPage = PAGE_CACHE_SHIFT - ip->i_blkbits; | 806 | int l2BlocksPerPage = PAGE_CACHE_SHIFT - ip->i_blkbits; |
807 | int BlocksPerPage = 1 << l2BlocksPerPage; | ||
512 | /* All callers are interested in block device's mapping */ | 808 | /* All callers are interested in block device's mapping */ |
513 | struct address_space *mapping = ip->i_sb->s_bdev->bd_inode->i_mapping; | 809 | struct address_space *mapping = |
810 | JFS_SBI(ip->i_sb)->direct_inode->i_mapping; | ||
514 | struct metapage *mp; | 811 | struct metapage *mp; |
515 | struct page *page; | 812 | struct page *page; |
813 | unsigned int offset; | ||
516 | 814 | ||
517 | /* | 815 | /* |
518 | * First, mark metapages to discard. They will eventually be | 816 | * Mark metapages to discard. They will eventually be |
519 | * released, but should not be written. | 817 | * released, but should not be written. |
520 | */ | 818 | */ |
521 | for (lblock = addr; lblock < addr + len; | 819 | for (lblock = addr & ~(BlocksPerPage - 1); lblock < addr + len; |
522 | lblock += 1 << l2BlocksPerPage) { | 820 | lblock += BlocksPerPage) { |
523 | hash_ptr = meta_hash(mapping, lblock); | 821 | page = find_lock_page(mapping, lblock >> l2BlocksPerPage); |
524 | again: | 822 | if (!page) |
525 | spin_lock(&meta_lock); | 823 | continue; |
526 | mp = search_hash(hash_ptr, mapping, lblock); | 824 | for (offset = 0; offset < PAGE_CACHE_SIZE; offset += PSIZE) { |
527 | if (mp) { | 825 | mp = page_to_mp(page, offset); |
528 | if (test_bit(META_stale, &mp->flag)) { | 826 | if (!mp) |
529 | spin_unlock(&meta_lock); | 827 | continue; |
530 | msleep(1); | 828 | if (mp->index < addr) |
531 | goto again; | 829 | continue; |
532 | } | 830 | if (mp->index >= addr + len) |
831 | break; | ||
533 | 832 | ||
534 | clear_bit(META_dirty, &mp->flag); | 833 | clear_bit(META_dirty, &mp->flag); |
535 | set_bit(META_discard, &mp->flag); | 834 | set_bit(META_discard, &mp->flag); |
536 | spin_unlock(&meta_lock); | 835 | if (mp->lsn) |
537 | } else { | 836 | remove_from_logsync(mp); |
538 | spin_unlock(&meta_lock); | ||
539 | page = find_lock_page(mapping, lblock>>l2BlocksPerPage); | ||
540 | if (page) { | ||
541 | block_invalidatepage(page, 0); | ||
542 | unlock_page(page); | ||
543 | page_cache_release(page); | ||
544 | } | ||
545 | } | 837 | } |
838 | unlock_page(page); | ||
839 | page_cache_release(page); | ||
546 | } | 840 | } |
547 | } | 841 | } |
548 | 842 | ||
diff --git a/fs/jfs/jfs_metapage.h b/fs/jfs/jfs_metapage.h index 0e58aba58c37..991e9fb84c75 100644 --- a/fs/jfs/jfs_metapage.h +++ b/fs/jfs/jfs_metapage.h | |||
@@ -33,38 +33,27 @@ struct metapage { | |||
33 | unsigned long flag; /* See Below */ | 33 | unsigned long flag; /* See Below */ |
34 | unsigned long count; /* Reference count */ | 34 | unsigned long count; /* Reference count */ |
35 | void *data; /* Data pointer */ | 35 | void *data; /* Data pointer */ |
36 | 36 | sector_t index; /* block address of page */ | |
37 | /* list management stuff */ | ||
38 | struct metapage *hash_prev; | ||
39 | struct metapage *hash_next; /* Also used for free list */ | ||
40 | |||
41 | /* | ||
42 | * mapping & index become redundant, but we need these here to | ||
43 | * add the metapage to the hash before we have the real page | ||
44 | */ | ||
45 | struct address_space *mapping; | ||
46 | unsigned long index; | ||
47 | wait_queue_head_t wait; | 37 | wait_queue_head_t wait; |
48 | 38 | ||
49 | /* implementation */ | 39 | /* implementation */ |
50 | struct page *page; | 40 | struct page *page; |
51 | unsigned long logical_size; | 41 | unsigned int logical_size; |
52 | 42 | ||
53 | /* Journal management */ | 43 | /* Journal management */ |
54 | int clsn; | 44 | int clsn; |
55 | atomic_t nohomeok; | 45 | int nohomeok; |
56 | struct jfs_log *log; | 46 | struct jfs_log *log; |
57 | }; | 47 | }; |
58 | 48 | ||
59 | /* metapage flag */ | 49 | /* metapage flag */ |
60 | #define META_locked 0 | 50 | #define META_locked 0 |
61 | #define META_absolute 1 | 51 | #define META_free 1 |
62 | #define META_free 2 | 52 | #define META_dirty 2 |
63 | #define META_dirty 3 | 53 | #define META_sync 3 |
64 | #define META_sync 4 | 54 | #define META_discard 4 |
65 | #define META_discard 5 | 55 | #define META_forcewrite 5 |
66 | #define META_forced 6 | 56 | #define META_io 6 |
67 | #define META_stale 7 | ||
68 | 57 | ||
69 | #define mark_metapage_dirty(mp) set_bit(META_dirty, &(mp)->flag) | 58 | #define mark_metapage_dirty(mp) set_bit(META_dirty, &(mp)->flag) |
70 | 59 | ||
@@ -80,7 +69,16 @@ extern struct metapage *__get_metapage(struct inode *inode, | |||
80 | __get_metapage(inode, lblock, size, absolute, TRUE) | 69 | __get_metapage(inode, lblock, size, absolute, TRUE) |
81 | 70 | ||
82 | extern void release_metapage(struct metapage *); | 71 | extern void release_metapage(struct metapage *); |
83 | extern void hold_metapage(struct metapage *, int); | 72 | extern void grab_metapage(struct metapage *); |
73 | extern void force_metapage(struct metapage *); | ||
74 | |||
75 | /* | ||
76 | * hold_metapage and put_metapage are used in conjuction. The page lock | ||
77 | * is not dropped between the two, so no other threads can get or release | ||
78 | * the metapage | ||
79 | */ | ||
80 | extern void hold_metapage(struct metapage *); | ||
81 | extern void put_metapage(struct metapage *); | ||
84 | 82 | ||
85 | static inline void write_metapage(struct metapage *mp) | 83 | static inline void write_metapage(struct metapage *mp) |
86 | { | 84 | { |
@@ -101,6 +99,46 @@ static inline void discard_metapage(struct metapage *mp) | |||
101 | release_metapage(mp); | 99 | release_metapage(mp); |
102 | } | 100 | } |
103 | 101 | ||
102 | static inline void metapage_nohomeok(struct metapage *mp) | ||
103 | { | ||
104 | struct page *page = mp->page; | ||
105 | lock_page(page); | ||
106 | if (!mp->nohomeok++) { | ||
107 | mark_metapage_dirty(mp); | ||
108 | page_cache_get(page); | ||
109 | wait_on_page_writeback(page); | ||
110 | } | ||
111 | unlock_page(page); | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | * This serializes access to mp->lsn when metapages are added to logsynclist | ||
116 | * without setting nohomeok. i.e. updating imap & dmap | ||
117 | */ | ||
118 | static inline void metapage_wait_for_io(struct metapage *mp) | ||
119 | { | ||
120 | if (test_bit(META_io, &mp->flag)) | ||
121 | wait_on_page_writeback(mp->page); | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * This is called when already holding the metapage | ||
126 | */ | ||
127 | static inline void _metapage_homeok(struct metapage *mp) | ||
128 | { | ||
129 | if (!--mp->nohomeok) | ||
130 | page_cache_release(mp->page); | ||
131 | } | ||
132 | |||
133 | static inline void metapage_homeok(struct metapage *mp) | ||
134 | { | ||
135 | hold_metapage(mp); | ||
136 | _metapage_homeok(mp); | ||
137 | put_metapage(mp); | ||
138 | } | ||
139 | |||
140 | extern struct address_space_operations jfs_metapage_aops; | ||
141 | |||
104 | /* | 142 | /* |
105 | * This routines invalidate all pages for an extent. | 143 | * This routines invalidate all pages for an extent. |
106 | */ | 144 | */ |
diff --git a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c index c535ffd638e8..032d111bc330 100644 --- a/fs/jfs/jfs_mount.c +++ b/fs/jfs/jfs_mount.c | |||
@@ -285,11 +285,6 @@ int jfs_mount_rw(struct super_block *sb, int remount) | |||
285 | */ | 285 | */ |
286 | logMOUNT(sb); | 286 | logMOUNT(sb); |
287 | 287 | ||
288 | /* | ||
289 | * Set page cache allocation policy | ||
290 | */ | ||
291 | mapping_set_gfp_mask(sb->s_bdev->bd_inode->i_mapping, GFP_NOFS); | ||
292 | |||
293 | return rc; | 288 | return rc; |
294 | } | 289 | } |
295 | 290 | ||
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index 98e16d93e146..bbc9c1407b55 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c | |||
@@ -227,6 +227,7 @@ static lid_t txLockAlloc(void) | |||
227 | 227 | ||
228 | static void txLockFree(lid_t lid) | 228 | static void txLockFree(lid_t lid) |
229 | { | 229 | { |
230 | TxLock[lid].tid = 0; | ||
230 | TxLock[lid].next = TxAnchor.freelock; | 231 | TxLock[lid].next = TxAnchor.freelock; |
231 | TxAnchor.freelock = lid; | 232 | TxAnchor.freelock = lid; |
232 | TxAnchor.tlocksInUse--; | 233 | TxAnchor.tlocksInUse--; |
@@ -633,8 +634,10 @@ struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp, | |||
633 | 634 | ||
634 | /* is page locked by the requester transaction ? */ | 635 | /* is page locked by the requester transaction ? */ |
635 | tlck = lid_to_tlock(lid); | 636 | tlck = lid_to_tlock(lid); |
636 | if ((xtid = tlck->tid) == tid) | 637 | if ((xtid = tlck->tid) == tid) { |
638 | TXN_UNLOCK(); | ||
637 | goto grantLock; | 639 | goto grantLock; |
640 | } | ||
638 | 641 | ||
639 | /* | 642 | /* |
640 | * is page locked by anonymous transaction/lock ? | 643 | * is page locked by anonymous transaction/lock ? |
@@ -649,6 +652,7 @@ struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp, | |||
649 | */ | 652 | */ |
650 | if (xtid == 0) { | 653 | if (xtid == 0) { |
651 | tlck->tid = tid; | 654 | tlck->tid = tid; |
655 | TXN_UNLOCK(); | ||
652 | tblk = tid_to_tblock(tid); | 656 | tblk = tid_to_tblock(tid); |
653 | /* | 657 | /* |
654 | * The order of the tlocks in the transaction is important | 658 | * The order of the tlocks in the transaction is important |
@@ -706,17 +710,18 @@ struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp, | |||
706 | */ | 710 | */ |
707 | tlck->tid = tid; | 711 | tlck->tid = tid; |
708 | 712 | ||
713 | TXN_UNLOCK(); | ||
714 | |||
709 | /* mark tlock for meta-data page */ | 715 | /* mark tlock for meta-data page */ |
710 | if (mp->xflag & COMMIT_PAGE) { | 716 | if (mp->xflag & COMMIT_PAGE) { |
711 | 717 | ||
712 | tlck->flag = tlckPAGELOCK; | 718 | tlck->flag = tlckPAGELOCK; |
713 | 719 | ||
714 | /* mark the page dirty and nohomeok */ | 720 | /* mark the page dirty and nohomeok */ |
715 | mark_metapage_dirty(mp); | 721 | metapage_nohomeok(mp); |
716 | atomic_inc(&mp->nohomeok); | ||
717 | 722 | ||
718 | jfs_info("locking mp = 0x%p, nohomeok = %d tid = %d tlck = 0x%p", | 723 | jfs_info("locking mp = 0x%p, nohomeok = %d tid = %d tlck = 0x%p", |
719 | mp, atomic_read(&mp->nohomeok), tid, tlck); | 724 | mp, mp->nohomeok, tid, tlck); |
720 | 725 | ||
721 | /* if anonymous transaction, and buffer is on the group | 726 | /* if anonymous transaction, and buffer is on the group |
722 | * commit synclist, mark inode to show this. This will | 727 | * commit synclist, mark inode to show this. This will |
@@ -762,8 +767,10 @@ struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp, | |||
762 | if (tlck->next == 0) { | 767 | if (tlck->next == 0) { |
763 | /* This inode's first anonymous transaction */ | 768 | /* This inode's first anonymous transaction */ |
764 | jfs_ip->atltail = lid; | 769 | jfs_ip->atltail = lid; |
770 | TXN_LOCK(); | ||
765 | list_add_tail(&jfs_ip->anon_inode_list, | 771 | list_add_tail(&jfs_ip->anon_inode_list, |
766 | &TxAnchor.anon_list); | 772 | &TxAnchor.anon_list); |
773 | TXN_UNLOCK(); | ||
767 | } | 774 | } |
768 | } | 775 | } |
769 | 776 | ||
@@ -821,8 +828,6 @@ struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp, | |||
821 | grantLock: | 828 | grantLock: |
822 | tlck->type |= type; | 829 | tlck->type |= type; |
823 | 830 | ||
824 | TXN_UNLOCK(); | ||
825 | |||
826 | return tlck; | 831 | return tlck; |
827 | 832 | ||
828 | /* | 833 | /* |
@@ -841,11 +846,19 @@ struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp, | |||
841 | BUG(); | 846 | BUG(); |
842 | } | 847 | } |
843 | INCREMENT(stattx.waitlock); /* statistics */ | 848 | INCREMENT(stattx.waitlock); /* statistics */ |
849 | TXN_UNLOCK(); | ||
844 | release_metapage(mp); | 850 | release_metapage(mp); |
851 | TXN_LOCK(); | ||
852 | xtid = tlck->tid; /* reaquire after dropping TXN_LOCK */ | ||
845 | 853 | ||
846 | jfs_info("txLock: in waitLock, tid = %d, xtid = %d, lid = %d", | 854 | jfs_info("txLock: in waitLock, tid = %d, xtid = %d, lid = %d", |
847 | tid, xtid, lid); | 855 | tid, xtid, lid); |
848 | TXN_SLEEP_DROP_LOCK(&tid_to_tblock(xtid)->waitor); | 856 | |
857 | /* Recheck everything since dropping TXN_LOCK */ | ||
858 | if (xtid && (tlck->mp == mp) && (mp->lid == lid)) | ||
859 | TXN_SLEEP_DROP_LOCK(&tid_to_tblock(xtid)->waitor); | ||
860 | else | ||
861 | TXN_UNLOCK(); | ||
849 | jfs_info("txLock: awakened tid = %d, lid = %d", tid, lid); | 862 | jfs_info("txLock: awakened tid = %d, lid = %d", tid, lid); |
850 | 863 | ||
851 | return NULL; | 864 | return NULL; |
@@ -906,6 +919,7 @@ static void txUnlock(struct tblock * tblk) | |||
906 | struct metapage *mp; | 919 | struct metapage *mp; |
907 | struct jfs_log *log; | 920 | struct jfs_log *log; |
908 | int difft, diffp; | 921 | int difft, diffp; |
922 | unsigned long flags; | ||
909 | 923 | ||
910 | jfs_info("txUnlock: tblk = 0x%p", tblk); | 924 | jfs_info("txUnlock: tblk = 0x%p", tblk); |
911 | log = JFS_SBI(tblk->sb)->log; | 925 | log = JFS_SBI(tblk->sb)->log; |
@@ -925,19 +939,14 @@ static void txUnlock(struct tblock * tblk) | |||
925 | assert(mp->xflag & COMMIT_PAGE); | 939 | assert(mp->xflag & COMMIT_PAGE); |
926 | 940 | ||
927 | /* hold buffer | 941 | /* hold buffer |
928 | * | ||
929 | * It's possible that someone else has the metapage. | ||
930 | * The only things were changing are nohomeok, which | ||
931 | * is handled atomically, and clsn which is protected | ||
932 | * by the LOGSYNC_LOCK. | ||
933 | */ | 942 | */ |
934 | hold_metapage(mp, 1); | 943 | hold_metapage(mp); |
935 | 944 | ||
936 | assert(atomic_read(&mp->nohomeok) > 0); | 945 | assert(mp->nohomeok > 0); |
937 | atomic_dec(&mp->nohomeok); | 946 | _metapage_homeok(mp); |
938 | 947 | ||
939 | /* inherit younger/larger clsn */ | 948 | /* inherit younger/larger clsn */ |
940 | LOGSYNC_LOCK(log); | 949 | LOGSYNC_LOCK(log, flags); |
941 | if (mp->clsn) { | 950 | if (mp->clsn) { |
942 | logdiff(difft, tblk->clsn, log); | 951 | logdiff(difft, tblk->clsn, log); |
943 | logdiff(diffp, mp->clsn, log); | 952 | logdiff(diffp, mp->clsn, log); |
@@ -945,16 +954,11 @@ static void txUnlock(struct tblock * tblk) | |||
945 | mp->clsn = tblk->clsn; | 954 | mp->clsn = tblk->clsn; |
946 | } else | 955 | } else |
947 | mp->clsn = tblk->clsn; | 956 | mp->clsn = tblk->clsn; |
948 | LOGSYNC_UNLOCK(log); | 957 | LOGSYNC_UNLOCK(log, flags); |
949 | 958 | ||
950 | assert(!(tlck->flag & tlckFREEPAGE)); | 959 | assert(!(tlck->flag & tlckFREEPAGE)); |
951 | 960 | ||
952 | if (tlck->flag & tlckWRITEPAGE) { | 961 | put_metapage(mp); |
953 | write_metapage(mp); | ||
954 | } else { | ||
955 | /* release page which has been forced */ | ||
956 | release_metapage(mp); | ||
957 | } | ||
958 | } | 962 | } |
959 | 963 | ||
960 | /* insert tlock, and linelock(s) of the tlock if any, | 964 | /* insert tlock, and linelock(s) of the tlock if any, |
@@ -981,10 +985,10 @@ static void txUnlock(struct tblock * tblk) | |||
981 | * has been inserted in logsync list at txUpdateMap()) | 985 | * has been inserted in logsync list at txUpdateMap()) |
982 | */ | 986 | */ |
983 | if (tblk->lsn) { | 987 | if (tblk->lsn) { |
984 | LOGSYNC_LOCK(log); | 988 | LOGSYNC_LOCK(log, flags); |
985 | log->count--; | 989 | log->count--; |
986 | list_del(&tblk->synclist); | 990 | list_del(&tblk->synclist); |
987 | LOGSYNC_UNLOCK(log); | 991 | LOGSYNC_UNLOCK(log, flags); |
988 | } | 992 | } |
989 | } | 993 | } |
990 | 994 | ||
@@ -1573,8 +1577,8 @@ static int dataLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, | |||
1573 | * the last entry, so don't bother logging this | 1577 | * the last entry, so don't bother logging this |
1574 | */ | 1578 | */ |
1575 | mp->lid = 0; | 1579 | mp->lid = 0; |
1576 | hold_metapage(mp, 0); | 1580 | grab_metapage(mp); |
1577 | atomic_dec(&mp->nohomeok); | 1581 | metapage_homeok(mp); |
1578 | discard_metapage(mp); | 1582 | discard_metapage(mp); |
1579 | tlck->mp = NULL; | 1583 | tlck->mp = NULL; |
1580 | return 0; | 1584 | return 0; |
@@ -2270,7 +2274,8 @@ void txForce(struct tblock * tblk) | |||
2270 | tlck->flag &= ~tlckWRITEPAGE; | 2274 | tlck->flag &= ~tlckWRITEPAGE; |
2271 | 2275 | ||
2272 | /* do not release page to freelist */ | 2276 | /* do not release page to freelist */ |
2273 | 2277 | force_metapage(mp); | |
2278 | #if 0 | ||
2274 | /* | 2279 | /* |
2275 | * The "right" thing to do here is to | 2280 | * The "right" thing to do here is to |
2276 | * synchronously write the metadata. | 2281 | * synchronously write the metadata. |
@@ -2282,9 +2287,10 @@ void txForce(struct tblock * tblk) | |||
2282 | * we can get by with synchronously writing | 2287 | * we can get by with synchronously writing |
2283 | * the pages when they are released. | 2288 | * the pages when they are released. |
2284 | */ | 2289 | */ |
2285 | assert(atomic_read(&mp->nohomeok)); | 2290 | assert(mp->nohomeok); |
2286 | set_bit(META_dirty, &mp->flag); | 2291 | set_bit(META_dirty, &mp->flag); |
2287 | set_bit(META_sync, &mp->flag); | 2292 | set_bit(META_sync, &mp->flag); |
2293 | #endif | ||
2288 | } | 2294 | } |
2289 | } | 2295 | } |
2290 | } | 2296 | } |
@@ -2344,7 +2350,7 @@ static void txUpdateMap(struct tblock * tblk) | |||
2344 | */ | 2350 | */ |
2345 | mp = tlck->mp; | 2351 | mp = tlck->mp; |
2346 | ASSERT(mp->xflag & COMMIT_PAGE); | 2352 | ASSERT(mp->xflag & COMMIT_PAGE); |
2347 | hold_metapage(mp, 0); | 2353 | grab_metapage(mp); |
2348 | } | 2354 | } |
2349 | 2355 | ||
2350 | /* | 2356 | /* |
@@ -2394,8 +2400,8 @@ static void txUpdateMap(struct tblock * tblk) | |||
2394 | ASSERT(mp->lid == lid); | 2400 | ASSERT(mp->lid == lid); |
2395 | tlck->mp->lid = 0; | 2401 | tlck->mp->lid = 0; |
2396 | } | 2402 | } |
2397 | assert(atomic_read(&mp->nohomeok) == 1); | 2403 | assert(mp->nohomeok == 1); |
2398 | atomic_dec(&mp->nohomeok); | 2404 | metapage_homeok(mp); |
2399 | discard_metapage(mp); | 2405 | discard_metapage(mp); |
2400 | tlck->mp = NULL; | 2406 | tlck->mp = NULL; |
2401 | } | 2407 | } |
@@ -2861,24 +2867,9 @@ static void LogSyncRelease(struct metapage * mp) | |||
2861 | { | 2867 | { |
2862 | struct jfs_log *log = mp->log; | 2868 | struct jfs_log *log = mp->log; |
2863 | 2869 | ||
2864 | assert(atomic_read(&mp->nohomeok)); | 2870 | assert(mp->nohomeok); |
2865 | assert(log); | 2871 | assert(log); |
2866 | atomic_dec(&mp->nohomeok); | 2872 | metapage_homeok(mp); |
2867 | |||
2868 | if (atomic_read(&mp->nohomeok)) | ||
2869 | return; | ||
2870 | |||
2871 | hold_metapage(mp, 0); | ||
2872 | |||
2873 | LOGSYNC_LOCK(log); | ||
2874 | mp->log = NULL; | ||
2875 | mp->lsn = 0; | ||
2876 | mp->clsn = 0; | ||
2877 | log->count--; | ||
2878 | list_del_init(&mp->synclist); | ||
2879 | LOGSYNC_UNLOCK(log); | ||
2880 | |||
2881 | release_metapage(mp); | ||
2882 | } | 2873 | } |
2883 | 2874 | ||
2884 | /* | 2875 | /* |
diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c index f31a9e3f3fec..5cf91785b541 100644 --- a/fs/jfs/jfs_umount.c +++ b/fs/jfs/jfs_umount.c | |||
@@ -49,7 +49,6 @@ | |||
49 | */ | 49 | */ |
50 | int jfs_umount(struct super_block *sb) | 50 | int jfs_umount(struct super_block *sb) |
51 | { | 51 | { |
52 | struct address_space *bdev_mapping = sb->s_bdev->bd_inode->i_mapping; | ||
53 | struct jfs_sb_info *sbi = JFS_SBI(sb); | 52 | struct jfs_sb_info *sbi = JFS_SBI(sb); |
54 | struct inode *ipbmap = sbi->ipbmap; | 53 | struct inode *ipbmap = sbi->ipbmap; |
55 | struct inode *ipimap = sbi->ipimap; | 54 | struct inode *ipimap = sbi->ipimap; |
@@ -109,8 +108,8 @@ int jfs_umount(struct super_block *sb) | |||
109 | * Make sure all metadata makes it to disk before we mark | 108 | * Make sure all metadata makes it to disk before we mark |
110 | * the superblock as clean | 109 | * the superblock as clean |
111 | */ | 110 | */ |
112 | filemap_fdatawrite(bdev_mapping); | 111 | filemap_fdatawrite(sbi->direct_inode->i_mapping); |
113 | filemap_fdatawait(bdev_mapping); | 112 | filemap_fdatawait(sbi->direct_inode->i_mapping); |
114 | 113 | ||
115 | /* | 114 | /* |
116 | * ensure all file system file pages are propagated to their | 115 | * ensure all file system file pages are propagated to their |
@@ -123,9 +122,6 @@ int jfs_umount(struct super_block *sb) | |||
123 | if (log) { /* log = NULL if read-only mount */ | 122 | if (log) { /* log = NULL if read-only mount */ |
124 | updateSuper(sb, FM_CLEAN); | 123 | updateSuper(sb, FM_CLEAN); |
125 | 124 | ||
126 | /* Restore default gfp_mask for bdev */ | ||
127 | mapping_set_gfp_mask(bdev_mapping, GFP_USER); | ||
128 | |||
129 | /* | 125 | /* |
130 | * close log: | 126 | * close log: |
131 | * | 127 | * |
@@ -140,7 +136,6 @@ int jfs_umount(struct super_block *sb) | |||
140 | 136 | ||
141 | int jfs_umount_rw(struct super_block *sb) | 137 | int jfs_umount_rw(struct super_block *sb) |
142 | { | 138 | { |
143 | struct address_space *bdev_mapping = sb->s_bdev->bd_inode->i_mapping; | ||
144 | struct jfs_sb_info *sbi = JFS_SBI(sb); | 139 | struct jfs_sb_info *sbi = JFS_SBI(sb); |
145 | struct jfs_log *log = sbi->log; | 140 | struct jfs_log *log = sbi->log; |
146 | 141 | ||
@@ -166,13 +161,10 @@ int jfs_umount_rw(struct super_block *sb) | |||
166 | * mark the superblock clean before everything is flushed to | 161 | * mark the superblock clean before everything is flushed to |
167 | * disk. | 162 | * disk. |
168 | */ | 163 | */ |
169 | filemap_fdatawrite(bdev_mapping); | 164 | filemap_fdatawrite(sbi->direct_inode->i_mapping); |
170 | filemap_fdatawait(bdev_mapping); | 165 | filemap_fdatawait(sbi->direct_inode->i_mapping); |
171 | 166 | ||
172 | updateSuper(sb, FM_CLEAN); | 167 | updateSuper(sb, FM_CLEAN); |
173 | 168 | ||
174 | /* Restore default gfp_mask for bdev */ | ||
175 | mapping_set_gfp_mask(bdev_mapping, GFP_USER); | ||
176 | |||
177 | return lmLogClose(sb); | 169 | return lmLogClose(sb); |
178 | } | 170 | } |
diff --git a/fs/jfs/resize.c b/fs/jfs/resize.c index 2eb6869b6e72..c6dc254d3253 100644 --- a/fs/jfs/resize.c +++ b/fs/jfs/resize.c | |||
@@ -209,6 +209,9 @@ int jfs_extendfs(struct super_block *sb, s64 newLVSize, int newLogSize) | |||
209 | */ | 209 | */ |
210 | txQuiesce(sb); | 210 | txQuiesce(sb); |
211 | 211 | ||
212 | /* Reset size of direct inode */ | ||
213 | sbi->direct_inode->i_size = sb->s_bdev->bd_inode->i_size; | ||
214 | |||
212 | if (sbi->mntflag & JFS_INLINELOG) { | 215 | if (sbi->mntflag & JFS_INLINELOG) { |
213 | /* | 216 | /* |
214 | * deactivate old inline log | 217 | * deactivate old inline log |
diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 5856866e24fc..0812005364a1 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c | |||
@@ -210,6 +210,10 @@ static void jfs_put_super(struct super_block *sb) | |||
210 | unload_nls(sbi->nls_tab); | 210 | unload_nls(sbi->nls_tab); |
211 | sbi->nls_tab = NULL; | 211 | sbi->nls_tab = NULL; |
212 | 212 | ||
213 | truncate_inode_pages(sbi->direct_inode->i_mapping, 0); | ||
214 | iput(sbi->direct_inode); | ||
215 | sbi->direct_inode = NULL; | ||
216 | |||
213 | kfree(sbi); | 217 | kfree(sbi); |
214 | } | 218 | } |
215 | 219 | ||
@@ -358,6 +362,12 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data) | |||
358 | } | 362 | } |
359 | 363 | ||
360 | if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) { | 364 | if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) { |
365 | /* | ||
366 | * Invalidate any previously read metadata. fsck may have | ||
367 | * changed the on-disk data since we mounted r/o | ||
368 | */ | ||
369 | truncate_inode_pages(JFS_SBI(sb)->direct_inode->i_mapping, 0); | ||
370 | |||
361 | JFS_SBI(sb)->flag = flag; | 371 | JFS_SBI(sb)->flag = flag; |
362 | return jfs_mount_rw(sb, 1); | 372 | return jfs_mount_rw(sb, 1); |
363 | } | 373 | } |
@@ -428,12 +438,26 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) | |||
428 | sb->s_op = &jfs_super_operations; | 438 | sb->s_op = &jfs_super_operations; |
429 | sb->s_export_op = &jfs_export_operations; | 439 | sb->s_export_op = &jfs_export_operations; |
430 | 440 | ||
441 | /* | ||
442 | * Initialize direct-mapping inode/address-space | ||
443 | */ | ||
444 | inode = new_inode(sb); | ||
445 | if (inode == NULL) | ||
446 | goto out_kfree; | ||
447 | inode->i_ino = 0; | ||
448 | inode->i_nlink = 1; | ||
449 | inode->i_size = sb->s_bdev->bd_inode->i_size; | ||
450 | inode->i_mapping->a_ops = &jfs_metapage_aops; | ||
451 | mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS); | ||
452 | |||
453 | sbi->direct_inode = inode; | ||
454 | |||
431 | rc = jfs_mount(sb); | 455 | rc = jfs_mount(sb); |
432 | if (rc) { | 456 | if (rc) { |
433 | if (!silent) { | 457 | if (!silent) { |
434 | jfs_err("jfs_mount failed w/return code = %d", rc); | 458 | jfs_err("jfs_mount failed w/return code = %d", rc); |
435 | } | 459 | } |
436 | goto out_kfree; | 460 | goto out_mount_failed; |
437 | } | 461 | } |
438 | if (sb->s_flags & MS_RDONLY) | 462 | if (sb->s_flags & MS_RDONLY) |
439 | sbi->log = NULL; | 463 | sbi->log = NULL; |
@@ -482,6 +506,13 @@ out_no_rw: | |||
482 | if (rc) { | 506 | if (rc) { |
483 | jfs_err("jfs_umount failed with return code %d", rc); | 507 | jfs_err("jfs_umount failed with return code %d", rc); |
484 | } | 508 | } |
509 | out_mount_failed: | ||
510 | filemap_fdatawrite(sbi->direct_inode->i_mapping); | ||
511 | filemap_fdatawait(sbi->direct_inode->i_mapping); | ||
512 | truncate_inode_pages(sbi->direct_inode->i_mapping, 0); | ||
513 | make_bad_inode(sbi->direct_inode); | ||
514 | iput(sbi->direct_inode); | ||
515 | sbi->direct_inode = NULL; | ||
485 | out_kfree: | 516 | out_kfree: |
486 | if (sbi->nls_tab) | 517 | if (sbi->nls_tab) |
487 | unload_nls(sbi->nls_tab); | 518 | unload_nls(sbi->nls_tab); |