Skip to content

Commit

Permalink
[LibOS] Add flock syscall
Browse files Browse the repository at this point in the history
The `flock` implementation introduces flock (aka BSD) locks, in addition
to already-existing fcntl (aka POSIX) locks. The flock heavily reuses
the current logic of `libos_file_lock` and `dent_file_locks`.

Since flock locks are tied to the handle, we introduce a new field
`struct libos_file_lock::handle_id` that serves to distinguish flock
locks from fcntl locks.

Similarly to fcntl locks, interruptable flock locks are not supported.

Co-authored-by: Dmitrii Kuvaiskii <dmitrii.kuvaiskii@intel.com>
Signed-off-by: Liang Ma <liang3.ma@intel.com>
Signed-off-by: Dmitrii Kuvaiskii <dmitrii.kuvaiskii@intel.com>
  • Loading branch information
billionairiam and Dmitrii Kuvaiskii committed Jun 27, 2023
1 parent ece36fe commit fcc5937
Show file tree
Hide file tree
Showing 13 changed files with 401 additions and 35 deletions.
23 changes: 19 additions & 4 deletions libos/include/libos_fs_lock.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
*/

/*
* File locks. Currently only POSIX locks are implemented.
* File locks. Both POSIX locks (fcntl syscall) and BSD locks (flock syscall) are implemented via
* a common struct `posix_lock` (the name is historic). See `man fcntl` and `man flock` for details.
*/

#pragma once
Expand All @@ -22,8 +23,8 @@ struct libos_dentry;
int init_fs_lock(void);

/*
* File locks. Currently describes only POSIX locks (also known as advisory record locks). See `man
* fcntl` for details.
* File locks. Describes both POSIX locks aka advisory record locks (fcntl syscall) and BSD locks
* (flock syscall). See `man fcntl` and `man flock` for details.
*
* The current implementation works over IPC and handles all requests in the main process. It has
* the following caveats:
Expand All @@ -34,7 +35,7 @@ int init_fs_lock(void);
* local-process-only filesystems (tmpfs).
* - There is no deadlock detection (EDEADLK).
* - The lock requests cannot be interrupted (EINTR).
* - The locks work only on files that have a dentry (no pipes, sockets etc.)
* - The locks work only on files that have a dentry (no pipes, sockets etc.).
*/

DEFINE_LISTP(libos_file_lock);
Expand All @@ -54,6 +55,9 @@ struct libos_file_lock {

/* List node, used internally */
LIST_TYPE(libos_file_lock) list;

/* Unique handle id, works as an identifier for `flock` syscall */
uint64_t handle_id;
};

/*!
Expand Down Expand Up @@ -125,3 +129,14 @@ int file_lock_set_from_ipc(const char* path, struct libos_file_lock* file_lock,
*/
int file_lock_get_from_ipc(const char* path, struct libos_file_lock* file_lock,
struct libos_file_lock* out_file_lock);

/*!
* \brief Determine whether dentry has flock-typed locks.
*
* \param dent The dentry for a file.
*
* Returns true if at least one associated lock is flock-typed. Otherwise returns false. Note that
* if a dentry has a mix of fcntl and flock locks, then this function returns true (and the
* subsequent behavior is undefined).
*/
bool has_flock_locks(struct libos_dentry* dent);
4 changes: 4 additions & 0 deletions libos/include/libos_handle.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ struct libos_handle {
enum libos_handle_type type;
bool is_dir;

/* Unique id, works as an identifier for `flock` syscall. This field does not change, so
* reading it does not require holding any locks. */
uint64_t id;

refcount_t ref_count;

struct libos_fs* fs;
Expand Down
2 changes: 2 additions & 0 deletions libos/include/libos_ipc.h
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ struct libos_ipc_file_lock {
int type;
uint64_t start;
uint64_t end;
uint64_t handle_id;
IDTYPE pid;

bool wait;
Expand All @@ -294,6 +295,7 @@ struct libos_ipc_file_lock_resp {
int type;
uint64_t start;
uint64_t end;
uint64_t handle_id;
IDTYPE pid;
};

Expand Down
31 changes: 29 additions & 2 deletions libos/src/bookkeep/libos_handle.c
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ static struct libos_handle* __detach_fd_handle(struct libos_fd_handle* fd, int*
}

static int clear_posix_locks(struct libos_handle* handle) {
if (handle && handle->dentry) {
if (handle && handle->dentry && (!has_flock_locks(handle->dentry))) {
/* Clear file (POSIX) locks for a file. We are required to do that every time a FD is
* closed, even if the process holds other handles for that file, or duplicated FDs for the
* same handle. */
Expand All @@ -301,6 +301,7 @@ static int clear_posix_locks(struct libos_handle* handle) {
.start = 0,
.end = FS_LOCK_EOF,
.pid = g_process.pid,
.handle_id = 0,
};
int ret = file_lock_set(handle->dentry, &file_lock, /*block=*/false);
if (ret < 0) {
Expand Down Expand Up @@ -350,6 +351,10 @@ struct libos_handle* get_new_handle(void) {
}
INIT_LISTP(&new_handle->epoll_items);
new_handle->epoll_items_count = 0;

static uint64_t local_counter = 0;
new_handle->id = ((uint64_t)g_process.pid << 32)
| __atomic_add_fetch(&local_counter, 1, __ATOMIC_RELAXED);
return new_handle;
}

Expand Down Expand Up @@ -475,6 +480,26 @@ static void destroy_handle(struct libos_handle* hdl) {
free_mem_obj_to_mgr(handle_mgr, hdl);
}

static int clear_flock_locks(struct libos_handle* hdl) {
/* Clear flock (BSD) locks for a file. We are required to do that when the handle is closed. */
if (hdl && hdl->dentry && has_flock_locks(hdl->dentry)) {
assert(hdl->ref_count == 0);
struct libos_file_lock file_lock = {
.type = F_UNLCK,
.start = 0,
.end = FS_LOCK_EOF,
.pid = g_process.pid,
.handle_id = hdl->id,
};
int ret = file_lock_set(hdl->dentry, &file_lock, /*block=*/false);
if (ret < 0) {
log_warning("error releasing locks: %s", unix_strerror(ret));
return ret;
}
}
return 0;
}

void put_handle(struct libos_handle* hdl) {
refcount_t ref_count = refcount_dec(&hdl->ref_count);

Expand All @@ -496,8 +521,10 @@ void put_handle(struct libos_handle* hdl) {
hdl->pal_handle = NULL;
}

if (hdl->dentry)
if (hdl->dentry) {
(void)clear_flock_locks(hdl);
put_dentry(hdl->dentry);
}

if (hdl->inode)
put_inode(hdl->inode);
Expand Down
Loading

0 comments on commit fcc5937

Please sign in to comment.