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
This commit is contained in:
Коммит
93ce93587d
|
@ -703,7 +703,7 @@ static int afs_writepages_region(struct address_space *mapping,
|
|||
struct folio *folio;
|
||||
struct page *head_page;
|
||||
ssize_t ret;
|
||||
int n;
|
||||
int n, skips = 0;
|
||||
|
||||
_enter("%llx,%llx,", start, end);
|
||||
|
||||
|
@ -754,8 +754,15 @@ static int afs_writepages_region(struct address_space *mapping,
|
|||
#ifdef CONFIG_AFS_FSCACHE
|
||||
folio_wait_fscache(folio);
|
||||
#endif
|
||||
} else {
|
||||
start += folio_size(folio);
|
||||
}
|
||||
folio_put(folio);
|
||||
if (wbc->sync_mode == WB_SYNC_NONE) {
|
||||
if (skips >= 5 || need_resched())
|
||||
break;
|
||||
skips++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,11 @@ struct cachefiles_xattr {
|
|||
static const char cachefiles_xattr_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
|
||||
*/
|
||||
|
@ -185,6 +190,7 @@ void cachefiles_prepare_to_write(struct fscache_cookie *cookie)
|
|||
*/
|
||||
bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume)
|
||||
{
|
||||
struct cachefiles_vol_xattr *buf;
|
||||
unsigned int len = volume->vcookie->coherency_len;
|
||||
const void *p = volume->vcookie->coherency;
|
||||
struct dentry *dentry = volume->dentry;
|
||||
|
@ -192,10 +198,17 @@ bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume)
|
|||
|
||||
_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();
|
||||
if (ret == 0)
|
||||
ret = vfs_setxattr(&init_user_ns, dentry, cachefiles_xattr_cache,
|
||||
p, len, 0);
|
||||
buf, len, 0);
|
||||
if (ret < 0) {
|
||||
trace_cachefiles_vfs_error(NULL, d_inode(dentry), ret,
|
||||
cachefiles_trace_setxattr_error);
|
||||
|
@ -209,6 +222,7 @@ bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume)
|
|||
cachefiles_coherency_vol_set_ok);
|
||||
}
|
||||
|
||||
kfree(buf);
|
||||
_leave(" = %d", ret);
|
||||
return ret == 0;
|
||||
}
|
||||
|
@ -218,7 +232,7 @@ bool cachefiles_set_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;
|
||||
unsigned int len = volume->vcookie->coherency_len;
|
||||
const void *p = volume->vcookie->coherency;
|
||||
|
@ -228,6 +242,7 @@ int cachefiles_check_volume_xattr(struct cachefiles_volume *volume)
|
|||
|
||||
_enter("");
|
||||
|
||||
len += sizeof(*buf);
|
||||
buf = kmalloc(len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
@ -245,7 +260,9 @@ int cachefiles_check_volume_xattr(struct cachefiles_volume *volume)
|
|||
"Failed to read xattr with error %zd", xlen);
|
||||
}
|
||||
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;
|
||||
} else {
|
||||
why = cachefiles_coherency_vol_check_ok;
|
||||
|
|
11
fs/pipe.c
11
fs/pipe.c
|
@ -253,7 +253,8 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to)
|
|||
*/
|
||||
was_full = pipe_full(pipe->head, pipe->tail, pipe->max_usage);
|
||||
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 mask = pipe->ring_size - 1;
|
||||
|
||||
|
@ -831,10 +832,8 @@ void free_pipe_info(struct pipe_inode_info *pipe)
|
|||
int i;
|
||||
|
||||
#ifdef CONFIG_WATCH_QUEUE
|
||||
if (pipe->watch_queue) {
|
||||
if (pipe->watch_queue)
|
||||
watch_queue_clear(pipe->watch_queue);
|
||||
put_watch_queue(pipe->watch_queue);
|
||||
}
|
||||
#endif
|
||||
|
||||
(void) account_pipe_buffers(pipe->user, pipe->nr_accounted, 0);
|
||||
|
@ -844,6 +843,10 @@ void free_pipe_info(struct pipe_inode_info *pipe)
|
|||
if (buf->ops)
|
||||
pipe_buf_release(pipe, buf);
|
||||
}
|
||||
#ifdef CONFIG_WATCH_QUEUE
|
||||
if (pipe->watch_queue)
|
||||
put_watch_queue(pipe->watch_queue);
|
||||
#endif
|
||||
if (pipe->tmp_page)
|
||||
__free_page(pipe->tmp_page);
|
||||
kfree(pipe->bufs);
|
||||
|
|
|
@ -28,7 +28,8 @@ struct watch_type_filter {
|
|||
struct watch_filter {
|
||||
union {
|
||||
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 */
|
||||
struct watch_type_filter filters[];
|
||||
|
|
|
@ -56,6 +56,7 @@ enum cachefiles_coherency_trace {
|
|||
cachefiles_coherency_set_ok,
|
||||
cachefiles_coherency_vol_check_cmp,
|
||||
cachefiles_coherency_vol_check_ok,
|
||||
cachefiles_coherency_vol_check_resv,
|
||||
cachefiles_coherency_vol_check_xattr,
|
||||
cachefiles_coherency_vol_set_fail,
|
||||
cachefiles_coherency_vol_set_ok,
|
||||
|
@ -139,6 +140,7 @@ enum cachefiles_error_trace {
|
|||
EM(cachefiles_coherency_set_ok, "SET ok ") \
|
||||
EM(cachefiles_coherency_vol_check_cmp, "VOL BAD cmp ") \
|
||||
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_set_fail, "VOL SET fail") \
|
||||
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,
|
|||
bit += page->index;
|
||||
|
||||
set_bit(bit, wqueue->notes_bitmap);
|
||||
generic_pipe_buf_release(pipe, buf);
|
||||
}
|
||||
|
||||
// No try_steal function => no stealing
|
||||
|
@ -112,7 +113,7 @@ static bool post_one_notification(struct watch_queue *wqueue,
|
|||
buf->offset = offset;
|
||||
buf->len = len;
|
||||
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)) {
|
||||
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)
|
|||
struct page **pages;
|
||||
unsigned long *bitmap;
|
||||
unsigned long user_bufs;
|
||||
unsigned int bmsize;
|
||||
int ret, i, nr_pages;
|
||||
|
||||
if (!wqueue)
|
||||
|
@ -243,7 +243,8 @@ long watch_queue_set_size(struct pipe_inode_info *pipe, unsigned int nr_notes)
|
|||
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)
|
||||
goto error;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
bmsize = (nr_notes + BITS_PER_LONG - 1) / BITS_PER_LONG;
|
||||
bmsize *= sizeof(unsigned long);
|
||||
bitmap = kmalloc(bmsize, GFP_KERNEL);
|
||||
bitmap = bitmap_alloc(nr_notes, GFP_KERNEL);
|
||||
if (!bitmap)
|
||||
goto error_p;
|
||||
|
||||
memset(bitmap, 0xff, bmsize);
|
||||
bitmap_fill(bitmap, nr_notes);
|
||||
wqueue->notes = pages;
|
||||
wqueue->notes_bitmap = bitmap;
|
||||
wqueue->nr_pages = nr_pages;
|
||||
wqueue->nr_notes = nr_pages * WATCH_QUEUE_NOTES_PER_PAGE;
|
||||
wqueue->nr_notes = nr_notes;
|
||||
return 0;
|
||||
|
||||
error_p:
|
||||
|
@ -320,7 +319,7 @@ long watch_queue_set_filter(struct pipe_inode_info *pipe,
|
|||
tf[i].info_mask & WATCH_INFO_LENGTH)
|
||||
goto err_filter;
|
||||
/* Ignore any unknown types */
|
||||
if (tf[i].type >= sizeof(wfilter->type_filter) * 8)
|
||||
if (tf[i].type >= WATCH_TYPE__NR)
|
||||
continue;
|
||||
nr_filter++;
|
||||
}
|
||||
|
@ -336,7 +335,7 @@ long watch_queue_set_filter(struct pipe_inode_info *pipe,
|
|||
|
||||
q = wfilter->filters;
|
||||
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;
|
||||
|
||||
q->type = tf[i].type;
|
||||
|
@ -371,6 +370,7 @@ static void __put_watch_queue(struct kref *kref)
|
|||
|
||||
for (i = 0; i < wqueue->nr_pages; i++)
|
||||
__free_page(wqueue->notes[i]);
|
||||
bitmap_free(wqueue->notes_bitmap);
|
||||
|
||||
wfilter = rcu_access_pointer(wqueue->filter);
|
||||
if (wfilter)
|
||||
|
@ -566,7 +566,7 @@ void watch_queue_clear(struct watch_queue *wqueue)
|
|||
rcu_read_lock();
|
||||
spin_lock_bh(&wqueue->lock);
|
||||
|
||||
/* Prevent new additions and prevent notifications from happening */
|
||||
/* Prevent new notifications from being stored. */
|
||||
wqueue->defunct = true;
|
||||
|
||||
while (!hlist_empty(&wqueue->watches)) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче