mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-29 17:25:38 +00:00
gfs2 fixes
- Fix filesystem block deallocation for short writes.
- Stop using glock holder auto-demotion for now.
- Get rid of buffered writes inefficiencies due to page
faults being disabled.
- Minor other cleanups.
-----BEGIN PGP SIGNATURE-----
iQJIBAABCAAyFiEEJZs3krPW0xkhLMTc1b+f6wMTZToFAmJ+wL4UHGFncnVlbmJh
QHJlZGhhdC5jb20ACgkQ1b+f6wMTZTqNkRAAuBc4oJ3Wkp/dkfF6MDY9DXqCzhQo
TodFIdEQvOUtncYBljE6DZQ9MT1sRvwxDe0nIjErFQzHYcW88zczILWOBRhrhlci
kANL6JtjSvtE3kecvR9I3nZX44aDETJliV3FX8n7vDSNMTIwjzW38d0XmDLX9t8F
bTEFv3rKsUzgcGaxpeQe7mzoQPi910WFPO/pos2ghuZwB1QEpdBrCESz4XB+OwKM
+V+8nooHvYp8T+2AzrBM6hBgsYelrBPRXlz6cYEjWY2FQuvQk/thX+zO2dvXCsPA
uNWJTCKJEsufWflPNI2ugZ9TVneIU1umGACoEHteeRvG6Qsg6K4Kf0EJEFf6Y0Tg
PKUJLUcdi0suS8UuUCBTAVAgCv9+ueLhIbbFeRkbHjxSjET7NQl2gbkfY2V1RsFt
yNFLMGU01xsb1YylncY4xQc9WVMDbPsdv1KGDF75njchuHZXhfg00ezPQys4Uy5R
0EUwqoPYNePV6VsoHLbU+kImf936VawP916yDiyflyz6UFSi5vNg7SwMqDrXpIxM
T8nNgrTC+Npv7T2xc8JhSFGv9T86nZXWjQTpDzV8onPvxdCLCT1cmm352aHqXd7+
wY9ZFJZ4iMoinYUkEzgySQW00+wK/AThQKQ6ImhLEvwxMUc6dJUnesVGkzLDGh9Z
KSfqgYzmlb2YdKY=
=FJq+
-----END PGP SIGNATURE-----
Merge tag 'gfs2-v5.18-rc4-fix3' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2
Pull gfs2 fixes from Andreas Gruenbacher:
"We've finally identified commit dc732906c2
("gfs2: Introduce flag
for glock holder auto-demotion") to be the other cause of the
filesystem corruption we've been seeing. This feature isn't strictly
necessary anymore, so we've decided to stop using it for now.
With this and the gfs_iomap_end rounding fix you've already seen
("gfs2: Fix filesystem block deallocation for short writes" in this
pull request), we're corruption free again now.
- Fix filesystem block deallocation for short writes.
- Stop using glock holder auto-demotion for now.
- Get rid of buffered writes inefficiencies due to page faults being
disabled.
- Minor other cleanups"
* tag 'gfs2-v5.18-rc4-fix3' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2:
gfs2: Stop using glock holder auto-demotion for now
gfs2: buffered write prefaulting
gfs2: Align read and write chunks to the page cache
gfs2: Pull return value test out of should_fault_in_pages
gfs2: Clean up use of fault_in_iov_iter_{read,write}able
gfs2: Variable rename
gfs2: Fix filesystem block deallocation for short writes
This commit is contained in:
commit
d928e8f3af
@ -1153,13 +1153,12 @@ static int gfs2_iomap_end(struct inode *inode, loff_t pos, loff_t length,
|
||||
|
||||
if (length != written && (iomap->flags & IOMAP_F_NEW)) {
|
||||
/* Deallocate blocks that were just allocated. */
|
||||
loff_t blockmask = i_blocksize(inode) - 1;
|
||||
loff_t end = (pos + length) & ~blockmask;
|
||||
loff_t hstart = round_up(pos + written, i_blocksize(inode));
|
||||
loff_t hend = iomap->offset + iomap->length;
|
||||
|
||||
pos = (pos + written + blockmask) & ~blockmask;
|
||||
if (pos < end) {
|
||||
truncate_pagecache_range(inode, pos, end - 1);
|
||||
punch_hole(ip, pos, end - pos);
|
||||
if (hstart < hend) {
|
||||
truncate_pagecache_range(inode, hstart, hend - 1);
|
||||
punch_hole(ip, hstart, hend - hstart);
|
||||
}
|
||||
}
|
||||
|
||||
|
143
fs/gfs2/file.c
143
fs/gfs2/file.c
@ -770,30 +770,27 @@ static int gfs2_fsync(struct file *file, loff_t start, loff_t end,
|
||||
return ret ? ret : ret1;
|
||||
}
|
||||
|
||||
static inline bool should_fault_in_pages(ssize_t ret, struct iov_iter *i,
|
||||
static inline bool should_fault_in_pages(struct iov_iter *i,
|
||||
struct kiocb *iocb,
|
||||
size_t *prev_count,
|
||||
size_t *window_size)
|
||||
{
|
||||
size_t count = iov_iter_count(i);
|
||||
size_t size, offs;
|
||||
|
||||
if (likely(!count))
|
||||
return false;
|
||||
if (ret <= 0 && ret != -EFAULT)
|
||||
if (!count)
|
||||
return false;
|
||||
if (!iter_is_iovec(i))
|
||||
return false;
|
||||
|
||||
size = PAGE_SIZE;
|
||||
offs = offset_in_page(i->iov[0].iov_base + i->iov_offset);
|
||||
offs = offset_in_page(iocb->ki_pos);
|
||||
if (*prev_count != count || !*window_size) {
|
||||
size_t nr_dirtied;
|
||||
|
||||
size = ALIGN(offs + count, PAGE_SIZE);
|
||||
size = min_t(size_t, size, SZ_1M);
|
||||
nr_dirtied = max(current->nr_dirtied_pause -
|
||||
current->nr_dirtied, 8);
|
||||
size = min(size, nr_dirtied << PAGE_SHIFT);
|
||||
size = min_t(size_t, SZ_1M, nr_dirtied << PAGE_SHIFT);
|
||||
}
|
||||
|
||||
*prev_count = count;
|
||||
@ -807,7 +804,7 @@ static ssize_t gfs2_file_direct_read(struct kiocb *iocb, struct iov_iter *to,
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
|
||||
size_t prev_count = 0, window_size = 0;
|
||||
size_t written = 0;
|
||||
size_t read = 0;
|
||||
ssize_t ret;
|
||||
|
||||
/*
|
||||
@ -835,35 +832,31 @@ static ssize_t gfs2_file_direct_read(struct kiocb *iocb, struct iov_iter *to,
|
||||
ret = gfs2_glock_nq(gh);
|
||||
if (ret)
|
||||
goto out_uninit;
|
||||
retry_under_glock:
|
||||
pagefault_disable();
|
||||
to->nofault = true;
|
||||
ret = iomap_dio_rw(iocb, to, &gfs2_iomap_ops, NULL,
|
||||
IOMAP_DIO_PARTIAL, written);
|
||||
IOMAP_DIO_PARTIAL, read);
|
||||
to->nofault = false;
|
||||
pagefault_enable();
|
||||
if (ret <= 0 && ret != -EFAULT)
|
||||
goto out_unlock;
|
||||
if (ret > 0)
|
||||
written = ret;
|
||||
read = ret;
|
||||
|
||||
if (should_fault_in_pages(ret, to, &prev_count, &window_size)) {
|
||||
size_t leftover;
|
||||
|
||||
gfs2_holder_allow_demote(gh);
|
||||
leftover = fault_in_iov_iter_writeable(to, window_size);
|
||||
gfs2_holder_disallow_demote(gh);
|
||||
if (leftover != window_size) {
|
||||
if (gfs2_holder_queued(gh))
|
||||
goto retry_under_glock;
|
||||
if (should_fault_in_pages(to, iocb, &prev_count, &window_size)) {
|
||||
gfs2_glock_dq(gh);
|
||||
window_size -= fault_in_iov_iter_writeable(to, window_size);
|
||||
if (window_size)
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
out_unlock:
|
||||
if (gfs2_holder_queued(gh))
|
||||
gfs2_glock_dq(gh);
|
||||
out_uninit:
|
||||
gfs2_holder_uninit(gh);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return written;
|
||||
return read;
|
||||
}
|
||||
|
||||
static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from,
|
||||
@ -873,7 +866,7 @@ static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from,
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
struct gfs2_inode *ip = GFS2_I(inode);
|
||||
size_t prev_count = 0, window_size = 0;
|
||||
size_t read = 0;
|
||||
size_t written = 0;
|
||||
ssize_t ret;
|
||||
|
||||
/*
|
||||
@ -901,39 +894,35 @@ static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from,
|
||||
goto out_uninit;
|
||||
/* Silently fall back to buffered I/O when writing beyond EOF */
|
||||
if (iocb->ki_pos + iov_iter_count(from) > i_size_read(&ip->i_inode))
|
||||
goto out;
|
||||
retry_under_glock:
|
||||
goto out_unlock;
|
||||
|
||||
from->nofault = true;
|
||||
ret = iomap_dio_rw(iocb, from, &gfs2_iomap_ops, NULL,
|
||||
IOMAP_DIO_PARTIAL, read);
|
||||
IOMAP_DIO_PARTIAL, written);
|
||||
from->nofault = false;
|
||||
|
||||
if (ret == -ENOTBLK)
|
||||
ret = 0;
|
||||
if (ret > 0)
|
||||
read = ret;
|
||||
|
||||
if (should_fault_in_pages(ret, from, &prev_count, &window_size)) {
|
||||
size_t leftover;
|
||||
|
||||
gfs2_holder_allow_demote(gh);
|
||||
leftover = fault_in_iov_iter_readable(from, window_size);
|
||||
gfs2_holder_disallow_demote(gh);
|
||||
if (leftover != window_size) {
|
||||
if (gfs2_holder_queued(gh))
|
||||
goto retry_under_glock;
|
||||
goto retry;
|
||||
}
|
||||
if (ret <= 0) {
|
||||
if (ret == -ENOTBLK)
|
||||
ret = 0;
|
||||
if (ret != -EFAULT)
|
||||
goto out_unlock;
|
||||
}
|
||||
out:
|
||||
if (ret > 0)
|
||||
written = ret;
|
||||
|
||||
if (should_fault_in_pages(from, iocb, &prev_count, &window_size)) {
|
||||
gfs2_glock_dq(gh);
|
||||
window_size -= fault_in_iov_iter_readable(from, window_size);
|
||||
if (window_size)
|
||||
goto retry;
|
||||
}
|
||||
out_unlock:
|
||||
if (gfs2_holder_queued(gh))
|
||||
gfs2_glock_dq(gh);
|
||||
out_uninit:
|
||||
gfs2_holder_uninit(gh);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return read;
|
||||
return written;
|
||||
}
|
||||
|
||||
static ssize_t gfs2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||
@ -941,7 +930,7 @@ static ssize_t gfs2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||
struct gfs2_inode *ip;
|
||||
struct gfs2_holder gh;
|
||||
size_t prev_count = 0, window_size = 0;
|
||||
size_t written = 0;
|
||||
size_t read = 0;
|
||||
ssize_t ret;
|
||||
|
||||
/*
|
||||
@ -962,7 +951,7 @@ static ssize_t gfs2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||
if (ret >= 0) {
|
||||
if (!iov_iter_count(to))
|
||||
return ret;
|
||||
written = ret;
|
||||
read = ret;
|
||||
} else if (ret != -EFAULT) {
|
||||
if (ret != -EAGAIN)
|
||||
return ret;
|
||||
@ -975,30 +964,26 @@ static ssize_t gfs2_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
|
||||
ret = gfs2_glock_nq(&gh);
|
||||
if (ret)
|
||||
goto out_uninit;
|
||||
retry_under_glock:
|
||||
pagefault_disable();
|
||||
ret = generic_file_read_iter(iocb, to);
|
||||
pagefault_enable();
|
||||
if (ret <= 0 && ret != -EFAULT)
|
||||
goto out_unlock;
|
||||
if (ret > 0)
|
||||
written += ret;
|
||||
read += ret;
|
||||
|
||||
if (should_fault_in_pages(ret, to, &prev_count, &window_size)) {
|
||||
size_t leftover;
|
||||
|
||||
gfs2_holder_allow_demote(&gh);
|
||||
leftover = fault_in_iov_iter_writeable(to, window_size);
|
||||
gfs2_holder_disallow_demote(&gh);
|
||||
if (leftover != window_size) {
|
||||
if (gfs2_holder_queued(&gh))
|
||||
goto retry_under_glock;
|
||||
if (should_fault_in_pages(to, iocb, &prev_count, &window_size)) {
|
||||
gfs2_glock_dq(&gh);
|
||||
window_size -= fault_in_iov_iter_writeable(to, window_size);
|
||||
if (window_size)
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
out_unlock:
|
||||
if (gfs2_holder_queued(&gh))
|
||||
gfs2_glock_dq(&gh);
|
||||
out_uninit:
|
||||
gfs2_holder_uninit(&gh);
|
||||
return written ? written : ret;
|
||||
return read ? read : ret;
|
||||
}
|
||||
|
||||
static ssize_t gfs2_file_buffered_write(struct kiocb *iocb,
|
||||
@ -1012,7 +997,7 @@ static ssize_t gfs2_file_buffered_write(struct kiocb *iocb,
|
||||
struct gfs2_holder *statfs_gh = NULL;
|
||||
size_t prev_count = 0, window_size = 0;
|
||||
size_t orig_count = iov_iter_count(from);
|
||||
size_t read = 0;
|
||||
size_t written = 0;
|
||||
ssize_t ret;
|
||||
|
||||
/*
|
||||
@ -1030,10 +1015,18 @@ static ssize_t gfs2_file_buffered_write(struct kiocb *iocb,
|
||||
|
||||
gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, gh);
|
||||
retry:
|
||||
if (should_fault_in_pages(from, iocb, &prev_count, &window_size)) {
|
||||
window_size -= fault_in_iov_iter_readable(from, window_size);
|
||||
if (!window_size) {
|
||||
ret = -EFAULT;
|
||||
goto out_uninit;
|
||||
}
|
||||
from->count = min(from->count, window_size);
|
||||
}
|
||||
ret = gfs2_glock_nq(gh);
|
||||
if (ret)
|
||||
goto out_uninit;
|
||||
retry_under_glock:
|
||||
|
||||
if (inode == sdp->sd_rindex) {
|
||||
struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
|
||||
|
||||
@ -1050,25 +1043,19 @@ static ssize_t gfs2_file_buffered_write(struct kiocb *iocb,
|
||||
current->backing_dev_info = NULL;
|
||||
if (ret > 0) {
|
||||
iocb->ki_pos += ret;
|
||||
read += ret;
|
||||
written += ret;
|
||||
}
|
||||
|
||||
if (inode == sdp->sd_rindex)
|
||||
gfs2_glock_dq_uninit(statfs_gh);
|
||||
|
||||
from->count = orig_count - read;
|
||||
if (should_fault_in_pages(ret, from, &prev_count, &window_size)) {
|
||||
size_t leftover;
|
||||
if (ret <= 0 && ret != -EFAULT)
|
||||
goto out_unlock;
|
||||
|
||||
gfs2_holder_allow_demote(gh);
|
||||
leftover = fault_in_iov_iter_readable(from, window_size);
|
||||
gfs2_holder_disallow_demote(gh);
|
||||
if (leftover != window_size) {
|
||||
from->count = min(from->count, window_size - leftover);
|
||||
if (gfs2_holder_queued(gh))
|
||||
goto retry_under_glock;
|
||||
goto retry;
|
||||
}
|
||||
from->count = orig_count - written;
|
||||
if (should_fault_in_pages(from, iocb, &prev_count, &window_size)) {
|
||||
gfs2_glock_dq(gh);
|
||||
goto retry;
|
||||
}
|
||||
out_unlock:
|
||||
if (gfs2_holder_queued(gh))
|
||||
@ -1077,8 +1064,8 @@ static ssize_t gfs2_file_buffered_write(struct kiocb *iocb,
|
||||
gfs2_holder_uninit(gh);
|
||||
if (statfs_gh)
|
||||
kfree(statfs_gh);
|
||||
from->count = orig_count - read;
|
||||
return read ? read : ret;
|
||||
from->count = orig_count - written;
|
||||
return written ? written : ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user