mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-06-04 02:42:45 -04:00
Merge tag 'vfs-7.1-rc5.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull vfs fixes from Christian Brauner: "This contains a fixes for the current development cycle. Note that AI related review sometimes delays fixes a bit because we find more fixes for the fixes. I might try and send smaller but more fixes PRs if this trend keeps up. - Fix various netfslib bugs - Fix an out-of-bounds write when listing idmappings - Fix the return values in jfs_mkdir() and orangefs_mkdir() - Fix a writeback writeback array overflow in fuse - Fix a forced iversion increment on lazytime timestamp updates - Reject a negative timeval component in kern_select() - Fix error return when vfs_mkdir() fails in the cachefiles code - Fix wrong error code returned for pidns ioctls" * tag 'vfs-7.1-rc5.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (31 commits) cachefiles: Fix error return when vfs_mkdir() fails afs: Fix the locking used by afs_get_link() netfs, afs: Fix write skipping in dir/link writepages netfs: Fix netfs_read_folio() to wait on writeback netfs: Fix folio->private handling in netfs_perform_write() netfs: Fix partial invalidation of streaming-write folio netfs: Fix potential UAF in netfs_unlock_abandoned_read_pages() netfs: Fix leak of request in netfs_write_begin() error handling netfs: Fix early put of sink folio in netfs_read_gaps() netfs: Fix write streaming disablement if fd open O_RDWR netfs: Fix read-gaps to remove netfs_folio from filled folio netfs: Fix potential deadlock in write-through mode netfs: Fix streaming write being overwritten netfs: Defer the emission of trace_netfs_folio() netfs: Fix netfs_invalidate_folio() to clear dirty bit if all changes gone netfs: Fix overrun check in netfs_extract_user_iter() netfs: fix error handling in netfs_extract_user_iter() netfs: Fix potential uninitialised var in netfs_extract_user_iter() netfs: fix VM_BUG_ON_FOLIO() issue in netfs_write_begin() call netfs: Fix zeropoint update where i_size > remote_i_size ...
This commit is contained in:
@@ -191,6 +191,29 @@ static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
||||
__list_add(new, head->prev, head);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add_tail_release - add a new entry with release barrier
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it before
|
||||
*
|
||||
* Insert a new entry before the specified head, using a release barrier to set
|
||||
* the ->next pointer that points to it. This is useful for implementing
|
||||
* queues, in particular one that the elements will be walked through forwards
|
||||
* locklessly.
|
||||
*/
|
||||
static inline void list_add_tail_release(struct list_head *new,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct list_head *prev = head->prev;
|
||||
|
||||
if (__list_add_valid(new, prev, head)) {
|
||||
new->next = head;
|
||||
new->prev = prev;
|
||||
head->prev = new;
|
||||
smp_store_release(&prev->next, new);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a list entry by making the prev/next entries
|
||||
* point to each other.
|
||||
@@ -644,6 +667,20 @@ static inline void list_splice_tail_init(struct list_head *list,
|
||||
pos__ != head__ ? list_entry(pos__, type, member) : NULL; \
|
||||
})
|
||||
|
||||
/**
|
||||
* list_first_entry_or_null_acquire - get the first element from a list with barrier
|
||||
* @ptr: the list head to take the element from.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Note that if the list is empty, it returns NULL.
|
||||
*/
|
||||
#define list_first_entry_or_null_acquire(ptr, type, member) ({ \
|
||||
struct list_head *head__ = (ptr); \
|
||||
struct list_head *pos__ = smp_load_acquire(&head__->next); \
|
||||
pos__ != head__ ? list_entry(pos__, type, member) : NULL; \
|
||||
})
|
||||
|
||||
/**
|
||||
* list_last_entry_or_null - get the last element from a list
|
||||
* @ptr: the list head to take the element from.
|
||||
|
||||
@@ -62,8 +62,8 @@ struct netfs_inode {
|
||||
struct fscache_cookie *cache;
|
||||
#endif
|
||||
struct mutex wb_lock; /* Writeback serialisation */
|
||||
loff_t remote_i_size; /* Size of the remote file */
|
||||
loff_t zero_point; /* Size after which we assume there's no data
|
||||
loff_t _remote_i_size; /* Size of the remote file */
|
||||
loff_t _zero_point; /* Size after which we assume there's no data
|
||||
* on the server */
|
||||
atomic_t io_count; /* Number of outstanding reqs */
|
||||
unsigned long flags;
|
||||
@@ -252,7 +252,7 @@ struct netfs_io_request {
|
||||
unsigned long long collected_to; /* Point we've collected to */
|
||||
unsigned long long cleaned_to; /* Position we've cleaned folios to */
|
||||
unsigned long long abandon_to; /* Position to abandon folios to */
|
||||
pgoff_t no_unlock_folio; /* Don't unlock this folio after read */
|
||||
const struct folio *no_unlock_folio; /* Don't unlock this folio after read */
|
||||
unsigned int direct_bv_count; /* Number of elements in direct_bv[] */
|
||||
unsigned int debug_id;
|
||||
unsigned int rsize; /* Maximum read size (0 for none) */
|
||||
@@ -474,6 +474,254 @@ static inline struct netfs_inode *netfs_inode(struct inode *inode)
|
||||
return container_of(inode, struct netfs_inode, inode);
|
||||
}
|
||||
|
||||
/**
|
||||
* netfs_read_remote_i_size - Read remote_i_size safely
|
||||
* @inode: The inode to access
|
||||
*
|
||||
* Read remote_i_size safely without the potential for tearing on 32-bit
|
||||
* arches.
|
||||
*
|
||||
* NOTE: in a 32bit arch with a preemptable kernel and an UP compile the
|
||||
* i_size_read/write must be atomic with respect to the local cpu (unlike with
|
||||
* preempt disabled), but they don't need to be atomic with respect to other
|
||||
* cpus like in true SMP (so they need either to either locally disable irq
|
||||
* around the read or for example on x86 they can be still implemented as a
|
||||
* cmpxchg8b without the need of the lock prefix). For SMP compiles and 64bit
|
||||
* archs it makes no difference if preempt is enabled or not.
|
||||
*/
|
||||
static inline unsigned long long netfs_read_remote_i_size(const struct inode *inode)
|
||||
{
|
||||
const struct netfs_inode *ictx = container_of(inode, struct netfs_inode, inode);
|
||||
unsigned long long remote_i_size;
|
||||
|
||||
#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
|
||||
unsigned int seq;
|
||||
|
||||
do {
|
||||
seq = read_seqcount_begin(&inode->i_size_seqcount);
|
||||
remote_i_size = ictx->_remote_i_size;
|
||||
} while (read_seqcount_retry(&inode->i_size_seqcount, seq));
|
||||
#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)
|
||||
preempt_disable();
|
||||
remote_i_size = ictx->_remote_i_size;
|
||||
preempt_enable();
|
||||
#else
|
||||
/* Pairs with smp_store_release() in netfs_write_remote_i_size() */
|
||||
remote_i_size = smp_load_acquire(&ictx->_remote_i_size);
|
||||
#endif
|
||||
return remote_i_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* netfs_write_remote_i_size - Set remote_i_size safely
|
||||
* @inode: The inode to access
|
||||
* @remote_i_size: The new value for the size of the file on the server
|
||||
*
|
||||
* Set remote_i_size safely without the potential for tearing on 32-bit arches.
|
||||
*
|
||||
* Context: The caller must hold inode->i_lock.
|
||||
*
|
||||
* NOTE: unlike netfs_read_remote_i_size(), netfs_write_remote_i_size() does
|
||||
* need locking around it (normally i_rwsem), otherwise on 32bit/SMP an update
|
||||
* of i_size_seqcount can be lost, resulting in subsequent i_size_read() calls
|
||||
* spinning forever.
|
||||
*/
|
||||
static inline void netfs_write_remote_i_size(struct inode *inode,
|
||||
unsigned long long remote_i_size)
|
||||
{
|
||||
struct netfs_inode *ictx = netfs_inode(inode);
|
||||
|
||||
#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
|
||||
write_seqcount_begin(&inode->i_size_seqcount);
|
||||
ictx->_remote_i_size = remote_i_size;
|
||||
write_seqcount_end(&inode->i_size_seqcount);
|
||||
#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)
|
||||
preempt_disable();
|
||||
ictx->_remote_i_size = remote_i_size;
|
||||
preempt_enable();
|
||||
#else
|
||||
/*
|
||||
* Pairs with smp_load_acquire() in netfs_read_remote_i_size() to
|
||||
* ensure changes related to inode size (such as page contents) are
|
||||
* visible before we see the changed inode size.
|
||||
*/
|
||||
smp_store_release(&ictx->_remote_i_size, remote_i_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* netfs_read_zero_point - Read zero_point safely
|
||||
* @inode: The inode to access
|
||||
*
|
||||
* Read zero_point safely without the potential for tearing on 32-bit
|
||||
* arches.
|
||||
*
|
||||
* NOTE: in a 32bit arch with a preemptable kernel and an UP compile the
|
||||
* i_size_read/write must be atomic with respect to the local cpu (unlike with
|
||||
* preempt disabled), but they don't need to be atomic with respect to other
|
||||
* cpus like in true SMP (so they need either to either locally disable irq
|
||||
* around the read or for example on x86 they can be still implemented as a
|
||||
* cmpxchg8b without the need of the lock prefix). For SMP compiles and 64bit
|
||||
* archs it makes no difference if preempt is enabled or not.
|
||||
*/
|
||||
static inline unsigned long long netfs_read_zero_point(const struct inode *inode)
|
||||
{
|
||||
struct netfs_inode *ictx = container_of(inode, struct netfs_inode, inode);
|
||||
unsigned long long zero_point;
|
||||
|
||||
#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
|
||||
unsigned int seq;
|
||||
|
||||
do {
|
||||
seq = read_seqcount_begin(&inode->i_size_seqcount);
|
||||
zero_point = ictx->_zero_point;
|
||||
} while (read_seqcount_retry(&inode->i_size_seqcount, seq));
|
||||
#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)
|
||||
preempt_disable();
|
||||
zero_point = ictx->_zero_point;
|
||||
preempt_enable();
|
||||
#else
|
||||
/* Pairs with smp_store_release() in netfs_write_zero_point() */
|
||||
zero_point = smp_load_acquire(&ictx->_zero_point);
|
||||
#endif
|
||||
return zero_point;
|
||||
}
|
||||
|
||||
/*
|
||||
* netfs_write_zero_point - Set zero_point safely
|
||||
* @inode: The inode to access
|
||||
* @zero_point: The new value for the point beyond which the server has no data
|
||||
*
|
||||
* Set zero_point safely without the potential for tearing on 32-bit arches.
|
||||
*
|
||||
* Context: The caller must hold inode->i_lock.
|
||||
*
|
||||
* NOTE: unlike netfs_read_zero_point(), netfs_write_zero_point() does need
|
||||
* locking around it (normally i_rwsem), otherwise on 32bit/SMP an update of
|
||||
* i_size_seqcount can be lost, resulting in subsequent read calls spinning
|
||||
* forever.
|
||||
*/
|
||||
static inline void netfs_write_zero_point(struct inode *inode,
|
||||
unsigned long long zero_point)
|
||||
{
|
||||
struct netfs_inode *ictx = netfs_inode(inode);
|
||||
|
||||
#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
|
||||
write_seqcount_begin(&inode->i_size_seqcount);
|
||||
ictx->_zero_point = zero_point;
|
||||
write_seqcount_end(&inode->i_size_seqcount);
|
||||
#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)
|
||||
preempt_disable();
|
||||
ictx->_zero_point = zero_point;
|
||||
preempt_enable();
|
||||
#else
|
||||
/*
|
||||
* Pairs with smp_load_acquire() in netfs_read_zero_point() to
|
||||
* ensure changes related to inode size (such as page contents) are
|
||||
* visible before we see the changed inode size.
|
||||
*/
|
||||
smp_store_release(&ictx->_zero_point, zero_point);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* netfs_read_sizes - Read remote_i_size and zero_point safely
|
||||
* @inode: The inode to access
|
||||
* @i_size: Where to return the local file size.
|
||||
* @remote_i_size: Where to return the size of the file on the server
|
||||
* @zero_point: Where to return the the point beyond which the server has no data
|
||||
*
|
||||
* Read remote_i_size and zero_point safely without the potential for tearing
|
||||
* on 32-bit arches.
|
||||
*
|
||||
* NOTE: in a 32bit arch with a preemptable kernel and an UP compile the
|
||||
* i_size_read/write must be atomic with respect to the local cpu (unlike with
|
||||
* preempt disabled), but they don't need to be atomic with respect to other
|
||||
* cpus like in true SMP (so they need either to either locally disable irq
|
||||
* around the read or for example on x86 they can be still implemented as a
|
||||
* cmpxchg8b without the need of the lock prefix). For SMP compiles and 64bit
|
||||
* archs it makes no difference if preempt is enabled or not.
|
||||
*/
|
||||
static inline void netfs_read_sizes(const struct inode *inode,
|
||||
unsigned long long *i_size,
|
||||
unsigned long long *remote_i_size,
|
||||
unsigned long long *zero_point)
|
||||
{
|
||||
const struct netfs_inode *ictx = container_of(inode, struct netfs_inode, inode);
|
||||
#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
|
||||
unsigned int seq;
|
||||
|
||||
do {
|
||||
seq = read_seqcount_begin(&inode->i_size_seqcount);
|
||||
*i_size = inode->i_size;
|
||||
*remote_i_size = ictx->_remote_i_size;
|
||||
*zero_point = ictx->_zero_point;
|
||||
} while (read_seqcount_retry(&inode->i_size_seqcount, seq));
|
||||
#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)
|
||||
preempt_disable();
|
||||
*i_size = inode->i_size;
|
||||
*remote_i_size = ictx->_remote_i_size;
|
||||
*zero_point = ictx->_zero_point;
|
||||
preempt_enable();
|
||||
#else
|
||||
/* Pairs with smp_store_release() in i_size_write() */
|
||||
*i_size = smp_load_acquire(&inode->i_size);
|
||||
/* Pairs with smp_store_release() in netfs_write_remote_i_size() */
|
||||
*remote_i_size = smp_load_acquire(&ictx->_remote_i_size);
|
||||
/* Pairs with smp_store_release() in netfs_write_zero_point() */
|
||||
*zero_point = smp_load_acquire(&ictx->_zero_point);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* netfs_write_sizes - Set i_size, remote_i_size and zero_point safely
|
||||
* @inode: The inode to access
|
||||
* @i_size: The new value for the local size of the file
|
||||
* @remote_i_size: The new value for the size of the file on the server
|
||||
* @zero_point: The new value for the point beyond which the server has no data
|
||||
*
|
||||
* Set both remote_i_size and zero_point safely without the potential for
|
||||
* tearing on 32-bit arches.
|
||||
*
|
||||
* Context: The caller must hold inode->i_lock.
|
||||
*
|
||||
* NOTE: unlike netfs_read_zero_point(), netfs_write_zero_point() does need
|
||||
* locking around it (normally i_rwsem), otherwise on 32bit/SMP an update of
|
||||
* i_size_seqcount can be lost, resulting in subsequent read calls spinning
|
||||
* forever.
|
||||
*/
|
||||
static inline void netfs_write_sizes(struct inode *inode,
|
||||
unsigned long long i_size,
|
||||
unsigned long long remote_i_size,
|
||||
unsigned long long zero_point)
|
||||
{
|
||||
struct netfs_inode *ictx = netfs_inode(inode);
|
||||
|
||||
#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
|
||||
write_seqcount_begin(&inode->i_size_seqcount);
|
||||
inode->i_size = i_size;
|
||||
ictx->_remote_i_size = remote_i_size;
|
||||
ictx->_zero_point = zero_point;
|
||||
write_seqcount_end(&inode->i_size_seqcount);
|
||||
#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)
|
||||
preempt_disable();
|
||||
inode->i_size = i_size;
|
||||
ictx->_remote_i_size = remote_i_size;
|
||||
ictx->_zero_point = zero_point;
|
||||
preempt_enable();
|
||||
#else
|
||||
/*
|
||||
* Pairs with smp_load_acquire() in i_size_read(),
|
||||
* netfs_read_remote_i_size() and netfs_read_zero_point() to ensure
|
||||
* changes related to inode size (such as page contents) are visible
|
||||
* before we see the changed inode size.
|
||||
*/
|
||||
smp_store_release(&inode->i_size, i_size);
|
||||
smp_store_release(&ictx->_remote_i_size, remote_i_size);
|
||||
smp_store_release(&ictx->_zero_point, zero_point);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* netfs_inode_init - Initialise a netfslib inode context
|
||||
* @ctx: The netfs inode to initialise
|
||||
@@ -488,8 +736,8 @@ static inline void netfs_inode_init(struct netfs_inode *ctx,
|
||||
bool use_zero_point)
|
||||
{
|
||||
ctx->ops = ops;
|
||||
ctx->remote_i_size = i_size_read(&ctx->inode);
|
||||
ctx->zero_point = LLONG_MAX;
|
||||
ctx->_remote_i_size = i_size_read(&ctx->inode);
|
||||
ctx->_zero_point = LLONG_MAX;
|
||||
ctx->flags = 0;
|
||||
atomic_set(&ctx->io_count, 0);
|
||||
#if IS_ENABLED(CONFIG_FSCACHE)
|
||||
@@ -498,7 +746,7 @@ static inline void netfs_inode_init(struct netfs_inode *ctx,
|
||||
mutex_init(&ctx->wb_lock);
|
||||
/* ->releasepage() drives zero_point */
|
||||
if (use_zero_point) {
|
||||
ctx->zero_point = ctx->remote_i_size;
|
||||
ctx->_zero_point = ctx->_remote_i_size;
|
||||
mapping_set_release_always(ctx->inode.i_mapping);
|
||||
}
|
||||
}
|
||||
@@ -511,13 +759,40 @@ static inline void netfs_inode_init(struct netfs_inode *ctx,
|
||||
*
|
||||
* Inform the netfs lib that a file got resized so that it can adjust its state.
|
||||
*/
|
||||
static inline void netfs_resize_file(struct netfs_inode *ctx, loff_t new_i_size,
|
||||
static inline void netfs_resize_file(struct netfs_inode *ictx,
|
||||
unsigned long long new_i_size,
|
||||
bool changed_on_server)
|
||||
{
|
||||
#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
|
||||
struct inode *inode = &ictx->inode;
|
||||
|
||||
preempt_disable();
|
||||
write_seqcount_begin(&inode->i_size_seqcount);
|
||||
if (changed_on_server)
|
||||
ctx->remote_i_size = new_i_size;
|
||||
if (new_i_size < ctx->zero_point)
|
||||
ctx->zero_point = new_i_size;
|
||||
ictx->_remote_i_size = new_i_size;
|
||||
if (new_i_size < ictx->_zero_point)
|
||||
ictx->_zero_point = new_i_size;
|
||||
write_seqcount_end(&inode->i_size_seqcount);
|
||||
preempt_enable();
|
||||
#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPTION)
|
||||
preempt_disable();
|
||||
if (changed_on_server)
|
||||
ictx->_remote_i_size = new_i_size;
|
||||
if (new_i_size < ictx->_zero_point)
|
||||
ictx->_zero_point = new_i_size;
|
||||
preempt_enable();
|
||||
#else
|
||||
/*
|
||||
* Pairs with smp_load_acquire() in netfs_read_remote_i_size and
|
||||
* netfs_read_zero_point() to ensure changes related to inode size
|
||||
* (such as page contents) are visible before we see the changed inode
|
||||
* size.
|
||||
*/
|
||||
if (changed_on_server)
|
||||
smp_store_release(&ictx->_remote_i_size, new_i_size);
|
||||
if (new_i_size < ictx->_zero_point)
|
||||
smp_store_release(&ictx->_zero_point, new_i_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user