Skip to content

Commit

Permalink
cachefiles: unbind cachefiles gracefully in on-demand mode
Browse files Browse the repository at this point in the history
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 <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Acked-by: David Howells <[email protected]>
Signed-off-by: Gao Xiang <[email protected]>
  • Loading branch information
lostjeffle authored and hsiangkao committed May 17, 2022
1 parent c838305 commit d11b0b0
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 3 deletions.
19 changes: 16 additions & 3 deletions fs/cachefiles/daemon.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ static int cachefiles_daemon_open(struct inode *inode, struct file *file)
INIT_LIST_HEAD(&cache->volumes);
INIT_LIST_HEAD(&cache->object_list);
spin_lock_init(&cache->object_list_lock);
refcount_set(&cache->unbind_pincount, 1);
xa_init_flags(&cache->reqs, XA_FLAGS_ALLOC);
xa_init_flags(&cache->ondemand_ids, XA_FLAGS_ALLOC1);

Expand Down Expand Up @@ -164,6 +165,20 @@ static void cachefiles_flush_reqs(struct cachefiles_cache *cache)
xa_destroy(&cache->ondemand_ids);
}

void cachefiles_put_unbind_pincount(struct cachefiles_cache *cache)
{
if (refcount_dec_and_test(&cache->unbind_pincount)) {
cachefiles_daemon_unbind(cache);
cachefiles_open = 0;
kfree(cache);
}
}

void cachefiles_get_unbind_pincount(struct cachefiles_cache *cache)
{
refcount_inc(&cache->unbind_pincount);
}

/*
* Release a cache.
*/
Expand All @@ -179,14 +194,12 @@ static int cachefiles_daemon_release(struct inode *inode, struct file *file)

if (cachefiles_in_ondemand_mode(cache))
cachefiles_flush_reqs(cache);
cachefiles_daemon_unbind(cache);

/* clean up the control file interface */
cache->cachefilesd = NULL;
file->private_data = NULL;
cachefiles_open = 0;

kfree(cache);
cachefiles_put_unbind_pincount(cache);

_leave("");
return 0;
Expand Down
3 changes: 3 additions & 0 deletions fs/cachefiles/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ struct cachefiles_cache {
char *rootdirname; /* name of cache root directory */
char *secctx; /* LSM security context */
char *tag; /* cache binding tag */
refcount_t unbind_pincount;/* refcount to do daemon unbind */
struct xarray reqs; /* xarray of pending on-demand requests */
struct xarray ondemand_ids; /* xarray for ondemand_id allocation */
u32 ondemand_id_next;
Expand Down Expand Up @@ -171,6 +172,8 @@ extern int cachefiles_has_space(struct cachefiles_cache *cache,
* daemon.c
*/
extern const struct file_operations cachefiles_daemon_fops;
extern void cachefiles_get_unbind_pincount(struct cachefiles_cache *cache);
extern void cachefiles_put_unbind_pincount(struct cachefiles_cache *cache);

/*
* error_inject.c
Expand Down
3 changes: 3 additions & 0 deletions fs/cachefiles/ondemand.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ static int cachefiles_ondemand_fd_release(struct inode *inode,
object->ondemand_id = CACHEFILES_ONDEMAND_ID_CLOSED;
xa_erase(&cache->ondemand_ids, object_id);
cachefiles_put_object(object, cachefiles_obj_put_ondemand_fd);
cachefiles_put_unbind_pincount(cache);
return 0;
}

Expand Down Expand Up @@ -169,6 +170,8 @@ static int cachefiles_ondemand_get_fd(struct cachefiles_req *req)
load->fd = fd;
req->msg.object_id = object_id;
object->ondemand_id = object_id;

cachefiles_get_unbind_pincount(cache);
return 0;

err_put_fd:
Expand Down

0 comments on commit d11b0b0

Please sign in to comment.