Skip to content

Commit 2e06589

Browse files
dhowellsbrauner
authored andcommitted
netfs: Fix i_size updating
Fix the updating of i_size, particularly in regard to the completion of DIO writes and especially async DIO writes by using a lock. The bug is triggered occasionally by the generic/207 xfstest as it chucks a bunch of AIO DIO writes at the filesystem and then checks that fstat() returns a reasonable st_size as each completes. The problem is that netfs is trying to do "if new_size > inode->i_size, update inode->i_size" sort of thing but without a lock around it. This can be seen with cifs, but shouldn't be seen with kafs because kafs serialises modification ops on the client whereas cifs sends the requests to the server as they're generated and lets the server order them. Fixes: 153a996 ("netfs: Implement unbuffered/DIO write support") Signed-off-by: David Howells <[email protected]> Link: https://lore.kernel.org/[email protected] Reviewed-by: Paulo Alcantara (Red Hat) <[email protected]> cc: Steve French <[email protected]> cc: Paulo Alcantara <[email protected]> cc: [email protected] cc: [email protected] cc: [email protected] Signed-off-by: Christian Brauner <[email protected]>
1 parent 74ee76b commit 2e06589

File tree

2 files changed

+8
-2
lines changed

2 files changed

+8
-2
lines changed

fs/netfs/buffered_write.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ static void netfs_update_i_size(struct netfs_inode *ctx, struct inode *inode,
6464
return;
6565
}
6666

67+
spin_lock(&inode->i_lock);
6768
i_size_write(inode, pos);
6869
#if IS_ENABLED(CONFIG_FSCACHE)
6970
fscache_update_cookie(ctx->cache, NULL, &pos);
@@ -77,6 +78,7 @@ static void netfs_update_i_size(struct netfs_inode *ctx, struct inode *inode,
7778
DIV_ROUND_UP(pos, SECTOR_SIZE),
7879
inode->i_blocks + add);
7980
}
81+
spin_unlock(&inode->i_lock);
8082
}
8183

8284
/**

fs/netfs/direct_write.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,17 @@ static void netfs_cleanup_dio_write(struct netfs_io_request *wreq)
1414
struct inode *inode = wreq->inode;
1515
unsigned long long end = wreq->start + wreq->transferred;
1616

17-
if (!wreq->error &&
18-
i_size_read(inode) < end) {
17+
if (wreq->error || end <= i_size_read(inode))
18+
return;
19+
20+
spin_lock(&inode->i_lock);
21+
if (end > i_size_read(inode)) {
1922
if (wreq->netfs_ops->update_i_size)
2023
wreq->netfs_ops->update_i_size(inode, end);
2124
else
2225
i_size_write(inode, end);
2326
}
27+
spin_unlock(&inode->i_lock);
2428
}
2529

2630
/*

0 commit comments

Comments
 (0)