diff options
Diffstat (limited to 'fs/ceph/inode.c')
-rw-r--r-- | fs/ceph/inode.c | 39 |
1 files changed, 22 insertions, 17 deletions
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 98b6e50bde04..602ccd8e06b7 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c | |||
@@ -352,6 +352,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb) | |||
352 | for (i = 0; i < CEPH_FILE_MODE_NUM; i++) | 352 | for (i = 0; i < CEPH_FILE_MODE_NUM; i++) |
353 | ci->i_nr_by_mode[i] = 0; | 353 | ci->i_nr_by_mode[i] = 0; |
354 | 354 | ||
355 | mutex_init(&ci->i_truncate_mutex); | ||
355 | ci->i_truncate_seq = 0; | 356 | ci->i_truncate_seq = 0; |
356 | ci->i_truncate_size = 0; | 357 | ci->i_truncate_size = 0; |
357 | ci->i_truncate_pending = 0; | 358 | ci->i_truncate_pending = 0; |
@@ -463,16 +464,20 @@ int ceph_fill_file_size(struct inode *inode, int issued, | |||
463 | dout("truncate_seq %u -> %u\n", | 464 | dout("truncate_seq %u -> %u\n", |
464 | ci->i_truncate_seq, truncate_seq); | 465 | ci->i_truncate_seq, truncate_seq); |
465 | ci->i_truncate_seq = truncate_seq; | 466 | ci->i_truncate_seq = truncate_seq; |
467 | |||
468 | /* the MDS should have revoked these caps */ | ||
469 | WARN_ON_ONCE(issued & (CEPH_CAP_FILE_EXCL | | ||
470 | CEPH_CAP_FILE_RD | | ||
471 | CEPH_CAP_FILE_WR | | ||
472 | CEPH_CAP_FILE_LAZYIO)); | ||
466 | /* | 473 | /* |
467 | * If we hold relevant caps, or in the case where we're | 474 | * If we hold relevant caps, or in the case where we're |
468 | * not the only client referencing this file and we | 475 | * not the only client referencing this file and we |
469 | * don't hold those caps, then we need to check whether | 476 | * don't hold those caps, then we need to check whether |
470 | * the file is either opened or mmaped | 477 | * the file is either opened or mmaped |
471 | */ | 478 | */ |
472 | if ((issued & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_RD| | 479 | if ((issued & (CEPH_CAP_FILE_CACHE| |
473 | CEPH_CAP_FILE_WR|CEPH_CAP_FILE_BUFFER| | 480 | CEPH_CAP_FILE_BUFFER)) || |
474 | CEPH_CAP_FILE_EXCL| | ||
475 | CEPH_CAP_FILE_LAZYIO)) || | ||
476 | mapping_mapped(inode->i_mapping) || | 481 | mapping_mapped(inode->i_mapping) || |
477 | __ceph_caps_file_wanted(ci)) { | 482 | __ceph_caps_file_wanted(ci)) { |
478 | ci->i_truncate_pending++; | 483 | ci->i_truncate_pending++; |
@@ -1427,18 +1432,20 @@ static void ceph_invalidate_work(struct work_struct *work) | |||
1427 | u32 orig_gen; | 1432 | u32 orig_gen; |
1428 | int check = 0; | 1433 | int check = 0; |
1429 | 1434 | ||
1435 | mutex_lock(&ci->i_truncate_mutex); | ||
1430 | spin_lock(&ci->i_ceph_lock); | 1436 | spin_lock(&ci->i_ceph_lock); |
1431 | dout("invalidate_pages %p gen %d revoking %d\n", inode, | 1437 | dout("invalidate_pages %p gen %d revoking %d\n", inode, |
1432 | ci->i_rdcache_gen, ci->i_rdcache_revoking); | 1438 | ci->i_rdcache_gen, ci->i_rdcache_revoking); |
1433 | if (ci->i_rdcache_revoking != ci->i_rdcache_gen) { | 1439 | if (ci->i_rdcache_revoking != ci->i_rdcache_gen) { |
1434 | /* nevermind! */ | 1440 | /* nevermind! */ |
1435 | spin_unlock(&ci->i_ceph_lock); | 1441 | spin_unlock(&ci->i_ceph_lock); |
1442 | mutex_unlock(&ci->i_truncate_mutex); | ||
1436 | goto out; | 1443 | goto out; |
1437 | } | 1444 | } |
1438 | orig_gen = ci->i_rdcache_gen; | 1445 | orig_gen = ci->i_rdcache_gen; |
1439 | spin_unlock(&ci->i_ceph_lock); | 1446 | spin_unlock(&ci->i_ceph_lock); |
1440 | 1447 | ||
1441 | truncate_inode_pages(&inode->i_data, 0); | 1448 | truncate_inode_pages(inode->i_mapping, 0); |
1442 | 1449 | ||
1443 | spin_lock(&ci->i_ceph_lock); | 1450 | spin_lock(&ci->i_ceph_lock); |
1444 | if (orig_gen == ci->i_rdcache_gen && | 1451 | if (orig_gen == ci->i_rdcache_gen && |
@@ -1453,6 +1460,7 @@ static void ceph_invalidate_work(struct work_struct *work) | |||
1453 | ci->i_rdcache_revoking); | 1460 | ci->i_rdcache_revoking); |
1454 | } | 1461 | } |
1455 | spin_unlock(&ci->i_ceph_lock); | 1462 | spin_unlock(&ci->i_ceph_lock); |
1463 | mutex_unlock(&ci->i_truncate_mutex); | ||
1456 | 1464 | ||
1457 | if (check) | 1465 | if (check) |
1458 | ceph_check_caps(ci, 0, NULL); | 1466 | ceph_check_caps(ci, 0, NULL); |
@@ -1473,16 +1481,7 @@ static void ceph_vmtruncate_work(struct work_struct *work) | |||
1473 | struct inode *inode = &ci->vfs_inode; | 1481 | struct inode *inode = &ci->vfs_inode; |
1474 | 1482 | ||
1475 | dout("vmtruncate_work %p\n", inode); | 1483 | dout("vmtruncate_work %p\n", inode); |
1476 | if (!mutex_trylock(&inode->i_mutex)) { | ||
1477 | /* | ||
1478 | * the i_mutex can be hold by a writer who is waiting for | ||
1479 | * caps. wake up waiters, they will do pending vmtruncate. | ||
1480 | */ | ||
1481 | wake_up_all(&ci->i_cap_wq); | ||
1482 | mutex_lock(&inode->i_mutex); | ||
1483 | } | ||
1484 | __ceph_do_pending_vmtruncate(inode); | 1484 | __ceph_do_pending_vmtruncate(inode); |
1485 | mutex_unlock(&inode->i_mutex); | ||
1486 | iput(inode); | 1485 | iput(inode); |
1487 | } | 1486 | } |
1488 | 1487 | ||
@@ -1515,11 +1514,13 @@ void __ceph_do_pending_vmtruncate(struct inode *inode) | |||
1515 | u64 to; | 1514 | u64 to; |
1516 | int wrbuffer_refs, finish = 0; | 1515 | int wrbuffer_refs, finish = 0; |
1517 | 1516 | ||
1517 | mutex_lock(&ci->i_truncate_mutex); | ||
1518 | retry: | 1518 | retry: |
1519 | spin_lock(&ci->i_ceph_lock); | 1519 | spin_lock(&ci->i_ceph_lock); |
1520 | if (ci->i_truncate_pending == 0) { | 1520 | if (ci->i_truncate_pending == 0) { |
1521 | dout("__do_pending_vmtruncate %p none pending\n", inode); | 1521 | dout("__do_pending_vmtruncate %p none pending\n", inode); |
1522 | spin_unlock(&ci->i_ceph_lock); | 1522 | spin_unlock(&ci->i_ceph_lock); |
1523 | mutex_unlock(&ci->i_truncate_mutex); | ||
1523 | return; | 1524 | return; |
1524 | } | 1525 | } |
1525 | 1526 | ||
@@ -1536,6 +1537,9 @@ retry: | |||
1536 | goto retry; | 1537 | goto retry; |
1537 | } | 1538 | } |
1538 | 1539 | ||
1540 | /* there should be no reader or writer */ | ||
1541 | WARN_ON_ONCE(ci->i_rd_ref || ci->i_wr_ref); | ||
1542 | |||
1539 | to = ci->i_truncate_size; | 1543 | to = ci->i_truncate_size; |
1540 | wrbuffer_refs = ci->i_wrbuffer_ref; | 1544 | wrbuffer_refs = ci->i_wrbuffer_ref; |
1541 | dout("__do_pending_vmtruncate %p (%d) to %lld\n", inode, | 1545 | dout("__do_pending_vmtruncate %p (%d) to %lld\n", inode, |
@@ -1553,6 +1557,8 @@ retry: | |||
1553 | if (!finish) | 1557 | if (!finish) |
1554 | goto retry; | 1558 | goto retry; |
1555 | 1559 | ||
1560 | mutex_unlock(&ci->i_truncate_mutex); | ||
1561 | |||
1556 | if (wrbuffer_refs == 0) | 1562 | if (wrbuffer_refs == 0) |
1557 | ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL); | 1563 | ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL); |
1558 | 1564 | ||
@@ -1601,8 +1607,6 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) | |||
1601 | if (ceph_snap(inode) != CEPH_NOSNAP) | 1607 | if (ceph_snap(inode) != CEPH_NOSNAP) |
1602 | return -EROFS; | 1608 | return -EROFS; |
1603 | 1609 | ||
1604 | __ceph_do_pending_vmtruncate(inode); | ||
1605 | |||
1606 | err = inode_change_ok(inode, attr); | 1610 | err = inode_change_ok(inode, attr); |
1607 | if (err != 0) | 1611 | if (err != 0) |
1608 | return err; | 1612 | return err; |
@@ -1783,7 +1787,8 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) | |||
1783 | ceph_cap_string(dirtied), mask); | 1787 | ceph_cap_string(dirtied), mask); |
1784 | 1788 | ||
1785 | ceph_mdsc_put_request(req); | 1789 | ceph_mdsc_put_request(req); |
1786 | __ceph_do_pending_vmtruncate(inode); | 1790 | if (mask & CEPH_SETATTR_SIZE) |
1791 | __ceph_do_pending_vmtruncate(inode); | ||
1787 | return err; | 1792 | return err; |
1788 | out: | 1793 | out: |
1789 | spin_unlock(&ci->i_ceph_lock); | 1794 | spin_unlock(&ci->i_ceph_lock); |