about summary refs log tree commit homepage
path: root/lib/PublicInbox/Spawn.pm
diff options
context:
space:
mode:
authorEric Wong <e@yhbt.net>2020-08-08 04:59:48 +0000
committerEric Wong <e@yhbt.net>2020-08-08 10:47:11 +0000
commit683e5fbbfef867ff04b376b3d5230976004a6c7a (patch)
tree85b6cb3b3f40d88a51cf3b1d6902373f6318a836 /lib/PublicInbox/Spawn.pm
parent6e98887b3d539dd07c9d49e3334e48d720fc1e31 (diff)
downloadpublic-inbox-683e5fbbfef867ff04b376b3d5230976004a6c7a.tar.gz
support setting No_COW on Perl <5.22
fileno(DIRHANDLE) only works on Perl 5.22+, so we need to use
dirfd(3) ourselves from Inline::C (or rely on chattr(1) being
installed).

While we're at it, rename `set_nodatacow' to `nodatacow_fd'
for consistency with `nodatacow_dir'.
Diffstat (limited to 'lib/PublicInbox/Spawn.pm')
-rw-r--r--lib/PublicInbox/Spawn.pm21
1 files changed, 18 insertions, 3 deletions
diff --git a/lib/PublicInbox/Spawn.pm b/lib/PublicInbox/Spawn.pm
index 508d43fd..cb16fcf6 100644
--- a/lib/PublicInbox/Spawn.pm
+++ b/lib/PublicInbox/Spawn.pm
@@ -19,7 +19,7 @@ use strict;
 use parent qw(Exporter);
 use Symbol qw(gensym);
 use PublicInbox::ProcessPipe;
-our @EXPORT_OK = qw/which spawn popen_rd/;
+our @EXPORT_OK = qw/which spawn popen_rd nodatacow_dir/;
 our @RLIMITS = qw(RLIMIT_CPU RLIMIT_CORE RLIMIT_DATA);
 
 my $vfork_spawn = <<'VFORK_SPAWN';
@@ -159,11 +159,12 @@ my $set_nodatacow = $^O eq 'linux' ? <<'SET_NODATACOW' : '';
 #include <sys/vfs.h>
 #include <linux/magic.h>
 #include <linux/fs.h>
+#include <dirent.h>
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
 
-void set_nodatacow(int fd)
+void nodatacow_fd(int fd)
 {
         struct statfs buf;
         int val = 0;
@@ -185,6 +186,19 @@ void set_nodatacow(int fd)
         if (ioctl(fd, FS_IOC_SETFLAGS, &val) < 0)
                 fprintf(stderr, "FS_IOC_SET_FLAGS: %s\\n", strerror(errno));
 }
+
+void nodatacow_dir(const char *dir)
+{
+        DIR *dh = opendir(dir);
+        int fd;
+
+        if (!dh) croak("opendir(%s): %s", dir, strerror(errno));
+        fd = dirfd(dh);
+        if (fd >= 0)
+                nodatacow_fd(fd);
+        /* ENOTSUP probably won't happen under Linux... */
+        closedir(dh);
+}
 SET_NODATACOW
 
 my $inline_dir = $ENV{PERL_INLINE_DIRECTORY} //= (
@@ -226,7 +240,8 @@ unless (defined $vfork_spawn) {
 unless ($set_nodatacow) {
         require PublicInbox::NDC_PP;
         no warnings 'once';
-        *set_nodatacow = \&PublicInbox::NDC_PP::set_nodatacow;
+        *nodatacow_fd = \&PublicInbox::NDC_PP::nodatacow_fd;
+        *nodatacow_dir = \&PublicInbox::NDC_PP::nodatacow_dir;
 }
 undef $set_nodatacow;
 undef $vfork_spawn;