Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,11 @@ aclocal.m4
.deps
/*.exe
*.dSYM/
simdtest
t_chmod_secure
t_secure_relpath
testsuite/__pycache__/
testsuite/chown-fake_test.py
testsuite/devices-fake_test.py
testsuite/exclude-lsh_test.py
testsuite/xattrs-hlink_test.py
2 changes: 1 addition & 1 deletion Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ zlib_OBJS=zlib/deflate.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o \
OBJS1=flist.o rsync.o generator.o receiver.o cleanup.o sender.o exclude.o \
util1.o util2.o main.o checksum.o match.o syscall.o log.o backup.o delete.o
OBJS2=options.o io.o compat.o hlink.o token.o uidlist.o socket.o hashtable.o \
usage.o fileio.o batch.o clientname.o chmod.o acls.o xattrs.o
usage.o fileio.o batch.o clientname.o chmod.o acls.o xattrs.o niceness.o
OBJS3=progress.o pipe.o @MD5_ASM@ @ROLL_SIMD@ @ROLL_ASM@
DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
popt_OBJS= popt/popt.o popt/poptconfig.o \
Expand Down
4 changes: 3 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ AC_CHECK_HEADERS(sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h \
sys/acl.h acl/libacl.h attr/xattr.h sys/xattr.h sys/extattr.h dl.h \
popt.h popt/popt.h linux/falloc.h netinet/in_systm.h netgroup.h \
zlib.h xxhash.h openssl/md4.h openssl/md5.h zstd.h lz4.h sys/file.h \
bsd/string.h)
bsd/string.h sys/resource.h linux/ioprio.h sys/syscall.h)
AC_CHECK_HEADERS([netinet/ip.h], [], [], [[#include <netinet/in.h>]])
AC_HEADER_MAJOR_FIXED

Expand Down Expand Up @@ -1465,6 +1465,8 @@ case "$CC" in
;;
esac

AC_DEFINE_UNQUOTED([COMPILE_TARGET], ["$host"], [String describing the compiled target OS and architecture])

AC_CONFIG_FILES([Makefile lib/dummy zlib/dummy popt/dummy shconfig])
AC_OUTPUT

Expand Down
10 changes: 10 additions & 0 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ extern char backup_dir_buf[MAXPATHLEN];
extern char *basis_dir[MAX_BASIS_DIRS+1];
extern struct file_list *first_flist;
extern filter_rule_list daemon_filter_list, implied_filter_list;
extern int nice_local;
extern int ionice_local;

uid_t our_uid;
gid_t our_gid;
Expand Down Expand Up @@ -1835,6 +1837,14 @@ int main(int argc,char *argv[])
if (write_batch < 0)
dry_run = 1;

if (nice_local) {
renice_me(nice_local);
}

if (ionice_local) {
ionice_me();
}

if (am_server) {
#ifdef ICONV_CONST
setup_iconv();
Expand Down
70 changes: 70 additions & 0 deletions niceness.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Renice or ionice the current process to reduce its impact on the system
*
* Copyright (C) 2026 Michael Mess
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, visit the http://fsf.org website.
*/

#include "rsync.h"

extern int am_server;

int get_renice_default_prio()
{
return 19; // lowest CPU Priority
}

void renice_me(int prio)
{
#ifdef SUPPORT_RENICE
int which = PRIO_PROCESS; // who specifies a Process ID
int who = 0; // 0 means current process
int result = setpriority(which, who, prio);
if ( result < 0 ) {
// Failed to set priority, inform user, but can be ignored (it's just not so nice).
rprintf(FWARNING, "renice to %d rejected by OS (%s version %s): %s\n",
prio, RSYNC_NAME, rsync_version(), strerror(errno));
} else {
if (DEBUG_GTE(CMD, 1))
rprintf(FINFO, "successfully reniced %s to new priority %d\n", am_server ? "server" : "client", prio);
}
#else
rprintf(FWARNING, "renice not supported for %s (%s: %s version %s)\n",
COMPILE_TARGET, am_server ? "server" : "client", RSYNC_NAME, rsync_version());
#endif
}

void ionice_me()
{
#ifdef SUPPORT_IONICE
int which = IOPRIO_WHO_PROCESS; // who specifies a Process ID
int who = 0; // 0 means current process
int class = IOPRIO_CLASS_IDLE;
int data = 0; // Ignored when using the IOPRIO_CLASS_IDLE class
int ioprio = IOPRIO_PRIO_VALUE(class, data);
int result = syscall(SYS_ioprio_set, which, who, ioprio);
if ( result < 0 ) {
// Failed to set priority, inform user, but can be ignored (it's just not so ionice).
rprintf(FWARNING, "ionice rejected by OS (%s version %s)\n",
RSYNC_NAME, rsync_version());
} else {
if (DEBUG_GTE(CMD, 1))
rprintf(FINFO, "successfully ioniced %s\n", am_server ? "server" : "client");
}
#else
rprintf(FWARNING, "ionice not supported for %s (%s: %s version %s)\n",
COMPILE_TARGET, am_server ? "server" : "client", RSYNC_NAME, rsync_version());
#endif
}
100 changes: 99 additions & 1 deletion options.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,19 @@ extern filter_rule_list daemon_filter_list;

int make_backups = 0;

/* If set to other than 0, be nice on the local or remote site
* Contains the nice priority to be set on the process, or 0=feature is turned off, no priority will be set.
* I have to admit, that it is not possible to set a nice value of 0 with this code,
* but in most cases 0 should be the priority of the newly started rsync process already anyway.
*/
int nice_local = 0;
int nice_remote = 0;
/* If set to other than 0, be ionice on the local or remote site
* Currently only idle is supported for ionice when turned on.
*/
int ionice_local = 0;
int ionice_remote = 0;

/**
* If 1, send the whole file as literal data rather than trying to
* create an incremental diff.
Expand Down Expand Up @@ -594,7 +607,8 @@ enum {OPT_SERVER = 1000, OPT_DAEMON, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
OPT_NO_D, OPT_APPEND, OPT_NO_ICONV, OPT_INFO, OPT_DEBUG, OPT_BLOCK_SIZE,
OPT_USERMAP, OPT_GROUPMAP, OPT_CHOWN, OPT_BWLIMIT, OPT_STDERR,
OPT_OLD_COMPRESS, OPT_NEW_COMPRESS, OPT_NO_COMPRESS, OPT_OLD_ARGS,
OPT_STOP_AFTER, OPT_STOP_AT,
OPT_STOP_AFTER, OPT_STOP_AT, OPT_NICE, OPT_NO_NICE, OPT_IONICE, OPT_NO_IONICE,
OPT_NICE_LOCAL, OPT_NICE_REMOTE, OPT_NICE_VALUE,
OPT_REFUSED_BASE = 9000};

static struct poptOption long_options[] = {
Expand Down Expand Up @@ -845,6 +859,22 @@ static struct poptOption long_options[] = {
{"remote-option", 'M', POPT_ARG_STRING, 0, 'M', 0, 0 },
{"protocol", 0, POPT_ARG_INT, &protocol_version, 0, 0, 0 },
{"checksum-seed", 0, POPT_ARG_INT, &checksum_seed, 0, 0, 0 },
{"nice-local", 0, POPT_ARG_NONE, 0, OPT_NICE_LOCAL, 0, 0 },
{"nice-local-value", 0, POPT_ARG_INT, &nice_local, 0, 0, 0 },
{"nice-remote", 0, POPT_ARG_NONE, 0, OPT_NICE_REMOTE, 0, 0 },
{"nice-remote-value",0, POPT_ARG_INT, &nice_remote, 0, 0, 0 },
{"ionice-local", 0, POPT_ARG_VAL, &ionice_local, 1, 0, 0 },
{"ionice-remote", 0, POPT_ARG_VAL, &ionice_remote, 1, 0, 0 },
{"no-nice-local", 0, POPT_ARG_VAL, &nice_local, 0, 0, 0 },
{"no-nice-remote", 0, POPT_ARG_VAL, &nice_remote, 0, 0, 0 },
{"no-ionice-local", 0, POPT_ARG_VAL, &ionice_local, 0, 0, 0 },
{"no-ionice-remote", 0, POPT_ARG_VAL, &ionice_remote, 0, 0, 0 },
{"nice", 0, POPT_ARG_NONE, 0, OPT_NICE, 0, 0 },
{"nice-value", 0, POPT_ARG_INT, &nice_local, OPT_NICE_VALUE, 0, 0 },
{"ionice", 0, POPT_ARG_NONE, 0, OPT_IONICE, 0, 0 },
{"no-nice", 0, POPT_ARG_NONE, 0, OPT_NO_NICE, 0, 0 },
{"no-ionice", 0, POPT_ARG_NONE, 0, OPT_NO_IONICE, 0, 0 },
{"nice-and-ionice", 'Q', POPT_ARG_NONE, 0, 'Q', 0, 0 },
{"server", 0, POPT_ARG_NONE, 0, OPT_SERVER, 0, 0 },
{"sender", 0, POPT_ARG_NONE, 0, OPT_SENDER, 0, 0 },
/* All the following options switch us into daemon-mode option-parsing. */
Expand Down Expand Up @@ -1365,6 +1395,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
int argc = *argc_p;
int opt, want_dest_type;
int orig_protect_args = protect_args;
int default_nice_prio = get_renice_default_prio(); // default nice priority to be used, if no explicit priority is given.

if (argc == 0) {
strlcpy(err_buf, "argc is zero!\n", sizeof err_buf);
Expand Down Expand Up @@ -1598,6 +1629,60 @@ int parse_arguments(int *argc_p, const char ***argv_p)
quiet++;
break;

case 'Q':
/*
* Turn nice on with default prio when it was turned off, but do not overwrite any previously set nice value.
*/
nice_local = nice_local==0 ? default_nice_prio : nice_local;
nice_remote = nice_remote==0 ? default_nice_prio : nice_remote;
ionice_local = 1;
ionice_remote = 1;
break;

case OPT_NICE:
/*
* Turn nice on with default prio when it was turned off, but do not overwrite any previously set nice value.
*/
nice_local = nice_local==0 ? default_nice_prio : nice_local;
nice_remote = nice_remote==0 ? default_nice_prio : nice_remote;
break;

case OPT_NICE_VALUE:
/*
* POPT writes to nice_local. We have to copy the value from nice-local to nice-remote here.
*/
nice_remote = nice_local;
break;

case OPT_NICE_LOCAL:
/*
* Turn nice on with default prio when it was turned off, but do not overwrite any previously set nice value.
*/
nice_local = nice_local==0 ? default_nice_prio : nice_local;
break;

case OPT_NICE_REMOTE:
/*
* Turn nice on with default prio when it was turned off, but do not overwrite any previously set nice value.
*/
nice_remote = nice_remote==0 ? default_nice_prio : nice_remote;
break;

case OPT_IONICE:
ionice_local = 1;
ionice_remote = 1;
break;

case OPT_NO_NICE:
nice_local = 0;
nice_remote = 0;
break;

case OPT_NO_IONICE:
ionice_local = 0;
ionice_remote = 0;
break;

case 'x':
one_file_system++;
break;
Expand Down Expand Up @@ -2996,6 +3081,19 @@ void server_options(char **args, int *argc_p)
if (mkpath_dest_arg && am_sender)
args[ac++] = "--mkpath";

if (nice_remote) {
if (get_renice_default_prio()==nice_remote) {
args[ac++] = "--nice-local";
} else {
if (asprintf(&arg, "--nice-local-value=%d", nice_remote) < 0)
goto oom;
args[ac++] = arg;
}
}

if (ionice_remote)
args[ac++] = "--ionice-local";

if (ac > MAX_SERVER_ARGS) { /* Not possible... */
rprintf(FERROR, "argc overflow in server_options().\n");
exit_cleanup(RERR_MALLOC);
Expand Down
13 changes: 13 additions & 0 deletions rsync.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,16 @@ has its own detailed description later in this manpage.
--checksum-seed=NUM set block/file checksum seed (advanced)
--ipv4, -4 prefer IPv4
--ipv6, -6 prefer IPv6
--nice-local renice local process to low priority
--nice-remote renice remote process to low priority
--ionice-local ionice local process to low priority
--ionice-remote ionice remote process to low priority
--nice, --ionice set local and remote process to low priority
--nice-local-value=10 renice local process to given priority
--nice-remote-value=10 renice remote process to given priority
--nice-value=10 renice local+remote process to given priority
--no-nice, ... prepending "no-" turns the given option off
--nice-and-ionice, -Q same as --nice --ionice
--version, -V print the version + other info and exit
--help, -h (*) show this help (* -h is help only on its own)
```
Expand All @@ -579,6 +589,9 @@ accepted:
--log-file=FILE override the "log file" setting
--log-file-format=FMT override the "log format" setting
--sockopts=OPTIONS specify custom TCP options
--nice-local renice local daemon process to low priority
--ionice-local ionice local daemon process to low priority
They are given at client site as (io)nice-remote
--verbose, -v increase verbosity
--ipv4, -4 prefer IPv4
--ipv6, -6 prefer IPv6
Expand Down
17 changes: 17 additions & 0 deletions rsync.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
* with this program; if not, visit the http://fsf.org website.
*/

#ifndef RSYNC_H // Ensure that this header file is never included more than once, thus avoiding errors with duplicate definitions
#define RSYNC_H 1

#define False 0
#define True 1
#define Unset (-1) /* Our BOOL values are always an int. */
Expand Down Expand Up @@ -1510,3 +1513,17 @@ const char *get_panic_action(void);
#elif defined HAVE_MALLINFO
#define MEM_ALLOC_INFO mallinfo
#endif

/* Some header files needed to be nice ;) */
#ifdef HAVE_SYS_RESOURCE_H
#define SUPPORT_RENICE
#include <sys/resource.h>
#endif

#if defined HAVE_LINUX_IOPRIO_H && defined HAVE_SYS_SYSCALL_H
#define SUPPORT_IONICE
#include <linux/ioprio.h>
#include <sys/syscall.h>
#endif

#endif // ifndef RSYNC_H
Loading