Skip to content

Commit b5bcca8

Browse files
committed
replace flock with fcntl based locks
Signed-off-by: Utkarsh Srivastava <[email protected]> add comment to point to the GH discussion Signed-off-by: Utkarsh Srivastava <[email protected]>
1 parent 60b2be7 commit b5bcca8

File tree

5 files changed

+70
-8
lines changed

5 files changed

+70
-8
lines changed

src/manage_nsfs/manage_nsfs_glacier.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ async function lock_and_run(fs_context, lockfilename, cb) {
223223
const lockfd = await nb_native().fs.open(fs_context, path.join(config.NSFS_GLACIER_LOGS_DIR, lockfilename), 'w');
224224

225225
try {
226-
await lockfd.flock(fs_context, 'EXCLUSIVE');
226+
await lockfd.fcntllock(fs_context, 'EXCLUSIVE');
227227
await cb();
228228
} finally {
229229
await lockfd.close(fs_context);

src/native/fs/fs_napi.cpp

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <map>
1515
#include <math.h>
1616
#include <stdlib.h>
17+
#include <sys/fcntl.h>
1718
#include <sys/stat.h>
1819
#include <sys/syscall.h>
1920
#include <sys/types.h>
@@ -1363,6 +1364,7 @@ struct FileWrap : public Napi::ObjectWrap<FileWrap>
13631364
InstanceMethod<&FileWrap::stat>("stat"),
13641365
InstanceMethod<&FileWrap::fsync>("fsync"),
13651366
InstanceMethod<&FileWrap::flock>("flock"),
1367+
InstanceMethod<&FileWrap::fcntllock>("fcntllock"),
13661368
InstanceAccessor<&FileWrap::getfd>("fd"),
13671369
}));
13681370
constructor.SuppressDestruct();
@@ -1392,6 +1394,7 @@ struct FileWrap : public Napi::ObjectWrap<FileWrap>
13921394
Napi::Value fsync(const Napi::CallbackInfo& info);
13931395
Napi::Value getfd(const Napi::CallbackInfo& info);
13941396
Napi::Value flock(const Napi::CallbackInfo& info);
1397+
Napi::Value fcntllock(const Napi::CallbackInfo& info);
13951398
};
13961399

13971400
Napi::FunctionReference FileWrap::constructor;
@@ -1732,8 +1735,10 @@ struct FileFlock : public FSWrapWorker<FileWrap>
17321735
lock_mode = LOCK_EX;
17331736
} else if (mode == "UNLOCK") {
17341737
lock_mode = LOCK_UN;
1735-
} else {
1738+
} else if (mode == "SHARED") {
17361739
lock_mode = LOCK_SH;
1740+
} else {
1741+
SetError("invalid lock type");
17371742
}
17381743
}
17391744

@@ -1747,6 +1752,45 @@ struct FileFlock : public FSWrapWorker<FileWrap>
17471752
}
17481753
};
17491754

1755+
struct FileFcntlLock : public FSWrapWorker<FileWrap>
1756+
{
1757+
struct flock fl;
1758+
FileFcntlLock(const Napi::CallbackInfo& info)
1759+
: FSWrapWorker<FileWrap>(info)
1760+
, fl()
1761+
{
1762+
// lock entire file
1763+
fl.l_whence = SEEK_SET;
1764+
fl.l_start = 0;
1765+
fl.l_len = 0;
1766+
fl.l_pid = 0;
1767+
fl.l_type = F_RDLCK;
1768+
1769+
if (info.Length() > 1 && !info[1].IsUndefined()) {
1770+
auto mode = info[1].As<Napi::String>().Utf8Value();
1771+
if (mode == "EXCLUSIVE") {
1772+
fl.l_type = F_WRLCK;
1773+
} else if (mode == "UNLOCK") {
1774+
fl.l_type = F_UNLCK;
1775+
} else if (mode == "SHARED") {
1776+
fl.l_type = F_RDLCK;
1777+
} else {
1778+
SetError("invalid lock type");
1779+
}
1780+
}
1781+
1782+
Begin(XSTR() << "FileFcntlLock" << DVAL(_wrap->_path));
1783+
}
1784+
virtual void Work()
1785+
{
1786+
int fd = _wrap->_fd;
1787+
CHECK_WRAP_FD(fd);
1788+
// This uses F_OFD_SETLKW instead for discussion related to this choice
1789+
// refer: https://github.com/noobaa/noobaa-core/pull/8174
1790+
SYSCALL_OR_RETURN(fcntl(fd, F_OFD_SETLKW, &fl));
1791+
}
1792+
};
1793+
17501794
struct RealPath : public FSWorker
17511795
{
17521796
std::string _path;
@@ -1899,6 +1943,12 @@ FileWrap::flock(const Napi::CallbackInfo& info)
18991943
return api<FileFlock>(info);
19001944
}
19011945

1946+
Napi::Value
1947+
FileWrap::fcntllock(const Napi::CallbackInfo& info)
1948+
{
1949+
return api<FileFcntlLock>(info);
1950+
}
1951+
19021952
/**
19031953
*
19041954
*/

src/sdk/nb.d.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,8 +1002,9 @@ interface NativeFile {
10021002
replacexattr(fs_context: NativeFSContext, xattr: NativeFSXattr, clear_prefix?: string): Promise<void>;
10031003
linkfileat(fs_context: NativeFSContext, path: string, fd?: number): Promise<void>;
10041004
fsync(fs_context: NativeFSContext): Promise<void>;
1005-
fd: number
1005+
fd: number;
10061006
flock(fs_context: NativeFSContext, operation: "EXCLUSIVE" | "SHARED" | "UNLOCK"): Promise<void>;
1007+
fcntllock(fs_context: NativeFSContext, operation: "EXCLUSIVE" | "SHARED" | "UNLOCK"): Promise<void>;
10071008
}
10081009

10091010
interface NativeDir {
@@ -1124,4 +1125,4 @@ interface RestoreStatus {
11241125
state: nb.RestoreState;
11251126
ongoing?: boolean;
11261127
expiry_time?: Date;
1127-
}
1128+
}

src/util/file_reader.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,13 @@ class NewlineReader {
115115
async init() {
116116
let fh = null;
117117
try {
118-
fh = await nb_native().fs.open(this.fs_context, this.path, 'r');
119-
if (this.lock) await fh.flock(this.fs_context, this.lock);
118+
// here we are opening the file with both read and write to make sure
119+
// fcntlock can acquire both `EXCLUSIVE` as well as `SHARED` lock based
120+
// on the need.
121+
// If incompatible file descriptor and lock types are used then fcntl
122+
// throws `EBADF`.
123+
fh = await nb_native().fs.open(this.fs_context, this.path, '+');
124+
if (this.lock) await fh.fcntllock(this.fs_context, this.lock);
120125

121126
this.fh = fh;
122127
} catch (error) {

src/util/persistent_logger.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class PersistentLogger {
5959
let fh = null;
6060
try {
6161
fh = await this._open();
62-
if (this.locking) await fh.flock(this.fs_context, this.locking);
62+
if (this.locking) await fh.fcntllock(this.fs_context, this.locking);
6363

6464
const fh_stat = await fh.stat(this.fs_context);
6565
const path_stat = await nb_native().fs.stat(this.fs_context, this.active_path);
@@ -222,7 +222,13 @@ class PersistentLogger {
222222

223223
async _open() {
224224
await native_fs_utils._create_path(this.dir, this.fs_context);
225-
return nb_native().fs.open(this.fs_context, this.active_path, 'as');
225+
226+
// here we are opening the file with both read and write to make sure
227+
// fcntlock can acquire both `EXCLUSIVE` as well as `SHARED` lock based
228+
// on the need.
229+
// If incompatible file descriptor and lock types are used then fcntl
230+
// throws `EBADF`.
231+
return nb_native().fs.open(this.fs_context, this.active_path, 'as+');
226232
}
227233

228234
_poll_active_file_change(poll_interval) {

0 commit comments

Comments
 (0)