Skip to content

Commit 2645840

Browse files
committed
Merge tag 'vfs-6.8.cachefiles' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull vfs cachefiles updates from Christian Brauner: "This contains improvements for on-demand cachefiles. If the daemon crashes and the on-demand cachefiles fd is unexpectedly closed in-flight requests and subsequent read operations associated with the fd will fail with EIO. This causes issues in various scenarios as this failure is currently unrecoverable. The work contained in this pull request introduces a failover mode and enables the daemon to recover in-flight requested-related objects. A restarted daemon will be able to process requests as usual. This requires that in-flight requests are stored during daemon crash or while the daemon is offline. In addition, a handle to /dev/cachefiles needs to be stored. This can be done by e.g., systemd's fdstore (cf. [1]) which enables the restarted daemon to recover state. Three new states are introduced in this patchset: (1) CLOSE Object is closed by the daemon. (2) OPEN Object is open and ready for processing. IOW, the open request has been handled successfully. (3) REOPENING Object has been previously closed and is now reopened due to a read request. A restarted daemon can recover the /dev/cachefiles fd from systemd's fdstore and writes "restore" to the device. This causes the object state to be reset from CLOSE to REOPENING and reinitializes the object. The daemon may now handle the open request. Any in-flight operations are restored and handled avoiding interruptions for users" Link: https://systemd.io/FILE_DESCRIPTOR_STORE [1] * tag 'vfs-6.8.cachefiles' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: cachefiles: add restore command to recover inflight ondemand read requests cachefiles: narrow the scope of triggering EPOLLIN events in ondemand mode cachefiles: resend an open request if the read request's object is closed cachefiles: extract ondemand info field from cachefiles_object cachefiles: introduce object ondemand state
2 parents bb93c5e + e73fa11 commit 2645840

4 files changed

Lines changed: 201 additions & 46 deletions

File tree

fs/cachefiles/daemon.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ static const struct cachefiles_daemon_cmd cachefiles_daemon_cmds[] = {
7777
{ "tag", cachefiles_daemon_tag },
7878
#ifdef CONFIG_CACHEFILES_ONDEMAND
7979
{ "copen", cachefiles_ondemand_copen },
80+
{ "restore", cachefiles_ondemand_restore },
8081
#endif
8182
{ "", NULL }
8283
};
@@ -355,14 +356,24 @@ static __poll_t cachefiles_daemon_poll(struct file *file,
355356
struct poll_table_struct *poll)
356357
{
357358
struct cachefiles_cache *cache = file->private_data;
359+
XA_STATE(xas, &cache->reqs, 0);
360+
struct cachefiles_req *req;
358361
__poll_t mask;
359362

360363
poll_wait(file, &cache->daemon_pollwq, poll);
361364
mask = 0;
362365

363366
if (cachefiles_in_ondemand_mode(cache)) {
364-
if (!xa_empty(&cache->reqs))
365-
mask |= EPOLLIN;
367+
if (!xa_empty(&cache->reqs)) {
368+
rcu_read_lock();
369+
xas_for_each_marked(&xas, req, ULONG_MAX, CACHEFILES_REQ_NEW) {
370+
if (!cachefiles_ondemand_is_reopening_read(req)) {
371+
mask |= EPOLLIN;
372+
break;
373+
}
374+
}
375+
rcu_read_unlock();
376+
}
366377
} else {
367378
if (test_bit(CACHEFILES_STATE_CHANGED, &cache->flags))
368379
mask |= EPOLLIN;

fs/cachefiles/interface.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ struct cachefiles_object *cachefiles_alloc_object(struct fscache_cookie *cookie)
3131
if (!object)
3232
return NULL;
3333

34+
if (cachefiles_ondemand_init_obj_info(object, volume)) {
35+
kmem_cache_free(cachefiles_object_jar, object);
36+
return NULL;
37+
}
38+
3439
refcount_set(&object->ref, 1);
3540

3641
spin_lock_init(&object->lock);
@@ -88,7 +93,7 @@ void cachefiles_put_object(struct cachefiles_object *object,
8893
ASSERTCMP(object->file, ==, NULL);
8994

9095
kfree(object->d_name);
91-
96+
cachefiles_ondemand_deinit_obj_info(object);
9297
cache = object->volume->cache->cache;
9398
fscache_put_cookie(object->cookie, fscache_cookie_put_object);
9499
object->cookie = NULL;

fs/cachefiles/internal.h

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,19 @@ struct cachefiles_volume {
4444
struct dentry *fanout[256]; /* Fanout subdirs */
4545
};
4646

47+
enum cachefiles_object_state {
48+
CACHEFILES_ONDEMAND_OBJSTATE_CLOSE, /* Anonymous fd closed by daemon or initial state */
49+
CACHEFILES_ONDEMAND_OBJSTATE_OPEN, /* Anonymous fd associated with object is available */
50+
CACHEFILES_ONDEMAND_OBJSTATE_REOPENING, /* Object that was closed and is being reopened. */
51+
};
52+
53+
struct cachefiles_ondemand_info {
54+
struct work_struct ondemand_work;
55+
int ondemand_id;
56+
enum cachefiles_object_state state;
57+
struct cachefiles_object *object;
58+
};
59+
4760
/*
4861
* Backing file state.
4962
*/
@@ -61,7 +74,7 @@ struct cachefiles_object {
6174
unsigned long flags;
6275
#define CACHEFILES_OBJECT_USING_TMPFILE 0 /* Have an unlinked tmpfile */
6376
#ifdef CONFIG_CACHEFILES_ONDEMAND
64-
int ondemand_id;
77+
struct cachefiles_ondemand_info *ondemand;
6578
#endif
6679
};
6780

@@ -290,12 +303,42 @@ extern ssize_t cachefiles_ondemand_daemon_read(struct cachefiles_cache *cache,
290303
extern int cachefiles_ondemand_copen(struct cachefiles_cache *cache,
291304
char *args);
292305

306+
extern int cachefiles_ondemand_restore(struct cachefiles_cache *cache,
307+
char *args);
308+
293309
extern int cachefiles_ondemand_init_object(struct cachefiles_object *object);
294310
extern void cachefiles_ondemand_clean_object(struct cachefiles_object *object);
295311

296312
extern int cachefiles_ondemand_read(struct cachefiles_object *object,
297313
loff_t pos, size_t len);
298314

315+
extern int cachefiles_ondemand_init_obj_info(struct cachefiles_object *obj,
316+
struct cachefiles_volume *volume);
317+
extern void cachefiles_ondemand_deinit_obj_info(struct cachefiles_object *obj);
318+
319+
#define CACHEFILES_OBJECT_STATE_FUNCS(_state, _STATE) \
320+
static inline bool \
321+
cachefiles_ondemand_object_is_##_state(const struct cachefiles_object *object) \
322+
{ \
323+
return object->ondemand->state == CACHEFILES_ONDEMAND_OBJSTATE_##_STATE; \
324+
} \
325+
\
326+
static inline void \
327+
cachefiles_ondemand_set_object_##_state(struct cachefiles_object *object) \
328+
{ \
329+
object->ondemand->state = CACHEFILES_ONDEMAND_OBJSTATE_##_STATE; \
330+
}
331+
332+
CACHEFILES_OBJECT_STATE_FUNCS(open, OPEN);
333+
CACHEFILES_OBJECT_STATE_FUNCS(close, CLOSE);
334+
CACHEFILES_OBJECT_STATE_FUNCS(reopening, REOPENING);
335+
336+
static inline bool cachefiles_ondemand_is_reopening_read(struct cachefiles_req *req)
337+
{
338+
return cachefiles_ondemand_object_is_reopening(req->object) &&
339+
req->msg.opcode == CACHEFILES_OP_READ;
340+
}
341+
299342
#else
300343
static inline ssize_t cachefiles_ondemand_daemon_read(struct cachefiles_cache *cache,
301344
char __user *_buffer, size_t buflen)
@@ -317,6 +360,20 @@ static inline int cachefiles_ondemand_read(struct cachefiles_object *object,
317360
{
318361
return -EOPNOTSUPP;
319362
}
363+
364+
static inline int cachefiles_ondemand_init_obj_info(struct cachefiles_object *obj,
365+
struct cachefiles_volume *volume)
366+
{
367+
return 0;
368+
}
369+
static inline void cachefiles_ondemand_deinit_obj_info(struct cachefiles_object *obj)
370+
{
371+
}
372+
373+
static inline bool cachefiles_ondemand_is_reopening_read(struct cachefiles_req *req)
374+
{
375+
return false;
376+
}
320377
#endif
321378

322379
/*

0 commit comments

Comments
 (0)