* finish, in order to do successful finish calls for all
* resources in the session.
* @finish: Required. Final cleanup in the new kernel.
+ * @get_id: Optional. Returns a unique identifier for the file.
* @owner: Module reference
*
* All operations (except can_preserve) receive a pointer to a
int (*retrieve)(struct liveupdate_file_op_args *args);
bool (*can_finish)(struct liveupdate_file_op_args *args);
void (*finish)(struct liveupdate_file_op_args *args);
+ unsigned long (*get_id)(struct file *file);
struct module *owner;
};
#include <linux/liveupdate.h>
#include <linux/module.h>
#include <linux/sizes.h>
+#include <linux/xarray.h>
#include <linux/slab.h>
#include <linux/string.h>
#include "luo_internal.h"
static LIST_HEAD(luo_file_handler_list);
+/* Keep track of files being preserved by LUO */
+static DEFINE_XARRAY(luo_preserved_files);
+
/* 2 4K pages, give space for 128 files per file_set */
#define LUO_FILE_PGCNT 2ul
#define LUO_FILE_MAX \
file_set->files = NULL;
}
+static unsigned long luo_get_id(struct liveupdate_file_handler *fh,
+ struct file *file)
+{
+ return fh->ops->get_id ? fh->ops->get_id(file) : (unsigned long)file;
+}
+
static bool luo_token_is_used(struct luo_file_set *file_set, u64 token)
{
struct luo_file *iter;
* Context: Can be called from an ioctl handler during normal system operation.
* Return: 0 on success. Returns a negative errno on failure:
* -EEXIST if the token is already used.
+ * -EBUSY if the file descriptor is already preserved by another session.
* -EBADF if the file descriptor is invalid.
* -ENOSPC if the file_set is full.
* -ENOENT if no compatible handler is found.
if (err)
goto err_free_files_mem;
- err = luo_flb_file_preserve(fh);
+ err = xa_insert(&luo_preserved_files, luo_get_id(fh, file),
+ file, GFP_KERNEL);
if (err)
goto err_free_files_mem;
+ err = luo_flb_file_preserve(fh);
+ if (err)
+ goto err_erase_xa;
+
luo_file = kzalloc_obj(*luo_file);
if (!luo_file) {
err = -ENOMEM;
kfree(luo_file);
err_flb_unpreserve:
luo_flb_file_unpreserve(fh);
+err_erase_xa:
+ xa_erase(&luo_preserved_files, luo_get_id(fh, file));
err_free_files_mem:
luo_free_files_mem(file_set);
err_fput:
luo_file->fh->ops->unpreserve(&args);
luo_flb_file_unpreserve(luo_file->fh);
+ xa_erase(&luo_preserved_files,
+ luo_get_id(luo_file->fh, luo_file->file));
list_del(&luo_file->list);
file_set->count--;
luo_file->file = args.file;
/* Get reference so we can keep this file in LUO until finish */
get_file(luo_file->file);
+
+ WARN_ON(xa_insert(&luo_preserved_files,
+ luo_get_id(luo_file->fh, luo_file->file),
+ luo_file->file, GFP_KERNEL));
+
*filep = luo_file->file;
luo_file->retrieve_status = 1;
luo_file_finish_one(file_set, luo_file);
- if (luo_file->file)
+ if (luo_file->file) {
+ xa_erase(&luo_preserved_files,
+ luo_get_id(luo_file->fh, luo_file->file));
fput(luo_file->file);
+ }
list_del(&luo_file->list);
file_set->count--;
mutex_destroy(&luo_file->mutex);