Commit 93ce9358 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'davidh' (fixes from David Howells)

Merge misc fixes from David Howells:
 "A set of patches for watch_queue filter issues noted by Jann. I've
  added in a cleanup patch from Christophe Jaillet to convert to using
  formal bitmap specifiers for the note allocation bitmap.

  Also two filesystem fixes (afs and cachefiles)"

* emailed patches from David Howells <dhowells@redhat.com>:
  cachefiles: Fix volume coherency attribute
  afs: Fix potential thrashing in afs writeback
  watch_queue: Make comment about setting ->defunct more accurate
  watch_queue: Fix lack of barrier/sync/lock between post and read
  watch_queue: Free the alloc bitmap when the watch_queue is torn down
  watch_queue: Fix the alloc bitmap size to reflect notes allocated
  watch_queue: Use the bitmap API when applicable
  watch_queue: Fix to always request a pow-of-2 pipe ring size
  watch_queue: Fix to release page in ->release()
  watch_queue, pipe: Free watchqueue state after clearing pipe ring
  watch_queue: Fix filter limit check
parents 79b00034 413a4a6b
...@@ -703,7 +703,7 @@ static int afs_writepages_region(struct address_space *mapping, ...@@ -703,7 +703,7 @@ static int afs_writepages_region(struct address_space *mapping,
struct folio *folio; struct folio *folio;
struct page *head_page; struct page *head_page;
ssize_t ret; ssize_t ret;
int n; int n, skips = 0;
_enter("%llx,%llx,", start, end); _enter("%llx,%llx,", start, end);
...@@ -754,8 +754,15 @@ static int afs_writepages_region(struct address_space *mapping, ...@@ -754,8 +754,15 @@ static int afs_writepages_region(struct address_space *mapping,
#ifdef CONFIG_AFS_FSCACHE #ifdef CONFIG_AFS_FSCACHE
folio_wait_fscache(folio); folio_wait_fscache(folio);
#endif #endif
} else {
start += folio_size(folio);
} }
folio_put(folio); folio_put(folio);
if (wbc->sync_mode == WB_SYNC_NONE) {
if (skips >= 5 || need_resched())
break;
skips++;
}
continue; continue;
} }
......
...@@ -28,6 +28,11 @@ struct cachefiles_xattr { ...@@ -28,6 +28,11 @@ struct cachefiles_xattr {
static const char cachefiles_xattr_cache[] = static const char cachefiles_xattr_cache[] =
XATTR_USER_PREFIX "CacheFiles.cache"; XATTR_USER_PREFIX "CacheFiles.cache";
struct cachefiles_vol_xattr {
__be32 reserved; /* Reserved, should be 0 */
__u8 data[]; /* netfs volume coherency data */
} __packed;
/* /*
* set the state xattr on a cache file * set the state xattr on a cache file
*/ */
...@@ -185,6 +190,7 @@ void cachefiles_prepare_to_write(struct fscache_cookie *cookie) ...@@ -185,6 +190,7 @@ void cachefiles_prepare_to_write(struct fscache_cookie *cookie)
*/ */
bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume) bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume)
{ {
struct cachefiles_vol_xattr *buf;
unsigned int len = volume->vcookie->coherency_len; unsigned int len = volume->vcookie->coherency_len;
const void *p = volume->vcookie->coherency; const void *p = volume->vcookie->coherency;
struct dentry *dentry = volume->dentry; struct dentry *dentry = volume->dentry;
...@@ -192,10 +198,17 @@ bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume) ...@@ -192,10 +198,17 @@ bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume)
_enter("%x,#%d", volume->vcookie->debug_id, len); _enter("%x,#%d", volume->vcookie->debug_id, len);
len += sizeof(*buf);
buf = kmalloc(len, GFP_KERNEL);
if (!buf)
return false;
buf->reserved = cpu_to_be32(0);
memcpy(buf->data, p, len);
ret = cachefiles_inject_write_error(); ret = cachefiles_inject_write_error();
if (ret == 0) if (ret == 0)
ret = vfs_setxattr(&init_user_ns, dentry, cachefiles_xattr_cache, ret = vfs_setxattr(&init_user_ns, dentry, cachefiles_xattr_cache,
p, len, 0); buf, len, 0);
if (ret < 0) { if (ret < 0) {
trace_cachefiles_vfs_error(NULL, d_inode(dentry), ret, trace_cachefiles_vfs_error(NULL, d_inode(dentry), ret,
cachefiles_trace_setxattr_error); cachefiles_trace_setxattr_error);
...@@ -209,6 +222,7 @@ bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume) ...@@ -209,6 +222,7 @@ bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume)
cachefiles_coherency_vol_set_ok); cachefiles_coherency_vol_set_ok);
} }
kfree(buf);
_leave(" = %d", ret); _leave(" = %d", ret);
return ret == 0; return ret == 0;
} }
...@@ -218,7 +232,7 @@ bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume) ...@@ -218,7 +232,7 @@ bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume)
*/ */
int cachefiles_check_volume_xattr(struct cachefiles_volume *volume) int cachefiles_check_volume_xattr(struct cachefiles_volume *volume)
{ {
struct cachefiles_xattr *buf; struct cachefiles_vol_xattr *buf;
struct dentry *dentry = volume->dentry; struct dentry *dentry = volume->dentry;
unsigned int len = volume->vcookie->coherency_len; unsigned int len = volume->vcookie->coherency_len;
const void *p = volume->vcookie->coherency; const void *p = volume->vcookie->coherency;
...@@ -228,6 +242,7 @@ int cachefiles_check_volume_xattr(struct cachefiles_volume *volume) ...@@ -228,6 +242,7 @@ int cachefiles_check_volume_xattr(struct cachefiles_volume *volume)
_enter(""); _enter("");
len += sizeof(*buf);
buf = kmalloc(len, GFP_KERNEL); buf = kmalloc(len, GFP_KERNEL);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
...@@ -245,7 +260,9 @@ int cachefiles_check_volume_xattr(struct cachefiles_volume *volume) ...@@ -245,7 +260,9 @@ int cachefiles_check_volume_xattr(struct cachefiles_volume *volume)
"Failed to read xattr with error %zd", xlen); "Failed to read xattr with error %zd", xlen);
} }
why = cachefiles_coherency_vol_check_xattr; why = cachefiles_coherency_vol_check_xattr;
} else if (memcmp(buf->data, p, len) != 0) { } else if (buf->reserved != cpu_to_be32(0)) {
why = cachefiles_coherency_vol_check_resv;
} else if (memcmp(buf->data, p, len - sizeof(*buf)) != 0) {
why = cachefiles_coherency_vol_check_cmp; why = cachefiles_coherency_vol_check_cmp;
} else { } else {
why = cachefiles_coherency_vol_check_ok; why = cachefiles_coherency_vol_check_ok;
......
...@@ -253,7 +253,8 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to) ...@@ -253,7 +253,8 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to)
*/ */
was_full = pipe_full(pipe->head, pipe->tail, pipe->max_usage); was_full = pipe_full(pipe->head, pipe->tail, pipe->max_usage);
for (;;) { for (;;) {
unsigned int head = pipe->head; /* Read ->head with a barrier vs post_one_notification() */
unsigned int head = smp_load_acquire(&pipe->head);
unsigned int tail = pipe->tail; unsigned int tail = pipe->tail;
unsigned int mask = pipe->ring_size - 1; unsigned int mask = pipe->ring_size - 1;
...@@ -831,10 +832,8 @@ void free_pipe_info(struct pipe_inode_info *pipe) ...@@ -831,10 +832,8 @@ void free_pipe_info(struct pipe_inode_info *pipe)
int i; int i;
#ifdef CONFIG_WATCH_QUEUE #ifdef CONFIG_WATCH_QUEUE
if (pipe->watch_queue) { if (pipe->watch_queue)
watch_queue_clear(pipe->watch_queue); watch_queue_clear(pipe->watch_queue);
put_watch_queue(pipe->watch_queue);
}
#endif #endif
(void) account_pipe_buffers(pipe->user, pipe->nr_accounted, 0); (void) account_pipe_buffers(pipe->user, pipe->nr_accounted, 0);
...@@ -844,6 +843,10 @@ void free_pipe_info(struct pipe_inode_info *pipe) ...@@ -844,6 +843,10 @@ void free_pipe_info(struct pipe_inode_info *pipe)
if (buf->ops) if (buf->ops)
pipe_buf_release(pipe, buf); pipe_buf_release(pipe, buf);
} }
#ifdef CONFIG_WATCH_QUEUE
if (pipe->watch_queue)
put_watch_queue(pipe->watch_queue);
#endif
if (pipe->tmp_page) if (pipe->tmp_page)
__free_page(pipe->tmp_page); __free_page(pipe->tmp_page);
kfree(pipe->bufs); kfree(pipe->bufs);
......
...@@ -28,7 +28,8 @@ struct watch_type_filter { ...@@ -28,7 +28,8 @@ struct watch_type_filter {
struct watch_filter { struct watch_filter {
union { union {
struct rcu_head rcu; struct rcu_head rcu;
unsigned long type_filter[2]; /* Bitmask of accepted types */ /* Bitmask of accepted types */
DECLARE_BITMAP(type_filter, WATCH_TYPE__NR);
}; };
u32 nr_filters; /* Number of filters */ u32 nr_filters; /* Number of filters */
struct watch_type_filter filters[]; struct watch_type_filter filters[];
......
...@@ -56,6 +56,7 @@ enum cachefiles_coherency_trace { ...@@ -56,6 +56,7 @@ enum cachefiles_coherency_trace {
cachefiles_coherency_set_ok, cachefiles_coherency_set_ok,
cachefiles_coherency_vol_check_cmp, cachefiles_coherency_vol_check_cmp,
cachefiles_coherency_vol_check_ok, cachefiles_coherency_vol_check_ok,
cachefiles_coherency_vol_check_resv,
cachefiles_coherency_vol_check_xattr, cachefiles_coherency_vol_check_xattr,
cachefiles_coherency_vol_set_fail, cachefiles_coherency_vol_set_fail,
cachefiles_coherency_vol_set_ok, cachefiles_coherency_vol_set_ok,
...@@ -139,6 +140,7 @@ enum cachefiles_error_trace { ...@@ -139,6 +140,7 @@ enum cachefiles_error_trace {
EM(cachefiles_coherency_set_ok, "SET ok ") \ EM(cachefiles_coherency_set_ok, "SET ok ") \
EM(cachefiles_coherency_vol_check_cmp, "VOL BAD cmp ") \ EM(cachefiles_coherency_vol_check_cmp, "VOL BAD cmp ") \
EM(cachefiles_coherency_vol_check_ok, "VOL OK ") \ EM(cachefiles_coherency_vol_check_ok, "VOL OK ") \
EM(cachefiles_coherency_vol_check_resv, "VOL BAD resv") \
EM(cachefiles_coherency_vol_check_xattr,"VOL BAD xatt") \ EM(cachefiles_coherency_vol_check_xattr,"VOL BAD xatt") \
EM(cachefiles_coherency_vol_set_fail, "VOL SET fail") \ EM(cachefiles_coherency_vol_set_fail, "VOL SET fail") \
E_(cachefiles_coherency_vol_set_ok, "VOL SET ok ") E_(cachefiles_coherency_vol_set_ok, "VOL SET ok ")
......
...@@ -54,6 +54,7 @@ static void watch_queue_pipe_buf_release(struct pipe_inode_info *pipe, ...@@ -54,6 +54,7 @@ static void watch_queue_pipe_buf_release(struct pipe_inode_info *pipe,
bit += page->index; bit += page->index;
set_bit(bit, wqueue->notes_bitmap); set_bit(bit, wqueue->notes_bitmap);
generic_pipe_buf_release(pipe, buf);
} }
// No try_steal function => no stealing // No try_steal function => no stealing
...@@ -112,7 +113,7 @@ static bool post_one_notification(struct watch_queue *wqueue, ...@@ -112,7 +113,7 @@ static bool post_one_notification(struct watch_queue *wqueue,
buf->offset = offset; buf->offset = offset;
buf->len = len; buf->len = len;
buf->flags = PIPE_BUF_FLAG_WHOLE; buf->flags = PIPE_BUF_FLAG_WHOLE;
pipe->head = head + 1; smp_store_release(&pipe->head, head + 1); /* vs pipe_read() */
if (!test_and_clear_bit(note, wqueue->notes_bitmap)) { if (!test_and_clear_bit(note, wqueue->notes_bitmap)) {
spin_unlock_irq(&pipe->rd_wait.lock); spin_unlock_irq(&pipe->rd_wait.lock);
...@@ -219,7 +220,6 @@ long watch_queue_set_size(struct pipe_inode_info *pipe, unsigned int nr_notes) ...@@ -219,7 +220,6 @@ long watch_queue_set_size(struct pipe_inode_info *pipe, unsigned int nr_notes)
struct page **pages; struct page **pages;
unsigned long *bitmap; unsigned long *bitmap;
unsigned long user_bufs; unsigned long user_bufs;
unsigned int bmsize;
int ret, i, nr_pages; int ret, i, nr_pages;
if (!wqueue) if (!wqueue)
...@@ -243,7 +243,8 @@ long watch_queue_set_size(struct pipe_inode_info *pipe, unsigned int nr_notes) ...@@ -243,7 +243,8 @@ long watch_queue_set_size(struct pipe_inode_info *pipe, unsigned int nr_notes)
goto error; goto error;
} }
ret = pipe_resize_ring(pipe, nr_notes); nr_notes = nr_pages * WATCH_QUEUE_NOTES_PER_PAGE;
ret = pipe_resize_ring(pipe, roundup_pow_of_two(nr_notes));
if (ret < 0) if (ret < 0)
goto error; goto error;
...@@ -258,17 +259,15 @@ long watch_queue_set_size(struct pipe_inode_info *pipe, unsigned int nr_notes) ...@@ -258,17 +259,15 @@ long watch_queue_set_size(struct pipe_inode_info *pipe, unsigned int nr_notes)
pages[i]->index = i * WATCH_QUEUE_NOTES_PER_PAGE; pages[i]->index = i * WATCH_QUEUE_NOTES_PER_PAGE;
} }
bmsize = (nr_notes + BITS_PER_LONG - 1) / BITS_PER_LONG; bitmap = bitmap_alloc(nr_notes, GFP_KERNEL);
bmsize *= sizeof(unsigned long);
bitmap = kmalloc(bmsize, GFP_KERNEL);
if (!bitmap) if (!bitmap)
goto error_p; goto error_p;
memset(bitmap, 0xff, bmsize); bitmap_fill(bitmap, nr_notes);
wqueue->notes = pages; wqueue->notes = pages;
wqueue->notes_bitmap = bitmap; wqueue->notes_bitmap = bitmap;
wqueue->nr_pages = nr_pages; wqueue->nr_pages = nr_pages;
wqueue->nr_notes = nr_pages * WATCH_QUEUE_NOTES_PER_PAGE; wqueue->nr_notes = nr_notes;
return 0; return 0;
error_p: error_p:
...@@ -320,7 +319,7 @@ long watch_queue_set_filter(struct pipe_inode_info *pipe, ...@@ -320,7 +319,7 @@ long watch_queue_set_filter(struct pipe_inode_info *pipe,
tf[i].info_mask & WATCH_INFO_LENGTH) tf[i].info_mask & WATCH_INFO_LENGTH)
goto err_filter; goto err_filter;
/* Ignore any unknown types */ /* Ignore any unknown types */
if (tf[i].type >= sizeof(wfilter->type_filter) * 8) if (tf[i].type >= WATCH_TYPE__NR)
continue; continue;
nr_filter++; nr_filter++;
} }
...@@ -336,7 +335,7 @@ long watch_queue_set_filter(struct pipe_inode_info *pipe, ...@@ -336,7 +335,7 @@ long watch_queue_set_filter(struct pipe_inode_info *pipe,
q = wfilter->filters; q = wfilter->filters;
for (i = 0; i < filter.nr_filters; i++) { for (i = 0; i < filter.nr_filters; i++) {
if (tf[i].type >= sizeof(wfilter->type_filter) * BITS_PER_LONG) if (tf[i].type >= WATCH_TYPE__NR)
continue; continue;
q->type = tf[i].type; q->type = tf[i].type;
...@@ -371,6 +370,7 @@ static void __put_watch_queue(struct kref *kref) ...@@ -371,6 +370,7 @@ static void __put_watch_queue(struct kref *kref)
for (i = 0; i < wqueue->nr_pages; i++) for (i = 0; i < wqueue->nr_pages; i++)
__free_page(wqueue->notes[i]); __free_page(wqueue->notes[i]);
bitmap_free(wqueue->notes_bitmap);
wfilter = rcu_access_pointer(wqueue->filter); wfilter = rcu_access_pointer(wqueue->filter);
if (wfilter) if (wfilter)
...@@ -566,7 +566,7 @@ void watch_queue_clear(struct watch_queue *wqueue) ...@@ -566,7 +566,7 @@ void watch_queue_clear(struct watch_queue *wqueue)
rcu_read_lock(); rcu_read_lock();
spin_lock_bh(&wqueue->lock); spin_lock_bh(&wqueue->lock);
/* Prevent new additions and prevent notifications from happening */ /* Prevent new notifications from being stored. */
wqueue->defunct = true; wqueue->defunct = true;
while (!hlist_empty(&wqueue->watches)) { while (!hlist_empty(&wqueue->watches)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment