Skip to content

Commit 90f5dc7

Browse files
authored
Merge pull request #8982 from romayalon/romy-getpwnam-concurrency-issue
NSFS | FS Napi | getpwnam concurrency issue
2 parents fdd041c + f225557 commit 90f5dc7

File tree

3 files changed

+78
-3
lines changed

3 files changed

+78
-3
lines changed

src/native/fs/fs_napi.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ typedef std::map<std::string, std::string> XattrMap;
168168
const char* gpfs_dl_path = std::getenv("GPFS_DL_PATH");
169169

170170
int gpfs_lib_file_exists = -1;
171+
static long PASSWD_BUF_SIZE = -1;
171172

172173
static int (*dlsym_gpfs_fcntl)(gpfs_file_t file, void* arg) = 0;
173174

@@ -1397,17 +1398,29 @@ struct Fsync : public FSWorker
13971398
struct GetPwName : public FSWorker
13981399
{
13991400
std::string _user;
1401+
struct passwd _pwd;
14001402
struct passwd *_getpwnam_res;
1403+
std::unique_ptr<char[]> _buf;
14011404
GetPwName(const Napi::CallbackInfo& info)
14021405
: FSWorker(info)
1406+
, _getpwnam_res(NULL)
14031407
{
14041408
_user = info[1].As<Napi::String>();
14051409
Begin(XSTR() << "GetPwName " << DVAL(_user));
14061410
}
14071411
virtual void Work()
14081412
{
1409-
_getpwnam_res = getpwnam(_user.c_str());
1410-
if (_getpwnam_res == NULL) SetSyscallError();
1413+
_buf.reset(new char[PASSWD_BUF_SIZE]);
1414+
if (!_buf) {
1415+
SetSyscallError();
1416+
return;
1417+
}
1418+
int rc = getpwnam_r(_user.c_str(), &_pwd, _buf.get(), PASSWD_BUF_SIZE, &_getpwnam_res);
1419+
if (rc != 0) {
1420+
SetSyscallError();
1421+
return;
1422+
}
1423+
if (_getpwnam_res == NULL) SetError("NO_SUCH_USER");
14111424
}
14121425

14131426
virtual void OnOK()
@@ -2402,6 +2415,12 @@ fs_napi(Napi::Env env, Napi::Object exports)
24022415
exports_fs["DT_DIR"] = Napi::Number::New(env, DT_DIR);
24032416
exports_fs["DT_LNK"] = Napi::Number::New(env, DT_LNK);
24042417
exports_fs["PLATFORM_IOV_MAX"] = Napi::Number::New(env, IOV_MAX);
2418+
long passwd_bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
2419+
if (passwd_bufsize == -1) {
2420+
passwd_bufsize = 16384;
2421+
}
2422+
PASSWD_BUF_SIZE = passwd_bufsize;
2423+
24052424

24062425
#ifdef O_DIRECT
24072426
exports_fs["O_DIRECT"] = Napi::Number::New(env, O_DIRECT);
@@ -2415,6 +2434,7 @@ fs_napi(Napi::Env env, Napi::Object exports)
24152434
exports_fs["set_log_config"] = Napi::Function::New(env, set_log_config);
24162435

24172436
exports["fs"] = exports_fs;
2437+
24182438
}
24192439

24202440
} // namespace noobaa
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/* Copyright (C) 2016 NooBaa */
2+
'use strict';
3+
4+
const P = require('../../../util/promise');
5+
const nb_native = require('../../../util/nb_native');
6+
const test_utils = require('../../system_tests/test_utils');
7+
const { TEST_TIMEOUT } = require('../../system_tests/test_utils');
8+
const { get_process_fs_context } = require('../../../util/native_fs_utils');
9+
10+
const DEFAULT_FS_CONFIG = get_process_fs_context();
11+
12+
describe('fs napi concurrency tests', function() {
13+
14+
describe('getpwnam concurrency tests', function() {
15+
16+
const users = [];
17+
beforeAll(async () => {
18+
for (let i = 0; i < 20; i++) {
19+
const username = `user-${i}`;
20+
const expected_config = { uid: 7000 + i, gid: 7000 + i };
21+
await test_utils.create_fs_user_by_platform(username, username, expected_config.uid, expected_config.gid);
22+
users.push({ username, expected_config });
23+
}
24+
}, TEST_TIMEOUT);
25+
26+
afterAll(async () => {
27+
for (let i = 0; i < users.length; i++) {
28+
await test_utils.delete_fs_user_by_platform(users[i].username);
29+
}
30+
}, TEST_TIMEOUT);
31+
32+
it('getpwnam concurrency tests', async function() {
33+
for (let i = 0; i < users.length; i++) {
34+
nb_native().fs.getpwname(
35+
DEFAULT_FS_CONFIG,
36+
users[i].username
37+
)
38+
.catch(err => {
39+
console.log('getpwname error - ', err);
40+
throw err;
41+
}).then(res => {
42+
console.log('getpwname res', res);
43+
users[i].actual_config = res;
44+
});
45+
}
46+
await P.delay(5000);
47+
for (let i = 0; i < users.length; i++) {
48+
const actual = users[i].actual_config;
49+
const expected = users[i].expected_config;
50+
expect(actual.uid).toBe(expected.uid);
51+
expect(actual.gid).toBe(expected.gid);
52+
}
53+
}, TEST_TIMEOUT);
54+
});
55+
});

src/util/native_fs_utils.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ async function get_user_by_distinguished_name({ distinguished_name }) {
502502
const user = await nb_native().fs.getpwname(context, distinguished_name);
503503
return user;
504504
} catch (err) {
505-
dbg.error('native_fs_utils.get_user_by_distinguished_name: failed with error', err, distinguished_name);
505+
dbg.error('native_fs_utils.get_user_by_distinguished_name: failed with error', err, err.code, distinguished_name);
506506
if (err.code !== undefined) throw err;
507507
throw new RpcError('NO_SUCH_USER', 'User with distinguished_name not found', err);
508508
}

0 commit comments

Comments
 (0)