/* * llmnrd -- LLMNR (RFC 4705) responder daemon. * * Copyright (C) 2014-2015 Tobias Klauser * * This file is part of llmnrd. * * llmnrd 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, version 2 of the License. * * llmnrd 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 llmnrd. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include "compiler.h" #include "log.h" #include "util.h" #include "iface.h" #include "llmnr.h" #include "llmnr-packet.h" static const char *short_opts = "H:p:6dhV"; static const struct option long_opts[] = { { "hostname", required_argument, NULL, 'H' }, { "port", required_argument, NULL, 'p' }, { "ipv6", no_argument, NULL, '6' }, { "daemonize", no_argument, NULL, 'd' }, { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 }, }; static void __noreturn usage_and_exit(int status) { fprintf(stdout, "Usage: llmnrd [OPTIONS]\n" "Options:\n" " -H, --hostname NAME set hostname to respond with (default: system hostname)\n" " -p, --port NUM set port number to listen on (default: %d)\n" " -6, --ipv6 enable LLMNR name resolution over IPv6\n" " -d, --daemonize run as daemon in the background\n" " -h, --help show this help and exit\n" " -V, --version show version information and exit\n", LLMNR_UDP_PORT); exit(status); } static void __noreturn version_and_exit(void) { fprintf(stdout, "llmnrd %s %s\n" "Copyright (C) 2014-2015 Tobias Klauser \n" "Licensed under the GNU General Public License, version 2\n", VERSION_STRING, GIT_VERSION); exit(EXIT_SUCCESS); } static void signal_handler(int sig) { switch (sig) { case SIGINT: case SIGQUIT: case SIGTERM: log_info("Interrupt received. Stopping llmnrd.\n"); iface_stop(); llmnr_stop(); break; case SIGHUP: default: /* ignore */ break; } } static void register_signal(int sig, void (*handler)(int)) { sigset_t block_mask; struct sigaction saction; sigfillset(&block_mask); saction.sa_handler = handler; saction.sa_mask = block_mask; if (sigaction(sig, &saction, NULL) != 0) { log_err("Failed to register signal handler for %s (%d)\n", strsignal(sig), sig); } } int main(int argc, char **argv) { int c, ret = EXIT_FAILURE; long num_arg; bool daemonize = false, ipv6 = false; char *hostname = NULL; uint16_t port = LLMNR_UDP_PORT; while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { switch (c) { case 'd': daemonize = true; break; case 'H': hostname = xstrdup(optarg); break; case 'p': num_arg = strtol(optarg, NULL, 0); if (num_arg < 0 || num_arg > UINT16_MAX) { log_err("Invalid port number: %ld\n", num_arg); return EXIT_FAILURE; } port = num_arg; case '6': ipv6 = true; break; case 'V': version_and_exit(); case 'h': usage_and_exit(EXIT_SUCCESS); default: usage_and_exit(EXIT_FAILURE); } } register_signal(SIGINT, signal_handler); register_signal(SIGQUIT, signal_handler); register_signal(SIGTERM, signal_handler); register_signal(SIGHUP, signal_handler); if (!hostname) { /* TODO: Consider hostname changing at runtime */ hostname = xmalloc(255); if (gethostname(hostname, 255) != 0) { log_err("Failed to get hostname"); return EXIT_FAILURE; } } if (daemonize) { if (daemon(0, 0) != 0) { log_err("Failed to daemonize process: %s\n", strerror(errno)); return EXIT_FAILURE; } } if (llmnr_init(hostname, port, ipv6) < 0) goto out; if (iface_start_thread() < 0) goto out; ret = llmnr_run(); out: free(hostname); return ret; } '>
authorDave Chinner <dchinner@redhat.com>2016-05-18 13:52:42 +1000
committerDave Chinner <david@fromorbit.com>2016-05-18 13:52:42 +1000
commit8179c03629de67f515d3ab825b5a9428687d4b85 (patch)
tree4c2f102c09531ba272bcec587c754c50f3d54712 /Documentation
parentf55532a0c0b8bb6148f4e07853b876ef73bc69ca (diff)
xfs: remove xfs_fs_evict_inode()
Joe Lawrence reported a list_add corruption with 4.6-rc1 when testing some custom md administration code that made it's own block device nodes for the md array. The simple test loop of: for i in {0..100}; do mknod --mode=0600 $tmp/tmp_node b $MAJOR $MINOR mdadm --detail --export $tmp/tmp_node > /dev/null rm -f $tmp/tmp_node done Would produce this warning in bd_acquire() when mdadm opened the device node: list_add double add: new=ffff88043831c7b8, prev=ffff8804380287d8, next=ffff88043831c7b8. And then produce this from bd_forget from kdevtmpfs evicting a block dev inode: list_del corruption. prev->next should be ffff8800bb83eb10, but was ffff88043831c7b8 This is a regression caused by commit c19b3b05 ("xfs: mode di_mode to vfs inode"). The issue is that xfs_inactive() frees the unlinked inode, and the above commit meant that this freeing zeroed the mode in the struct inode. The problem is that after evict() has called ->evict_inode, it expects the i_mode to be intact so that it can call bd_forget() or cd_forget() to drop the reference to the block device inode attached to the XFS inode. In reality, the only thing we do in xfs_fs_evict_inode() that is not generic is call xfs_inactive(). We can move the xfs_inactive() call to xfs_fs_destroy_inode() without any problems at all, and this will leave the VFS inode intact until it is completely done with it. So, remove xfs_fs_evict_inode(), and do the work it used to do in ->destroy_inode instead. cc: <stable@vger.kernel.org> # 4.6 Reported-by: Joe Lawrence <joe.lawrence@stratus.com> Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Brian Foster <bfoster@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
Diffstat (limited to 'Documentation')