Skip to content

Commit 2e78c92

Browse files
Chandan Rajendrakdave
authored andcommitted
Btrfs: __btrfs_buffered_write: Reserve/release extents aligned to block size
Currently, the code reserves/releases extents in multiples of PAGE_CACHE_SIZE units. Fix this by doing reservation/releases in block size units. Signed-off-by: Chandan Rajendra <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent e410e34 commit 2e78c92

File tree

2 files changed

+33
-13
lines changed

2 files changed

+33
-13
lines changed

fs/btrfs/ctree.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2353,6 +2353,9 @@ struct btrfs_map_token {
23532353
unsigned long offset;
23542354
};
23552355

2356+
#define BTRFS_BYTES_TO_BLKS(fs_info, bytes) \
2357+
((bytes) >> (fs_info)->sb->s_blocksize_bits)
2358+
23562359
static inline void btrfs_init_map_token (struct btrfs_map_token *token)
23572360
{
23582361
token->kaddr = NULL;

fs/btrfs/file.c

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ int btrfs_dirty_pages(struct btrfs_root *root, struct inode *inode,
498498
loff_t isize = i_size_read(inode);
499499

500500
start_pos = pos & ~((u64)root->sectorsize - 1);
501-
num_bytes = ALIGN(write_bytes + pos - start_pos, root->sectorsize);
501+
num_bytes = round_up(write_bytes + pos - start_pos, root->sectorsize);
502502

503503
end_of_last_block = start_pos + num_bytes - 1;
504504
err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block,
@@ -1379,16 +1379,19 @@ static noinline int prepare_pages(struct inode *inode, struct page **pages,
13791379
static noinline int
13801380
lock_and_cleanup_extent_if_need(struct inode *inode, struct page **pages,
13811381
size_t num_pages, loff_t pos,
1382+
size_t write_bytes,
13821383
u64 *lockstart, u64 *lockend,
13831384
struct extent_state **cached_state)
13841385
{
1386+
struct btrfs_root *root = BTRFS_I(inode)->root;
13851387
u64 start_pos;
13861388
u64 last_pos;
13871389
int i;
13881390
int ret = 0;
13891391

1390-
start_pos = pos & ~((u64)PAGE_CACHE_SIZE - 1);
1391-
last_pos = start_pos + ((u64)num_pages << PAGE_CACHE_SHIFT) - 1;
1392+
start_pos = round_down(pos, root->sectorsize);
1393+
last_pos = start_pos
1394+
+ round_up(pos + write_bytes - start_pos, root->sectorsize) - 1;
13921395

13931396
if (start_pos < inode->i_size) {
13941397
struct btrfs_ordered_extent *ordered;
@@ -1503,6 +1506,7 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
15031506

15041507
while (iov_iter_count(i) > 0) {
15051508
size_t offset = pos & (PAGE_CACHE_SIZE - 1);
1509+
size_t sector_offset;
15061510
size_t write_bytes = min(iov_iter_count(i),
15071511
nrptrs * (size_t)PAGE_CACHE_SIZE -
15081512
offset);
@@ -1511,6 +1515,8 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
15111515
size_t reserve_bytes;
15121516
size_t dirty_pages;
15131517
size_t copied;
1518+
size_t dirty_sectors;
1519+
size_t num_sectors;
15141520

15151521
WARN_ON(num_pages > nrptrs);
15161522

@@ -1523,7 +1529,9 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
15231529
break;
15241530
}
15251531

1526-
reserve_bytes = num_pages << PAGE_CACHE_SHIFT;
1532+
sector_offset = pos & (root->sectorsize - 1);
1533+
reserve_bytes = round_up(write_bytes + sector_offset,
1534+
root->sectorsize);
15271535

15281536
if (BTRFS_I(inode)->flags & (BTRFS_INODE_NODATACOW |
15291537
BTRFS_INODE_PREALLOC)) {
@@ -1542,7 +1550,9 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
15421550
*/
15431551
num_pages = DIV_ROUND_UP(write_bytes + offset,
15441552
PAGE_CACHE_SIZE);
1545-
reserve_bytes = num_pages << PAGE_CACHE_SHIFT;
1553+
reserve_bytes = round_up(write_bytes
1554+
+ sector_offset,
1555+
root->sectorsize);
15461556
goto reserve_metadata;
15471557
}
15481558
}
@@ -1576,8 +1586,8 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
15761586
break;
15771587

15781588
ret = lock_and_cleanup_extent_if_need(inode, pages, num_pages,
1579-
pos, &lockstart, &lockend,
1580-
&cached_state);
1589+
pos, write_bytes, &lockstart,
1590+
&lockend, &cached_state);
15811591
if (ret < 0) {
15821592
if (ret == -EAGAIN)
15831593
goto again;
@@ -1612,9 +1622,16 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
16121622
* we still have an outstanding extent for the chunk we actually
16131623
* managed to copy.
16141624
*/
1615-
if (num_pages > dirty_pages) {
1616-
release_bytes = (num_pages - dirty_pages) <<
1617-
PAGE_CACHE_SHIFT;
1625+
num_sectors = BTRFS_BYTES_TO_BLKS(root->fs_info,
1626+
reserve_bytes);
1627+
dirty_sectors = round_up(copied + sector_offset,
1628+
root->sectorsize);
1629+
dirty_sectors = BTRFS_BYTES_TO_BLKS(root->fs_info,
1630+
dirty_sectors);
1631+
1632+
if (num_sectors > dirty_sectors) {
1633+
release_bytes = (write_bytes - copied)
1634+
& ~((u64)root->sectorsize - 1);
16181635
if (copied > 0) {
16191636
spin_lock(&BTRFS_I(inode)->lock);
16201637
BTRFS_I(inode)->outstanding_extents++;
@@ -1633,7 +1650,8 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
16331650
}
16341651
}
16351652

1636-
release_bytes = dirty_pages << PAGE_CACHE_SHIFT;
1653+
release_bytes = round_up(copied + sector_offset,
1654+
root->sectorsize);
16371655

16381656
if (copied > 0)
16391657
ret = btrfs_dirty_pages(root, inode, pages,
@@ -1654,8 +1672,7 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
16541672

16551673
if (only_release_metadata && copied > 0) {
16561674
lockstart = round_down(pos, root->sectorsize);
1657-
lockend = lockstart +
1658-
(dirty_pages << PAGE_CACHE_SHIFT) - 1;
1675+
lockend = round_up(pos + copied, root->sectorsize) - 1;
16591676

16601677
set_extent_bit(&BTRFS_I(inode)->io_tree, lockstart,
16611678
lockend, EXTENT_NORESERVE, NULL,

0 commit comments

Comments
 (0)