Skip to content

Commit 5716f8c

Browse files
nyhwkozaczuk
authored andcommitted
Implement statx() function
Linux 4.11 introduced the statx() system call, which allows retrieving only specific stat fields instead of all of them as in the normal stat(), which can be beneficial for remote filesystems where collecting *all* the information might be slower than collecting just some. Moreover, statx may ask for additional attributes not available with the classic stat(). Recently, a lot of code, including the Boost library, started to use statx() instead of stat(), so OSv needs it too. The implementation in this patch is simple - it just calls stat() and translates its output (struct stat) into the desired format (struct statx). As explained in the code, it is ok that we retrieve all the fields and not just the desired ones - and it's ok if we can't retrieve more than the original stat() was able to retrive. With this patch, all OSv unit tests which still failed on Fedora 34 (with the updated Boost that uses statx()) now pass, and "make check" passes on Fedora 34. Unfortunately, the Musl header files we use do not declare statx(), struct statx, or the STATX_* constants, so for now I included these declarations inside the source file implementing statx(). In the future, when we update the header files, we can remove those declarations from the source file. Fixes #1148 Signed-off-by: Nadav Har'El <nyh@scylladb.com> Message-Id: <20210621095532.293657-1-nyh@scylladb.com>
1 parent bcaad08 commit 5716f8c

File tree

1 file changed

+77
-0
lines changed

1 file changed

+77
-0
lines changed

fs/vfs/main.cc

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,6 +1191,83 @@ int stat(const char *pathname, struct stat *st)
11911191
return __xstat(1, pathname, st);
11921192
}
11931193

1194+
// Our <sys/stat.h> (from Musl) doesn't yet declare statx(), struct statx,
1195+
// or the various STATX_* constants. So we need to do it here for now.
1196+
// Eventually, when we update Musl or modify it manually to include these
1197+
// definitions, they should be removed from here:
1198+
struct statx_timestamp
1199+
{
1200+
int64_t tv_sec;
1201+
uint32_t tv_nsec;
1202+
int32_t statx_timestamp_pad1[1];
1203+
};
1204+
struct statx {
1205+
uint32_t stx_mask;
1206+
uint32_t stx_blksize;
1207+
uint64_t stx_attributes;
1208+
uint32_t stx_nlink;
1209+
uint32_t stx_uid;
1210+
uint32_t stx_gid;
1211+
uint16_t stx_mode;
1212+
uint16_t __statx_pad1[1];
1213+
uint64_t stx_ino;
1214+
uint64_t stx_size;
1215+
uint64_t stx_blocks;
1216+
uint64_t stx_attributes_mask;
1217+
struct statx_timestamp stx_atime;
1218+
struct statx_timestamp stx_btime;
1219+
struct statx_timestamp stx_ctime;
1220+
struct statx_timestamp stx_mtime;
1221+
uint32_t stx_rdev_major;
1222+
uint32_t stx_rdev_minor;
1223+
uint32_t stx_dev_major;
1224+
uint32_t stx_dev_minor;
1225+
uint64_t __statx_pad2[14];
1226+
};
1227+
extern "C" int statx(int dirfd, const char* pathname, int flags, unsigned int mask, struct statx *buf);
1228+
#define STATX_BASIC_STATS 0x000007ffU
1229+
1230+
int statx(int dirfd, const char* pathname, int flags, unsigned int mask,
1231+
struct statx *buf)
1232+
{
1233+
// This is a simplistic implementation which just calls the old fstatat()
1234+
// and converts the resulting "struct stat" to a "struct statx".
1235+
// This is good enough for OSv and its local filesystems, where we don't
1236+
// expect great performance savings from not retrieving all the fields.
1237+
struct stat st;
1238+
int ret = fstatat(dirfd, pathname, &st, flags);
1239+
if (ret != 0) {
1240+
return ret;
1241+
}
1242+
// Convert the information we got in "struct stat" to "struct statx".
1243+
// We are allowed to ignore the list of requested attributes in "mask" -
1244+
// the documentation specifies that "the kernel may return fields that
1245+
// weren't requested and may fail to return fields that were requested
1246+
// ... Fields that are given values despite being unrequested can just
1247+
// be ignored.". We just need to return stx_mask saying what we filled.
1248+
buf->stx_mask = STATX_BASIC_STATS;
1249+
buf->stx_blksize = st.st_blksize;
1250+
buf->stx_attributes_mask = 0;
1251+
buf->stx_nlink = st.st_nlink;
1252+
buf->stx_uid = st.st_uid;
1253+
buf->stx_gid = st.st_gid;
1254+
buf->stx_mode = st.st_mode;
1255+
buf->stx_ino = st.st_ino;
1256+
buf->stx_size = st.st_size;
1257+
buf->stx_blocks = st.st_blocks;
1258+
buf->stx_atime.tv_sec = st.st_atim.tv_sec;
1259+
buf->stx_atime.tv_nsec = st.st_atim.tv_nsec;
1260+
buf->stx_mtime.tv_sec = st.st_mtim.tv_sec;
1261+
buf->stx_mtime.tv_nsec = st.st_mtim.tv_nsec;
1262+
buf->stx_ctime.tv_sec = st.st_ctim.tv_sec;
1263+
buf->stx_ctime.tv_nsec = st.st_ctim.tv_nsec;
1264+
buf->stx_rdev_major = major(st.st_rdev);
1265+
buf->stx_rdev_minor = minor(st.st_rdev);
1266+
buf->stx_dev_major = major(st.st_dev);
1267+
buf->stx_dev_minor = minor(st.st_dev);
1268+
return 0;
1269+
}
1270+
11941271
TRACEPOINT(trace_vfs_lstat, "pathname=%s, stat=%p", const char*, struct stat*);
11951272
TRACEPOINT(trace_vfs_lstat_ret, "");
11961273
TRACEPOINT(trace_vfs_lstat_err, "errno=%d", int);

0 commit comments

Comments
 (0)