Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

gfs2: Fix data loss during inode evict

When gfs2_evict_inode() is called on an inode with unwritten data in the
page cache, the page cache needs to be written before it can be
truncated. This doesn't always happen. Fix that by changing
gfs2_evict_inode() to always either call evict_linked_inode() or
evict_unlinked_inode().

Inside evict_unlinked_inode(), first check if the inode is dirty. If it
is, make sure the inode glock is held and write back the data and
metadata. If it isn't, skip those steps.

Also, make sure that gfs2_evict_inode() calls gfs2_evict_inode() and
evict_unlinked_inode() only if ip->i_gl is not NULL; this avoids
unnecessary complications there.

Fixes xfstest generic/211.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>

+28 -8
+28 -8
fs/gfs2/super.c
··· 1241 1241 struct gfs2_sbd *sdp = sb->s_fs_info; 1242 1242 int ret; 1243 1243 1244 + if (inode->i_nlink) 1245 + return EVICT_SHOULD_SKIP_DELETE; 1246 + 1244 1247 if (gfs2_holder_initialized(&ip->i_iopen_gh) && 1245 1248 test_bit(GLF_DEFER_DELETE, &ip->i_iopen_gh.gh_gl->gl_flags)) 1246 1249 return EVICT_SHOULD_DEFER_DELETE; ··· 1282 1279 /** 1283 1280 * evict_unlinked_inode - delete the pieces of an unlinked evicted inode 1284 1281 * @inode: The inode to evict 1282 + * @gh: The glock holder structure 1285 1283 */ 1286 - static int evict_unlinked_inode(struct inode *inode) 1284 + static int evict_unlinked_inode(struct inode *inode, struct gfs2_holder *gh) 1287 1285 { 1288 1286 struct gfs2_inode *ip = GFS2_I(inode); 1289 1287 struct gfs2_glock *gl = ip->i_gl; 1290 1288 int ret; 1289 + 1290 + /* The inode glock must be held exclusively and be instantiated. */ 1291 + BUG_ON(!gfs2_holder_initialized(gh) || 1292 + test_bit(GLF_INSTANTIATE_NEEDED, &gl->gl_flags)); 1291 1293 1292 1294 if (S_ISDIR(inode->i_mode) && 1293 1295 (ip->i_diskflags & GFS2_DIF_EXHASH)) { ··· 1326 1318 */ 1327 1319 1328 1320 ret = gfs2_dinode_dealloc(ip); 1329 - if (!ret && gl) 1321 + if (!ret) 1330 1322 gfs2_inode_remember_delete(gl, ip->i_no_formal_ino); 1331 1323 1332 1324 out: ··· 1365 1357 /* 1366 1358 * evict_linked_inode - evict an inode whose dinode has not been unlinked 1367 1359 * @inode: The inode to evict 1360 + * @gh: The glock holder structure 1368 1361 */ 1369 - static int evict_linked_inode(struct inode *inode) 1362 + static int evict_linked_inode(struct inode *inode, struct gfs2_holder *gh) 1370 1363 { 1371 1364 struct super_block *sb = inode->i_sb; 1372 1365 struct gfs2_sbd *sdp = sb->s_fs_info; 1373 1366 struct gfs2_inode *ip = GFS2_I(inode); 1374 1367 struct gfs2_glock *gl = ip->i_gl; 1375 - struct address_space *metamapping; 1368 + struct address_space *metamapping = gfs2_glock2aspace(gl); 1376 1369 int ret; 1370 + 1371 + if (!(test_bit(GLF_DIRTY, &gl->gl_flags) || inode->i_flags & I_DIRTY)) 1372 + goto clean; 1373 + 1374 + /* The inode glock must be held exclusively and be instantiated. */ 1375 + if (!gfs2_holder_initialized(gh)) 1376 + ret = gfs2_glock_nq_init(gl, LM_ST_EXCLUSIVE, 0, gh); 1377 + else 1378 + ret = gfs2_instantiate(gh); 1379 + if (ret) 1380 + return ret; 1377 1381 1378 1382 gfs2_log_flush(sdp, gl, GFS2_LOG_HEAD_FLUSH_NORMAL | 1379 1383 GFS2_LFC_EVICT_INODE); 1380 - metamapping = gfs2_glock2aspace(gl); 1381 1384 if (test_bit(GLF_DIRTY, &gl->gl_flags)) { 1382 1385 filemap_fdatawrite(metamapping); 1383 1386 filemap_fdatawait(metamapping); ··· 1396 1377 write_inode_now(inode, 1); 1397 1378 gfs2_ail_flush(gl, 0); 1398 1379 1380 + clean: 1399 1381 ret = gfs2_truncate_inode_pages(inode); 1400 1382 if (ret) 1401 1383 return ret; ··· 1435 1415 int ret; 1436 1416 1437 1417 gfs2_holder_mark_uninitialized(&gh); 1438 - if (inode->i_nlink || sb_rdonly(sb) || !ip->i_no_addr) 1418 + if (sb_rdonly(sb) || !ip->i_no_addr || !ip->i_gl) 1439 1419 goto out; 1440 1420 1441 1421 /* ··· 1460 1440 behavior = EVICT_SHOULD_SKIP_DELETE; 1461 1441 } 1462 1442 if (behavior == EVICT_SHOULD_DELETE) 1463 - ret = evict_unlinked_inode(inode); 1443 + ret = evict_unlinked_inode(inode, &gh); 1464 1444 else 1465 - ret = evict_linked_inode(inode); 1445 + ret = evict_linked_inode(inode, &gh); 1466 1446 1467 1447 if (gfs2_rs_active(&ip->i_res)) 1468 1448 gfs2_rs_deltree(&ip->i_res);