Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

cachefiles: unbind cachefiles gracefully in on-demand mode

Add a refcount to avoid the deadlock in on-demand read mode. The
on-demand read mode will pin the corresponding cachefiles object for
each anonymous fd. The cachefiles object is unpinned when the anonymous
fd gets closed. When the user daemon exits and the fd of
"/dev/cachefiles" device node gets closed, it will wait for all
cahcefiles objects getting withdrawn. Then if there's any anonymous fd
getting closed after the fd of the device node, the user daemon will
hang forever, waiting for all objects getting withdrawn.

To fix this, add a refcount indicating if there's any object pinned by
anonymous fds. The cachefiles cache gets unbound and withdrawn when the
refcount is decreased to 0. It won't change the behaviour of the
original mode, in which case the cachefiles cache gets unbound and
withdrawn as long as the fd of the device node gets closed.

Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>
Link: https://lore.kernel.org/r/20220509074028.74954-4-jefflexu@linux.alibaba.com
Acked-by: David Howells <dhowells@redhat.com>
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>

authored by

Jeffle Xu and committed by
Gao Xiang
d11b0b04 c8383054

+22 -3
+16 -3
fs/cachefiles/daemon.c
··· 111 111 INIT_LIST_HEAD(&cache->volumes); 112 112 INIT_LIST_HEAD(&cache->object_list); 113 113 spin_lock_init(&cache->object_list_lock); 114 + refcount_set(&cache->unbind_pincount, 1); 114 115 xa_init_flags(&cache->reqs, XA_FLAGS_ALLOC); 115 116 xa_init_flags(&cache->ondemand_ids, XA_FLAGS_ALLOC1); 116 117 ··· 165 164 xa_destroy(&cache->ondemand_ids); 166 165 } 167 166 167 + void cachefiles_put_unbind_pincount(struct cachefiles_cache *cache) 168 + { 169 + if (refcount_dec_and_test(&cache->unbind_pincount)) { 170 + cachefiles_daemon_unbind(cache); 171 + cachefiles_open = 0; 172 + kfree(cache); 173 + } 174 + } 175 + 176 + void cachefiles_get_unbind_pincount(struct cachefiles_cache *cache) 177 + { 178 + refcount_inc(&cache->unbind_pincount); 179 + } 180 + 168 181 /* 169 182 * Release a cache. 170 183 */ ··· 194 179 195 180 if (cachefiles_in_ondemand_mode(cache)) 196 181 cachefiles_flush_reqs(cache); 197 - cachefiles_daemon_unbind(cache); 198 182 199 183 /* clean up the control file interface */ 200 184 cache->cachefilesd = NULL; 201 185 file->private_data = NULL; 202 - cachefiles_open = 0; 203 186 204 - kfree(cache); 187 + cachefiles_put_unbind_pincount(cache); 205 188 206 189 _leave(""); 207 190 return 0;
+3
fs/cachefiles/internal.h
··· 109 109 char *rootdirname; /* name of cache root directory */ 110 110 char *secctx; /* LSM security context */ 111 111 char *tag; /* cache binding tag */ 112 + refcount_t unbind_pincount;/* refcount to do daemon unbind */ 112 113 struct xarray reqs; /* xarray of pending on-demand requests */ 113 114 struct xarray ondemand_ids; /* xarray for ondemand_id allocation */ 114 115 u32 ondemand_id_next; ··· 172 171 * daemon.c 173 172 */ 174 173 extern const struct file_operations cachefiles_daemon_fops; 174 + extern void cachefiles_get_unbind_pincount(struct cachefiles_cache *cache); 175 + extern void cachefiles_put_unbind_pincount(struct cachefiles_cache *cache); 175 176 176 177 /* 177 178 * error_inject.c
+3
fs/cachefiles/ondemand.c
··· 14 14 object->ondemand_id = CACHEFILES_ONDEMAND_ID_CLOSED; 15 15 xa_erase(&cache->ondemand_ids, object_id); 16 16 cachefiles_put_object(object, cachefiles_obj_put_ondemand_fd); 17 + cachefiles_put_unbind_pincount(cache); 17 18 return 0; 18 19 } 19 20 ··· 170 169 load->fd = fd; 171 170 req->msg.object_id = object_id; 172 171 object->ondemand_id = object_id; 172 + 173 + cachefiles_get_unbind_pincount(cache); 173 174 return 0; 174 175 175 176 err_put_fd: