sub tmp_clone {
my ($self, $dir) = @_;
my ($fh, $fn) = tempfile('msgmap-XXXXXXXX', EXLOCK => 0, DIR => $dir);
- PublicInbox::Spawn::set_nodatacow(fileno($fh));
+ PublicInbox::Spawn::nodatacow_fd(fileno($fh));
my $tmp;
if ($self->{dbh}->can('sqlite_backup_to_dbh')) {
$tmp = ref($self)->new_file($fn, 2);
use strict;
use v5.10.1;
-sub set_nodatacow ($) {
- my ($fd) = @_;
- return if $^O ne 'linux';
- defined(my $path = readlink("/proc/self/fd/$fd")) or return;
+sub nodatacow_dir ($) {
+ my ($path) = @_;
open my $mh, '<', '/proc/self/mounts' or return;
for (grep(/ btrfs /, <$mh>)) {
my (undef, $mnt_path, $type) = split(/ /);
}
}
+sub nodatacow_fd ($) {
+ my ($fd) = @_;
+ return if $^O ne 'linux';
+ defined(my $path = readlink("/proc/self/fd/$fd")) or return;
+ nodatacow_dir($path);
+}
+
1;
if ($rw) {
require PublicInbox::Spawn;
open my $fh, '+>>', $f or die "failed to open $f: $!";
- PublicInbox::Spawn::set_nodatacow(fileno($fh));
+ PublicInbox::Spawn::nodatacow_fd(fileno($fh));
my $j = "$f-journal";
open $fh, '+>>', $j or die "failed to open $j: $!";
- PublicInbox::Spawn::set_nodatacow(fileno($fh));
+ PublicInbox::Spawn::nodatacow_fd(fileno($fh));
} else {
$self->{filename} = $f; # die on stat() below:
}
use Carp qw(croak);
use POSIX qw(strftime);
use PublicInbox::OverIdx;
-use PublicInbox::Spawn qw(spawn);
+use PublicInbox::Spawn qw(spawn nodatacow_dir);
use PublicInbox::Git qw(git_unquote);
use PublicInbox::MsgTime qw(msg_timestamp msg_datestamp);
-our @EXPORT_OK = qw(crlf_adjust log2stack is_ancestor check_size nodatacow_dir);
+our @EXPORT_OK = qw(crlf_adjust log2stack is_ancestor check_size);
my $X = \%PublicInbox::Search::X;
my ($DB_CREATE_OR_OPEN, $DB_OPEN);
our $DB_NO_SYNC = 0;
1;
}
-sub nodatacow_dir ($) {
- my ($dir) = @_;
- opendir my $dh, $dir or die "opendir($dir): $!\n";
- PublicInbox::Spawn::set_nodatacow(fileno($dh));
-}
-
sub idx_acquire {
my ($self) = @_;
my $flag;
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';
#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;
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} //= (
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;
package PublicInbox::Xapcmd;
use strict;
use warnings;
-use PublicInbox::Spawn qw(which popen_rd);
+use PublicInbox::Spawn qw(which popen_rd nodatacow_dir);
use PublicInbox::Over;
-use PublicInbox::SearchIdx qw(nodatacow_dir);
+use PublicInbox::SearchIdx;
use File::Temp 0.19 (); # ->newdir
use File::Path qw(remove_tree);
use File::Basename qw(dirname);
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
use strict;
use Test::More;
-use File::Temp qw(tempfile);
+use File::Temp 0.19;
use PublicInbox::TestCommon;
use PublicInbox::Spawn qw(which);
use_ok 'PublicInbox::NDC_PP';
skip 'BTRFS_TESTDIR not defined', $nr unless defined $dir;
skip 'chattr(1) not installed', $nr unless which('chattr');
my $lsattr = which('lsattr') or skip 'lsattr(1) not installed', $nr;
- my ($fh, $name) = tempfile(DIR => $dir, UNLINK => 1);
- BAIL_OUT "tempfile: $!" unless $fh && defined($name);
- my $pp_sub = \&PublicInbox::NDC_PP::set_nodatacow;
+ my $tmp = File::Temp->newdir('nodatacow-XXXXX', DIR => $dir);
+ my $dn = $tmp->dirname;
+
+ my $name = "$dn/pp.f";
+ open my $fh, '>', $name or BAIL_OUT "open($name): $!";
+ my $pp_sub = \&PublicInbox::NDC_PP::nodatacow_fd;
$pp_sub->(fileno($fh));
my $res = xqx([$lsattr, $name]);
- like($res, qr/C/, "`C' attribute set with pure Perl");
+ like($res, qr/C.*\Q$name\E/, "`C' attribute set on fd with pure Perl");
+
+ $name = "$dn/pp.d";
+ mkdir($name) or BAIL_OUT "mkdir($name) $!";
+ PublicInbox::NDC_PP::nodatacow_dir($name);
+ $res = xqx([$lsattr, '-d', $name]);
+ like($res, qr/C.*\Q$name\E/, "`C' attribute set on dir with pure Perl");
- my $ic_sub = \&PublicInbox::Spawn::set_nodatacow;
+ $name = "$dn/ic.f";
+ my $ic_sub = \&PublicInbox::Spawn::nodatacow_fd;
$pp_sub == $ic_sub and
- skip 'Inline::C or Linux kernel headers missing', 1;
- ($fh, $name) = tempfile(DIR => $dir, UNLINK => 1);
+ skip 'Inline::C or Linux kernel headers missing', 2;
+ open $fh, '>', $name or BAIL_OUT "open($name): $!";
$ic_sub->(fileno($fh));
$res = xqx([$lsattr, $name]);
- like($res, qr/C/, "`C' attribute set with Inline::C");
+ like($res, qr/C.*\Q$name\E/, "`C' attribute set on fd with Inline::C");
+
+ $name = "$dn/ic.d";
+ mkdir($name) or BAIL_OUT "mkdir($name) $!";
+ PublicInbox::Spawn::nodatacow_dir($name);
+ $res = xqx([$lsattr, '-d', $name]);
+ like($res, qr/C.*\Q$name\E/, "`C' attribute set on dir with Inline::C");
};
done_testing;