diff --git a/.gitignore b/.gitignore index e97b31f5..e504d492 100644 --- a/.gitignore +++ b/.gitignore @@ -60,6 +60,8 @@ utils/statd/statd tools/locktest/testlk tools/getiversion/getiversion tools/nfsconf/nfsconf +tools/nfsrahead/nfsrahead +tools/nfsrahead/99-nfs_bdi.rules support/export/mount.h support/export/mount_clnt.c support/export/mount_xdr.c diff --git a/configure.ac b/configure.ac index 6d464ac5..f462a645 100644 --- a/configure.ac +++ b/configure.ac @@ -639,6 +639,7 @@ AC_CONFIG_FILES([ tools/rpcgen/Makefile tools/mountstats/Makefile tools/nfs-iostat/Makefile + tools/nfsrahead/Makefile tools/rpcctl/Makefile tools/nfsdclnts/Makefile tools/nfsconf/Makefile diff --git a/nfs.conf b/nfs.conf index 86ed7d53..30f9e109 100644 --- a/nfs.conf +++ b/nfs.conf @@ -5,6 +5,10 @@ [general] # pipefs-directory=/var/lib/nfs/rpc_pipefs # +[nfsrahead] +# nfs=15000 +# nfs4=16000 +# [exportfs] # debug=0 # diff --git a/systemd/nfs.conf.man b/systemd/nfs.conf.man index f32c690b..ebbf28d0 100644 --- a/systemd/nfs.conf.man +++ b/systemd/nfs.conf.man @@ -245,6 +245,17 @@ Only .B debug= is recognized. +.TP +.B nfsrahead +Recognized values: +.BR nfs , +.BR nfsv4 , +.BR default . + +See +.BR nfsrahead (5) +for deatils. + .SH FILES .I /etc/nfs.conf .SH SEE ALSO diff --git a/tools/Makefile.am b/tools/Makefile.am index c3feabbe..40c17c37 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -12,6 +12,6 @@ if CONFIG_NFSDCLD OPTDIRS += nfsdclddb endif -SUBDIRS = locktest rpcdebug nlmtest mountstats nfs-iostat rpcctl nfsdclnts $(OPTDIRS) +SUBDIRS = locktest rpcdebug nlmtest mountstats nfs-iostat rpcctl nfsdclnts nfsrahead $(OPTDIRS) MAINTAINERCLEANFILES = Makefile.in diff --git a/tools/nfsrahead/99-nfs.rules b/tools/nfsrahead/99-nfs.rules new file mode 100644 index 00000000..c74914b2 --- /dev/null +++ b/tools/nfsrahead/99-nfs.rules @@ -0,0 +1 @@ +SUBSYSTEM=="bdi", ACTION=="add", PROGRAM="/usr/libexec/nfsrahead %k", ATTR{read_ahead_kb}="%c" diff --git a/tools/nfsrahead/99-nfs.rules.in b/tools/nfsrahead/99-nfs.rules.in new file mode 100644 index 00000000..648813c5 --- /dev/null +++ b/tools/nfsrahead/99-nfs.rules.in @@ -0,0 +1 @@ +SUBSYSTEM=="bdi", ACTION=="add", PROGRAM="_libexecdir_/nfsrahead %k", ATTR{read_ahead_kb}="%c" diff --git a/tools/nfsrahead/Makefile.am b/tools/nfsrahead/Makefile.am new file mode 100644 index 00000000..845ea0d5 --- /dev/null +++ b/tools/nfsrahead/Makefile.am @@ -0,0 +1,16 @@ +libexec_PROGRAMS = nfsrahead +nfsrahead_SOURCES = main.c +nfsrahead_LDFLAGS= -lmount +nfsrahead_LDADD = ../../support/nfs/libnfsconf.la + +man5_MANS = nfsrahead.man +EXTRA_DIST = $(man5_MANS) + +udev_rulesdir = /usr/lib/udev/rules.d/ +udev_rules_DATA = 99-nfs.rules + +99-nfs.rules: 99-nfs.rules.in $(builddefs) + $(SED) "s|_libexecdir_|@libexecdir@|g" 99-nfs.rules.in > $@ + +clean-local: + $(RM) 99-nfs.rules diff --git a/tools/nfsrahead/main.c b/tools/nfsrahead/main.c new file mode 100644 index 00000000..c83c6f71 --- /dev/null +++ b/tools/nfsrahead/main.c @@ -0,0 +1,192 @@ +#include +#include +#include +#include +#include + +#include +#include + +#include "xlog.h" +#include "conffile.h" + +#ifndef MOUNTINFO_PATH +#define MOUNTINFO_PATH "/proc/self/mountinfo" +#endif + +#define CONF_NAME "nfsrahead" +#define NFS_DEFAULT_READAHEAD 128 + +/* Device information from the system */ +struct device_info { + char *device_number; + dev_t dev; + char *mountpoint; + char *fstype; +}; + +/* Convert a string in the format n:m to a device number */ +static int fill_device_number(struct device_info *info) +{ + char *s = strdup(info->device_number), *p; + char *maj_s, *min_s; + unsigned int maj, min; + int err = -EINVAL; + + maj_s = p = s; + for ( ; *p != ':' && *p != '\0'; p++) + ; + + if (*p == '\0') + goto out_free; + + err = 0; + *p = '\0'; + min_s = p + 1; + + maj = strtol(maj_s, NULL, 10); + min = strtol(min_s, NULL, 10); + + info->dev = makedev(maj, min); +out_free: + free(s); + return err; +} + +#define sfree(ptr) if (ptr) free(ptr) + +/* device_info maintenance */ +static void init_device_info(struct device_info *di, const char *device_number) +{ + di->device_number = strdup(device_number); + di->dev = 0; + di->mountpoint = NULL; + di->fstype = NULL; +} + + +static void free_device_info(struct device_info *di) +{ + sfree(di->mountpoint); + sfree(di->fstype); + sfree(di->device_number); +} + +static int get_mountinfo(const char *device_number, struct device_info *device_info, const char *mountinfo_path) +{ + int ret = 0; + struct libmnt_table *mnttbl; + struct libmnt_fs *fs; + char *target; + + init_device_info(device_info, device_number); + if ((ret = fill_device_number(device_info)) < 0) + goto out_free_device_info; + + mnttbl = mnt_new_table(); + + if ((ret = mnt_table_parse_file(mnttbl, mountinfo_path)) < 0) { + xlog(D_GENERAL, "Failed to parse %s\n", mountinfo_path); + goto out_free_tbl; + } + + if ((fs = mnt_table_find_devno(mnttbl, device_info->dev, MNT_ITER_FORWARD)) == NULL) { + ret = ENOENT; + goto out_free_tbl; + } + + if ((target = (char *)mnt_fs_get_target(fs)) == NULL) { + ret = ENOENT; + goto out_free_fs; + } + + device_info->mountpoint = strdup(target); + target = (char *)mnt_fs_get_fstype(fs); + if (target) + device_info->fstype = strdup(target); + +out_free_fs: + mnt_free_fs(fs); +out_free_tbl: + mnt_free_table(mnttbl); +out_free_device_info: + free(device_info->device_number); + device_info->device_number = NULL; + return ret; +} + +static int get_device_info(const char *device_number, struct device_info *device_info) +{ + int ret = ENOENT; + for (int retry_count = 0; retry_count < 10 && ret != 0; retry_count++) + ret = get_mountinfo(device_number, device_info, MOUNTINFO_PATH); + + return ret; +} + +static int conf_get_readahead(const char *kind) { + int readahead = 0; + + if((readahead = conf_get_num(CONF_NAME, kind, -1)) == -1) + readahead = conf_get_num(CONF_NAME, "default", NFS_DEFAULT_READAHEAD); + + return readahead; +} + +int main(int argc, char **argv) +{ + int ret = 0, retry, opt; + struct device_info device; + unsigned int readahead = 128, log_level, log_stderr = 0; + + + log_level = D_ALL & ~D_GENERAL; + while((opt = getopt(argc, argv, "dF")) != -1) { + switch (opt) { + case 'd': + log_level = D_ALL; + break; + case 'F': + log_stderr = 1; + break; + } + } + + conf_init_file(NFS_CONFFILE); + + xlog_stderr(log_stderr); + xlog_syslog(~log_stderr); + xlog_config(log_level, 1); + xlog_open(CONF_NAME); + + // xlog_err causes the system to exit + if ((argc - optind) != 1) + xlog_err("expected the device number of a BDI; is udev ok?"); + + for (retry = 0; retry <= 10; retry++ ) + if ((ret = get_device_info(argv[optind], &device)) == 0) + break; + + if (ret != 0) { + xlog(D_GENERAL, "unable to find device %s\n", argv[optind]); + goto out; + } + + if (strncmp("nfs", device.fstype, 3) != 0) { + xlog(D_GENERAL, + "not setting readahead for non supported fstype %s on device %s\n", + device.fstype, argv[optind]); + ret = -EINVAL; + goto out; + } + + readahead = conf_get_readahead(device.fstype); + + xlog(D_FAC7, "setting %s readahead to %d\n", device.mountpoint, readahead); + + printf("%d\n", readahead); + +out: + free_device_info(&device); + return ret; +} diff --git a/tools/nfsrahead/nfsrahead.man b/tools/nfsrahead/nfsrahead.man new file mode 100644 index 00000000..5488f633 --- /dev/null +++ b/tools/nfsrahead/nfsrahead.man @@ -0,0 +1,72 @@ +.\" Manpage for nfsrahead. +.nh +.ad l +.TH man 5 "08 Mar 2022" "1.0" "nfsrahead man page" +.SH NAME + +nfsrahead \- Configure the readahead for NFS mounts + +.SH SYNOPSIS + +nfsrahead [-F] [-d] + +.SH DESCRIPTION + +\fInfsrahead\fR is a tool intended to be used with udev to set the \fIread_ahead_kb\fR parameter of NFS mounts, according to the configuration file (see \fICONFIGURATION\fR). \fIdevice\fR is the device number for the NFS backing device as provided by the kernel. + +.SH OPTIONS +.TP +.B -F +Send messages to +.I stderr +instead of +.I syslog + +.TP +.B -d +Increase the debugging level. + +.SH CONFIGURATION +.I nfsrahead +is configured in +.IR /etc/nfs.conf , +in the section titled +.IR nfsrahead . +It accepts the following configurations. + +.TP +.B nfs= +The readahead value applied to NFSv3 mounts. + +.TP +.B nfs4= +The readahead value applied to NFSv4 mounts. + +.TP +.B default= +The default configuration when none of the configurations above is set. + +.SH EXAMPLE CONFIGURATION +[nfsrahead] +.br +nfs=15000 # readahead of 15000 for NFSv3 mounts +.br +nfs4=16000 # readahead of 16000 for NFSv4 mounts +.br +default=128 # default is 128 + +.SH SEE ALSO + +.BR mount.nfs (8), +.BR nfs (5), +.BR nfs.conf (5), +.BR udev (7), +.BR bcc-readahead (8) + +.SH BUGS + +No known bugs. + +.SH AUTHOR + +Thiago Rafael Becker diff --git a/utils/nfsidmap/nfsidmap.man b/utils/nfsidmap/nfsidmap.man index 2af16f31..1911c41b 100644 --- a/utils/nfsidmap/nfsidmap.man +++ b/utils/nfsidmap/nfsidmap.man @@ -2,7 +2,7 @@ .\"@(#)nfsidmap(8) - The NFS idmapper upcall program .\" .\" Copyright (C) 2010 Bryan Schumaker -.TH nfsidmap 5 "1 October 2010" +.TH nfsidmap 8 "1 October 2010" .SH NAME nfsidmap \- The NFS idmapper upcall program .SH SYNOPSIS