]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
client: Gracefully handle empty pathname for statxat()
authorAnoop C S <anoopcs@cryptolab.net>
Mon, 23 Sep 2024 07:06:55 +0000 (12:36 +0530)
committerAnoop C S <anoopcs@cryptolab.net>
Thu, 20 Mar 2025 10:18:22 +0000 (15:48 +0530)
man statx(2)[1] says the following:
. . .
AT_EMPTY_PATH
    If pathname is an empty string, operate on the file referred to by
    dirfd (which may have been obtained using the open(2) O_PATH flag).
    In this case, dirfd can refer to any type of file, not just a
    directory.

    If dirfd is AT_FDCWD, the call operates on the current working
    directory.
. . .

Look out for an empty pathname and use the relative fd's inode in the
presence of AT_EMPTY_PATH flag before calling internal _getattr().

Fixes: https://tracker.ceph.com/issues/68189
Review with: git show -w

Note: path_walk() refactor from https://github.com/ceph/ceph/pull/60746
included the core changes required here and thus src/client/Client.cc
changes have been removed from the cherry-pick as they conflict at the
same time.

[1] https://www.man7.org/linux/man-pages/man2/statx.2.html

Signed-off-by: Anoop C S <anoopcs@cryptolab.net>
(cherry picked from commit edd7fe76c4919bc243377c6d7aae20b0606b89c3)

src/include/cephfs/ceph_ll_client.h
src/include/cephfs/libcephfs.h
src/libcephfs.cc
src/test/libcephfs/test.cc

index ac5b7c2247178890e5e51ffe614a6dee0f6b694a..458edce590bfeb78d14c30f7766b008c886eaf6b 100644 (file)
@@ -110,6 +110,9 @@ struct ceph_statx {
  * others in the future, we disallow setting any that aren't recognized.
  */
 #define CEPH_REQ_FLAG_MASK             (AT_SYMLINK_NOFOLLOW|AT_STATX_DONT_SYNC)
+#if defined(__linux__) && defined(AT_EMPTY_PATH)
+#define CEPH_AT_EMPTY_PATH             (CEPH_REQ_FLAG_MASK|AT_EMPTY_PATH)
+#endif
 
 /* fallocate mode flags */
 #ifndef FALLOC_FL_KEEP_SIZE
index e5a23e06e21b707d5a3a5d74a3091e9b109340d0..4fc975801faf96c0a37dd0e7e5e6814b6ffa91a3 100644 (file)
@@ -948,7 +948,7 @@ int ceph_fstatx(struct ceph_mount_info *cmount, int fd, struct ceph_statx *stx,
  * @param relpath to the file/directory to get statistics of
  * @param stx the ceph_statx struct that will be filled in with the file's statistics.
  * @param want bitfield of CEPH_STATX_* flags showing designed attributes
- * @param flags bitfield that can be used to set AT_* modifier flags (AT_STATX_DONT_SYNC and AT_SYMLINK_NOFOLLOW)
+ * @param flags bitfield that can be used to set AT_* modifier flags (AT_STATX_DONT_SYNC, AT_SYMLINK_NOFOLLOW and AT_EMPTY_PATH)
  * @returns 0 on success or negative error code on failure.
  */
 int ceph_statxat(struct ceph_mount_info *cmount, int dirfd, const char *relpath,
index f492562c771e1bcfa6d2d8403f74c5b622ffb490..ce1b6ccd0b05af277b067167f802f5b38f09b72d 100644 (file)
@@ -1039,7 +1039,11 @@ extern "C" int ceph_statxat(struct ceph_mount_info *cmount, int dirfd, const cha
 {
   if (!cmount->is_mounted())
     return -ENOTCONN;
+#ifdef CEPH_AT_EMPTY_PATH
+  if (flags & ~CEPH_AT_EMPTY_PATH)
+#else
   if (flags & ~CEPH_REQ_FLAG_MASK)
+#endif
     return -EINVAL;
   return cmount->get_client()->statxat(dirfd, relpath, stx, cmount->default_perms,
                                        want, flags);
index bcdba534cb3b9b29b9dfda2d8e59b86bdc22a77d..87dd9827c97abfd345167083bc3127849eaef388 100644 (file)
@@ -2879,6 +2879,19 @@ TEST(LibCephFS, Statxat) {
   ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFDIR);
   ASSERT_EQ(ceph_statxat(cmount, fd, rel_file_name_2, &stx, 0, 0), 0);
   ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFREG);
+  // test relative to root with empty relpath
+#if defined(__linux__) && defined(AT_EMPTY_PATH)
+  int dir_fd = ceph_openat(cmount, fd, dir_name, O_DIRECTORY | O_RDONLY, 0);
+  ASSERT_LE(0, dir_fd);
+  ASSERT_EQ(ceph_statxat(cmount, dir_fd, "", &stx, 0, AT_EMPTY_PATH), 0);
+  ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFDIR);
+  ASSERT_EQ(0, ceph_close(cmount, dir_fd));
+  int file_fd = ceph_openat(cmount, fd, rel_file_name_2, O_RDONLY, 0);
+  ASSERT_LE(0, file_fd);
+  ASSERT_EQ(ceph_statxat(cmount, file_fd, "", &stx, 0, AT_EMPTY_PATH), 0);
+  ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFREG);
+  ASSERT_EQ(0, ceph_close(cmount, file_fd));
+#endif
   ASSERT_EQ(0, ceph_close(cmount, fd));
 
   // test relative to dir
@@ -2886,6 +2899,14 @@ TEST(LibCephFS, Statxat) {
   ASSERT_LE(0, fd);
   ASSERT_EQ(ceph_statxat(cmount, fd, rel_file_name_1, &stx, 0, 0), 0);
   ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFREG);
+  // test relative to dir with empty relpath
+#if defined(__linux__) && defined(AT_EMPTY_PATH)
+  int rel_file_fd = ceph_openat(cmount, fd, rel_file_name_1, O_RDONLY, 0);
+  ASSERT_LE(0, rel_file_fd);
+  ASSERT_EQ(ceph_statxat(cmount, rel_file_fd, "", &stx, 0, AT_EMPTY_PATH), 0);
+  ASSERT_EQ(stx.stx_mode & S_IFMT, S_IFREG);
+  ASSERT_EQ(0, ceph_close(cmount, rel_file_fd));
+#endif
 
   // delete the dirtree, recreate and verify
   ASSERT_EQ(0, ceph_unlink(cmount, file_path));