7
7
#include " ./gpfs_fcntl.h"
8
8
9
9
#include < dirent.h>
10
+ #include < errno.h>
10
11
#include < fcntl.h>
11
12
#include < limits.h>
12
13
#include < map>
22
23
#include < unistd.h>
23
24
#include < uv.h>
24
25
#include < vector>
25
- #include < errno.h>
26
26
27
27
#ifdef __APPLE__
28
- #include < sys/mount.h>
29
- #include < sys/param.h>
28
+ #include < sys/mount.h>
29
+ #include < sys/param.h>
30
30
#else
31
- #include < sys/statfs.h>
31
+ #include < sys/statfs.h>
32
32
#endif
33
33
34
34
#ifndef __APPLE__
35
- #define ENOATTR ENODATA
35
+ #define ENOATTR ENODATA
36
36
#endif
37
37
38
38
#define ROUNDUP (X, Y ) ((Y) * (((X) + (Y)-1 ) / (Y)))
121
121
} while (0 )
122
122
123
123
#ifdef __APPLE__
124
- #define flistxattr (a, b, c ) ::flistxattr(a, b, c, 0 )
125
- #define getxattr (a, b, c, d ) ::getxattr(a, b, c, d, 0 , 0 )
126
- #define fgetxattr (a, b, c, d ) ::fgetxattr(a, b, c, d, 0 , 0 )
127
- #define fsetxattr (a, b, c, d, e ) ::fsetxattr(a, b, c, d, e, 0 )
128
- #define fremovexattr (a, b ) ::fremovexattr(a, b, 0 )
124
+ #define flistxattr (a, b, c ) ::flistxattr(a, b, c, 0 )
125
+ #define getxattr (a, b, c, d ) ::getxattr(a, b, c, d, 0 , 0 )
126
+ #define fgetxattr (a, b, c, d ) ::fgetxattr(a, b, c, d, 0 , 0 )
127
+ #define fsetxattr (a, b, c, d, e ) ::fsetxattr(a, b, c, d, e, 0 )
128
+ #define fremovexattr (a, b ) ::fremovexattr(a, b, 0 )
129
129
#endif
130
130
131
131
namespace noobaa
@@ -146,41 +146,56 @@ static int (*dlsym_gpfs_linkatif)(
146
146
static int (*dlsym_gpfs_unlinkat)(
147
147
gpfs_file_t fileDesc, const char * path, gpfs_file_t fd) = 0;
148
148
149
- const static std::map<std::string, int > flags_to_case = {
150
- { " r" , O_RDONLY },
151
- { " rs" , O_RDONLY | O_SYNC },
152
- { " sr" , O_RDONLY | O_SYNC },
153
- #ifdef O_DIRECT
154
- { " rd" , O_RDONLY | O_DIRECT },
155
- { " dr" , O_RDONLY | O_DIRECT },
156
- { " rds" , O_RDONLY | O_DIRECT | O_SYNC },
157
- #endif
158
- { " r+" , O_RDWR },
159
- { " rs+" , O_RDWR | O_SYNC },
160
- { " sr+" , O_RDWR | O_SYNC },
161
- { " w" , O_TRUNC | O_CREAT | O_WRONLY },
149
+ static int
150
+ parse_open_flags (std::string flags)
151
+ {
152
+ int bits = 0 ;
153
+ for (char ch : flags) {
154
+ switch (ch) {
155
+ case ' r' :
156
+ bits |= O_RDONLY;
157
+ break ;
158
+ case ' w' :
159
+ bits |= O_TRUNC | O_CREAT | O_WRONLY;
160
+ break ;
161
+ case ' a' :
162
+ bits |= O_APPEND | O_CREAT | O_WRONLY;
163
+ break ;
164
+ case ' +' :
165
+ bits |= O_RDWR;
166
+ bits &= ~(O_RDONLY | O_WRONLY);
167
+ break ;
168
+ case ' s' :
169
+ bits |= O_SYNC;
170
+ break ;
171
+ case ' x' :
172
+ bits |= O_EXCL;
173
+ break ;
174
+ case ' t' :
162
175
#ifdef O_TMPFILE
163
- { " wt" , O_RDWR | O_TMPFILE },
176
+ bits |= O_TMPFILE | O_RDWR;
177
+ bits &= ~(O_RDONLY | O_WRONLY);
178
+ #else
179
+ LOG (" FS: Unsupported O_TMPFILE " << flags);
164
180
#endif
165
- { " wx" , O_TRUNC | O_CREAT | O_WRONLY | O_EXCL },
166
- { " xw" , O_TRUNC | O_CREAT | O_WRONLY | O_EXCL },
167
- { " w+" , O_TRUNC | O_CREAT | O_RDWR },
168
- { " wx+" , O_TRUNC | O_CREAT | O_RDWR | O_EXCL },
169
- { " xw+" , O_TRUNC | O_CREAT | O_RDWR | O_EXCL },
170
- { " a" , O_APPEND | O_CREAT | O_WRONLY },
171
- { " ax" , O_APPEND | O_CREAT | O_WRONLY | O_EXCL },
172
- { " xa" , O_APPEND | O_CREAT | O_WRONLY | O_EXCL },
173
- { " as" , O_APPEND | O_CREAT | O_WRONLY | O_SYNC },
174
- { " sa" , O_APPEND | O_CREAT | O_WRONLY | O_SYNC },
175
- { " a+" , O_APPEND | O_CREAT | O_RDWR },
176
- { " ax+" , O_APPEND | O_CREAT | O_RDWR | O_EXCL },
177
- { " xa+" , O_APPEND | O_CREAT | O_RDWR | O_EXCL },
178
- { " as+" , O_APPEND | O_CREAT | O_RDWR | O_SYNC },
179
- { " sa+" , O_APPEND | O_CREAT | O_RDWR | O_SYNC },
180
- };
181
+ break ;
182
+ case ' d' :
183
+ #ifdef O_DIRECT
184
+ bits |= O_DIRECT;
185
+ #else
186
+ LOG (" FS: Unsupported O_DIRECT " << flags);
187
+ #endif
188
+ break ;
189
+ default :
190
+ LOG (" FS: Unexpected open flags " << flags);
191
+ return -1 ;
192
+ }
193
+ }
194
+ return bits;
195
+ }
181
196
182
197
const static std::vector<std::string> GPFS_XATTRS{ GPFS_ENCRYPTION_XATTR_NAME };
183
- const static std::vector<std::string> USER_XATTRS{ " user.content_md5" , " user.version_id" , " user.prev_version_id" , " user.delete_marker" , " user.dir_content" };
198
+ const static std::vector<std::string> USER_XATTRS{ " user.content_md5" , " user.version_id" , " user.prev_version_id" , " user.delete_marker" , " user.dir_content" };
184
199
185
200
struct Entry
186
201
{
@@ -196,7 +211,7 @@ struct gpfsRequest_t
196
211
char buffer[GPFS_XATTR_BUFFER_SIZE];
197
212
};
198
213
199
- void
214
+ static void
200
215
build_gpfs_get_ea_request (gpfsRequest_t* reqP, std::string key)
201
216
{
202
217
int nameLen = key.size ();
@@ -224,7 +239,7 @@ api(const Napi::CallbackInfo& info)
224
239
return promise;
225
240
}
226
241
227
- void
242
+ static void
228
243
set_stat_res (Napi::Object res, Napi::Env env, struct stat & stat_res, XattrMap& xattr_res)
229
244
{
230
245
res[" dev" ] = Napi::Number::New (env, stat_res.st_dev );
@@ -278,7 +293,7 @@ set_stat_res(Napi::Object res, Napi::Env env, struct stat& stat_res, XattrMap& x
278
293
}
279
294
}
280
295
281
- void
296
+ static void
282
297
set_statfs_res (Napi::Object res, Napi::Env env, struct statfs & statfs_res)
283
298
{
284
299
res[" type" ] = Napi::Number::New (env, statfs_res.f_type );
@@ -302,26 +317,26 @@ set_statfs_res(Napi::Object res, Napi::Env env, struct statfs& statfs_res)
302
317
#endif
303
318
}
304
319
305
- void
320
+ static void
306
321
set_fs_worker_stats (Napi::Env env, Napi::Object fs_worker_stats, std::string work_name, double took_time, int error)
307
322
{
308
323
fs_worker_stats[" name" ] = Napi::String::New (env, work_name);
309
324
fs_worker_stats[" took_time" ] = Napi::Number::New (env, took_time);
310
325
fs_worker_stats[" error" ] = Napi::Number::New (env, error);
311
326
}
312
327
313
- bool
328
+ static bool
314
329
cmp_ver_id (int64_t link_expected_mtime, int64_t link_expected_inode, struct stat & _stat_res)
315
330
{
316
331
// extract actual stat ino and mtime
317
332
int64_t stat_actual_ino = _stat_res.st_ino ;
318
- #ifdef __APPLE__
319
- auto actual_mtime_sec = _stat_res.st_mtimespec .tv_sec ;
320
- auto actual_mtime_nsec = _stat_res.st_mtimespec .tv_nsec ;
321
- #else
322
- auto actual_mtime_sec = _stat_res.st_mtim .tv_sec ;
323
- auto actual_mtime_nsec = _stat_res.st_mtim .tv_nsec ;
324
- #endif
333
+ #ifdef __APPLE__
334
+ auto actual_mtime_sec = _stat_res.st_mtimespec .tv_sec ;
335
+ auto actual_mtime_nsec = _stat_res.st_mtimespec .tv_nsec ;
336
+ #else
337
+ auto actual_mtime_sec = _stat_res.st_mtim .tv_sec ;
338
+ auto actual_mtime_nsec = _stat_res.st_mtim .tv_nsec ;
339
+ #endif
325
340
auto actual_mtimeNs = int64_t (round ((double (1e9 ) * actual_mtime_sec)) + actual_mtime_nsec);
326
341
return link_expected_mtime == actual_mtimeNs && link_expected_inode == stat_actual_ino;
327
342
}
@@ -512,7 +527,7 @@ struct FSWorker : public Napi::AsyncWorker
512
527
DBG1 (" FS::FSWorker::Execute: " << _desc << DVAL (_uid) << DVAL (_gid) << DVAL (_backend));
513
528
ThreadScope tx;
514
529
tx.set_user (_uid, _gid);
515
- DBG1 (" FS::FSWorker::Execute: " << _desc << DVAL (_uid) << DVAL (_gid) << DVAL (geteuid ()) << DVAL (getegid ()) << DVAL (getuid ()) << DVAL (getgid ()));
530
+ DBG1 (" FS::FSWorker::Execute: " << _desc << DVAL (_uid) << DVAL (_gid) << DVAL (geteuid ()) << DVAL (getegid ()) << DVAL (getuid ()) << DVAL (getgid ()));
516
531
517
532
auto start_time = std::chrono::high_resolution_clock::now ();
518
533
Work ();
@@ -838,11 +853,10 @@ struct Rmdir : public FSWorker
838
853
}
839
854
};
840
855
841
-
842
856
/* *
843
857
* SafeLink is an fs op
844
858
* 1. link
845
- * 2. check if the target has the expected version
859
+ * 2. check if the target has the expected version
846
860
* 2.1. if yes - return
847
861
* 2.2. else - unlink and retry
848
862
*/
@@ -864,16 +878,15 @@ struct SafeLink : public FSWorker
864
878
Begin (XSTR () << " SafeLink " << DVAL (_link_from.c_str ()) << DVAL (_link_to.c_str ()) << DVAL (_link_expected_mtime) << DVAL (_link_expected_inode));
865
879
}
866
880
virtual void Work ()
867
- {
881
+ {
868
882
SYSCALL_OR_RETURN (link (_link_from.c_str (), _link_to.c_str ()));
869
883
struct stat _stat_res;
870
884
SYSCALL_OR_RETURN (stat (_link_to.c_str (), &_stat_res));
871
885
if (cmp_ver_id (_link_expected_mtime, _link_expected_inode, _stat_res) == true ) return ;
872
886
SYSCALL_OR_RETURN (unlink (_link_to.c_str ()));
873
- DBG0 (" FS::SafeLink::Execute: ERROR link target doesn't match the expected inode + mtime" << DVAL (_link_to)
874
- << DVAL (_link_expected_mtime) << DVAL (_link_expected_inode));
887
+ DBG0 (" FS::SafeLink::Execute: ERROR link target doesn't match the expected inode + mtime" << DVAL (_link_to)
888
+ << DVAL (_link_expected_mtime) << DVAL (_link_expected_inode));
875
889
SetError (XSTR () << " FS::SafeLink ERROR link target doesn't match expected inode and mtime" );
876
-
877
890
}
878
891
};
879
892
@@ -895,7 +908,7 @@ struct SafeUnlink : public FSWorker
895
908
{
896
909
_to_unlink = info[1 ].As <Napi::String>();
897
910
_mv_to = info[2 ].As <Napi::String>();
898
- if (info.Length () > 4 && !info[3 ].IsUndefined () && !info[4 ].IsUndefined ()) {
911
+ if (info.Length () > 4 && !info[3 ].IsUndefined () && !info[4 ].IsUndefined ()) {
899
912
// TODO: handle lossless
900
913
bool lossless = true ;
901
914
_unlink_expected_mtime = info[3 ].As <Napi::BigInt>().Int64Value (&lossless);
@@ -908,13 +921,13 @@ struct SafeUnlink : public FSWorker
908
921
SYSCALL_OR_RETURN (rename (_to_unlink.c_str (), _mv_to.c_str ()));
909
922
struct stat _stat_res;
910
923
SYSCALL_OR_RETURN (stat (_mv_to.c_str (), &_stat_res));
911
- if (cmp_ver_id (_unlink_expected_mtime, _unlink_expected_inode, _stat_res) == true ){
924
+ if (cmp_ver_id (_unlink_expected_mtime, _unlink_expected_inode, _stat_res) == true ) {
912
925
SYSCALL_OR_RETURN (unlink (_mv_to.c_str ()));
913
926
return ;
914
927
}
915
928
SYSCALL_OR_RETURN (link (_mv_to.c_str (), _to_unlink.c_str ()));
916
- DBG0 (" FS::SafeUnlink::Execute: ERROR unlink target doesn't match the expected inode + mtime, retry" << DVAL (_to_unlink)
917
- << DVAL (_unlink_expected_mtime) << DVAL (_unlink_expected_inode));
929
+ DBG0 (" FS::SafeUnlink::Execute: ERROR unlink target doesn't match the expected inode + mtime, retry"
930
+ << DVAL (_to_unlink) << DVAL ( _unlink_expected_mtime) << DVAL (_unlink_expected_inode));
918
931
SetError (XSTR () << " FS::SafeUnlink ERROR unlink target doesn't match expected inode and mtime" );
919
932
}
920
933
};
@@ -1245,7 +1258,8 @@ struct FileOpen : public FSWorker
1245
1258
{
1246
1259
_path = info[1 ].As <Napi::String>();
1247
1260
if (info.Length () > 2 && !info[2 ].IsUndefined ()) {
1248
- _flags = flags_to_case.at (info[2 ].As <Napi::String>());
1261
+ _flags = parse_open_flags (info[2 ].As <Napi::String>());
1262
+ if (_flags < 0 ) SetError (" Unexpected open flags" );
1249
1263
}
1250
1264
if (info.Length () > 3 && !info[3 ].IsUndefined ()) {
1251
1265
_mode = info[3 ].As <Napi::Number>().Uint32Value ();
@@ -1442,7 +1456,7 @@ struct LinkFileAt : public FSWrapWorker<FileWrap>
1442
1456
{
1443
1457
// gpfs_linkat() is the same as Linux linkat() but we need a new function because
1444
1458
// Linux will fail the linkat() if the file already exist and we want to replace it if it existed.
1445
- if (_replace_fd == 0 ){
1459
+ if (_replace_fd == 0 ) {
1446
1460
SYSCALL_OR_RETURN (dlsym_gpfs_linkat (_wrap->_fd , " " , AT_FDCWD, _filepath.c_str (), AT_EMPTY_PATH));
1447
1461
} else {
1448
1462
SYSCALL_OR_RETURN (dlsym_gpfs_linkatif (_wrap->_fd , " " , AT_FDCWD, _filepath.c_str (), AT_EMPTY_PATH, _replace_fd));
@@ -1465,12 +1479,11 @@ struct UnlinkFileAt : public FSWrapWorker<FileWrap>
1465
1479
Begin (XSTR () << " UnlinkFileAt" << DVAL (_wrap->_path .c_str ()) << DVAL (_wrap->_fd ) << DVAL (_filepath) << DVAL (_delete_fd));
1466
1480
}
1467
1481
virtual void Work ()
1468
- {
1482
+ {
1469
1483
SYSCALL_OR_RETURN (dlsym_gpfs_unlinkat (_wrap->_fd , _filepath.c_str (), _delete_fd));
1470
1484
}
1471
1485
};
1472
1486
1473
-
1474
1487
struct FileStat : public FSWrapWorker <FileWrap>
1475
1488
{
1476
1489
struct stat _stat_res;
@@ -1613,7 +1626,6 @@ struct GetSingleXattr : public FSWorker
1613
1626
}
1614
1627
};
1615
1628
1616
-
1617
1629
Napi::Value
1618
1630
FileWrap::close (const Napi::CallbackInfo& info)
1619
1631
{
@@ -1825,7 +1837,7 @@ DirWrap::read(const Napi::CallbackInfo& info)
1825
1837
return api<DirReadEntry>(info);
1826
1838
}
1827
1839
1828
- Napi::Value
1840
+ static Napi::Value
1829
1841
set_debug_level (const Napi::CallbackInfo& info)
1830
1842
{
1831
1843
int level = info[0 ].As <Napi::Number>();
@@ -1834,6 +1846,29 @@ set_debug_level(const Napi::CallbackInfo& info)
1834
1846
return info.Env ().Undefined ();
1835
1847
}
1836
1848
1849
+ static const int DIO_BUFFER_MEMALIGN = 4096 ;
1850
+
1851
+ static void
1852
+ dio_buffer_free (Napi::Env env, uint8_t * buf)
1853
+ {
1854
+ if (buf) free (buf);
1855
+ }
1856
+
1857
+ /* *
1858
+ * Allocate memory aligned buffer for direct IO.
1859
+ */
1860
+ static Napi::Value
1861
+ dio_buffer_alloc (const Napi::CallbackInfo& info)
1862
+ {
1863
+ int size = info[0 ].As <Napi::Number>();
1864
+ uint8_t * buf = 0 ;
1865
+ int r = posix_memalign ((void **)&buf, DIO_BUFFER_MEMALIGN, size);
1866
+ if (r || !buf) {
1867
+ throw Napi::Error::New (info.Env (), " FS::dio_buffer_alloc: failed to allocate memory" );
1868
+ }
1869
+ return Napi::Buffer<uint8_t >::New (info.Env (), buf, size, dio_buffer_free);
1870
+ }
1871
+
1837
1872
void
1838
1873
fs_napi (Napi::Env env, Napi::Object exports)
1839
1874
{
@@ -1906,6 +1941,14 @@ fs_napi(Napi::Env env, Napi::Object exports)
1906
1941
exports_fs[" DT_LNK" ] = Napi::Number::New (env, DT_LNK);
1907
1942
exports_fs[" PLATFORM_IOV_MAX" ] = Napi::Number::New (env, IOV_MAX);
1908
1943
1944
+ #ifdef O_DIRECT
1945
+ exports_fs[" O_DIRECT" ] = Napi::Number::New (env, O_DIRECT);
1946
+ #endif
1947
+ #ifdef O_TMPFILE
1948
+ exports_fs[" O_TMPFILE" ] = Napi::Number::New (env, O_TMPFILE);
1949
+ #endif
1950
+
1951
+ exports_fs[" dio_buffer_alloc" ] = Napi::Function::New (env, dio_buffer_alloc);
1909
1952
exports_fs[" set_debug_level" ] = Napi::Function::New (env, set_debug_level);
1910
1953
1911
1954
exports[" fs" ] = exports_fs;
0 commit comments