Create shared API to access on-disk NSM data
Subsystems (2)
cover Create shared API to access on-disk NSM data
The goal of these patches is to replace duplicate code in statd and sm-notify that accesses the local NSM state number and the on-disk monitor and notify lists. This change allows us to fix bugs and add IPv6 support in one place instead of two.
There should be little behavioral change, since the new code in libnsm.a is by and large copied from existing code in statd and sm-notify. Some error checking is enhanced. The sync(2) system call done after an NSM state number update is removed, since the update is already performed with POSIX file system calls that are all synchronous with permanent storage.
---
Chuck Lever (3):
statd: Use the new nsm_ file.c calls in rpc.statd
statd: Use the new nsm_ file.c calls in sm_notify libnsm.a: Introduce common routines to handle persistent storage
support/include/Makefile.am | 2 support/include/nsm.h | 64 +++ support/nsm/Makefile.am | 2 support/nsm/file.c | 819 +++++++++++++++++++++++++++++++++++++++++++ utils/statd/misc.c | 24 - utils/statd/monitor.c | 140 ++----- utils/statd/sm-notify.c | 288 +++------------ utils/statd/statd.c | 116 +----- utils/statd/statd.h | 23 - 9 files changed, 1006 insertions(+), 472 deletions(-) create mode 100644 support/include/nsm.h create mode 100644 support/nsm/file.c
Signature · 1 line
Chuck Lever <[email protected]>
A message that is not in the archive (sent off-list or not yet received): 20100108180144.452.14970.stgit-bi+AKbBUZKY6gyzm1THtWbp2dZbC/[email protected]
PATCH 1/3 libnsm.a: Introduce common routines to handle persistent storage
rpc.statd and sm-notify access the same set of files under /var/lib/nfs/statd, but both have their own code base to handle this. They should share this code.
In addition, the on-disk format used by statd and friends is considered a formal interface, so this new code will codify the API and provide documentation for it.
The shared code handles switching from the default parent statd directory, reducing privileges at start-up, and managing the NSM state files, in addition to handling normal operations on the monitored host and notification lists on disk.
The new code is simply a copy of the same logic that was used in rpc.statd and sm-notify, but wrapped in a nice API. There should be minimal behavioral and no on-disk format changes with the new libnsm.a code.
The new code is more careful to check for bad corner cases. Occassionally this code may not allow an operation that was permitted in the past, but hopefully the error reporting has improved enough that it should be easy to track down any problems.
---
support/include/Makefile.am | 2 support/include/nsm.h | 64 +++ support/nsm/Makefile.am | 2 support/nsm/file.c | 819 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 886 insertions(+), 1 deletions(-) create mode 100644 support/include/nsm.h create mode 100644 support/nsm/file.c
support/include/Makefile.am +2 -0
@@ -9,6 +9,8 @@ noinst_HEADERS = \ nfs_mntent.h \ nfs_paths.h \ nfslib.h \ + nfsrpc.h \ + nsm.h \ rpcmisc.h \ tcpwrapper.h \ xio.h \
support/include/nsm.h new file +64 -0
64 lines not on this page · raw message
support/nsm/Makefile.am +1 -1
@@ -10,7 +10,7 @@ GENFILES = $(GENFILES_CLNT) $(GENFILES_SVC) $(GENFILES_XDR) $(GENFILES_H) EXTRA_DIST = sm_inter.x noinst_LIBRARIES = libnsm.a -libnsm_a_SOURCES = $(GENFILES) +libnsm_a_SOURCES = $(GENFILES) file.c BUILT_SOURCES = $(GENFILES)
support/nsm/file.c new file +819 -0
819 lines not on this page · raw message
PATCH 2/3 statd: Use the new nsm_ file.c calls in sm_notify
In reply to a message not in the archiveReplace open-coded accesses to on-disk NSM data with calls to the new libnsm.a API.
One major change is that sync(2) is no longer called when the NSM state number is updated at boot time. Otherwise sm-notify should behave much the same as it did before.
---
utils/statd/sm-notify.c | 288 ++++++++++------------------------------------- 1 files changed, 63 insertions(+), 225 deletions(-)
utils/statd/sm-notify.c +63 -225
@@ -8,6 +8,7 @@#include <config.h> #endif +#include <err.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/stat.h>
@@ -29,25 +30,9 @@#include <grp.h> #include "xlog.h" +#include "nsm.h" #include "nfsrpc.h" -#ifndef BASEDIR -# ifdef NFS_STATEDIR -# define BASEDIR NFS_STATEDIR -# else -# define BASEDIR "/var/lib/nfs" -# endif -#endif - -#define DEFAULT_SM_STATE_PATH BASEDIR "/state" -#define DEFAULT_SM_DIR_PATH BASEDIR "/sm" -#define DEFAULT_SM_BAK_PATH DEFAULT_SM_DIR_PATH ".bak" - -char *_SM_BASE_PATH =BASEDIR ; -char *_SM_STATE_PATH =DEFAULT_SM_STATE_PATH ; -char *_SM_DIR_PATH =DEFAULT_SM_DIR_PATH ; -char *_SM_BAK_PATH =DEFAULT_SM_BAK_PATH ; -#define NSM_PROG 100024#define NSM_PROGRAM 100024#define NSM_VERSION 1
@@ -59,7 +44,6 @@ char *_SM_BAK_PATH = DEFAULT_SM_BAK_PATH;struct nsm_host {struct nsm_host * next;char * name; -char * path;struct sockaddr_storage addr;struct addrinfo *ai;time_t last_used;
@@ -70,24 +54,19 @@ struct nsm_host { };static char nsm_hostname[256 ]; -static uint32_t nsm_state; +static int nsm_state;static int opt_debug =0 ; -static int opt_update_state =1 ; +static _Bool opt_update_state = true;static unsigned int opt_max_retry =15 *60 ;static char * opt_srcaddr =0 ;static uint16_t opt_srcport =0 ; -static unsigned int nsm_get_state (int );static void notify (void );static int notify_host (int ,struct nsm_host *);static void recv_reply (int ); -static void backup_hosts (const char *,const char *); -static void get_hosts (const char *);static void insert_host (struct nsm_host *);static struct nsm_host *find_host (uint32_t );static int record_pid (void ); -static void drop_privs (void ); -static void set_kernel_nsm_state (int state);static struct nsm_host * hosts =NULL ;
@@ -111,10 +90,39 @@ static struct addrinfo *smn_lookup(const char *name)return ai; } +__attribute_malloc__ +static struct nsm_host * +smn_alloc_host (const char *hostname,const time_t timestamp) +{ +struct nsm_host *host; + + host =calloc (1 ,sizeof (*host)); +if (host ==NULL ) + goto out_nomem; + + host->name =strdup (hostname); +if (host->name ==NULL ) { +free (host); + goto out_nomem; + } + + host->last_used = timestamp; + host->timeout =NSM_TIMEOUT ; + host->retries =100 ;/* force address retry */ + +return host; + +out_nomem: +xlog_warn ("Unable to allocate memory" ); +return NULL ; +} +static void smn_forget_host (struct nsm_host *host) { -unlink (host->path); -free (host->path); +xlog (D_CALL ,"Removing %s from notify list" , host->name); + +nsm_delete_notified_host (host->name); +free (host->name);if (host->ai)freeaddrinfo (host->ai);
@@ -122,6 +130,23 @@ static void smn_forget_host(struct nsm_host *host)free (host); } +static unsigned int +smn_get_host (const char *hostname, + __attribute__ ((unused))const struct sockaddr *sap, + __attribute__ ((unused))const struct mon *m, +const time_t timestamp) +{ +struct nsm_host *host; + + host =smn_alloc_host (hostname, timestamp); +if (host ==NULL ) +return 0 ; + +insert_host (host); +xlog (D_GENERAL ,"Added host %s to notify list" , hostname); +return 1 ; +} +int main (int argc,char **argv) {
@@ -147,7 +172,7 @@ main(int argc, char **argv) opt_max_retry =atoi (optarg) *60 ;break ;case 'n' : - opt_update_state =0 ; + opt_update_state = false;break ;case 'p' : opt_srcport =atoi (optarg);
@@ -156,20 +181,8 @@ main(int argc, char **argv) opt_srcaddr = optarg;break ;case 'P' : - _SM_BASE_PATH =strdup (optarg); - _SM_STATE_PATH =malloc (strlen (optarg)+1 +sizeof ("state" )); - _SM_DIR_PATH =malloc (strlen (optarg)+1 +sizeof ("sm" )); - _SM_BAK_PATH =malloc (strlen (optarg)+1 +sizeof ("sm.bak" )); -if (_SM_BASE_PATH ==NULL || - _SM_STATE_PATH ==NULL || - _SM_DIR_PATH ==NULL || - _SM_BAK_PATH ==NULL ) { -fprintf (stderr,"unable to allocate memory" ); +if (!nsm_setup_pathnames (argv[0 ], optarg))exit (1 ); - } -strcat (strcpy (_SM_STATE_PATH, _SM_BASE_PATH),"/state" ); -strcat (strcpy (_SM_DIR_PATH, _SM_BASE_PATH),"/sm" ); -strcat (strcpy (_SM_BAK_PATH, _SM_BASE_PATH),"/sm.bak" );break ;default :
@@ -195,8 +208,8 @@ usage: fprintf(stderr,xlog_open (progname);xlog (L_NOTICE ,"Version " VERSION " starting" ); -if (strcmp (_SM_BASE_PATH,BASEDIR ) ==0 ) { -if (record_pid () ==0 && force ==0 && opt_update_state ==1 ) { +if (nsm_is_default_parentdir ()) { +if (record_pid () ==0 && force ==0 && opt_update_state) {/* already run, don't try again */ xlog (L_NOTICE ,"Already notifying clients; Exiting!" );exit (0 );
@@ -211,18 +224,16 @@ usage: fprintf(stderr,exit (1 ); } -backup_hosts (_SM_DIR_PATH, _SM_BAK_PATH); -get_hosts (_SM_BAK_PATH); - -/* If there are not hosts to notify, just exit */ -if (!hosts) { + (void )nsm_retire_monitored_hosts (); +if (nsm_load_notify_list (smn_get_host) ==0 ) {xlog (D_GENERAL ,"No hosts to notify; exiting" );return 0 ; } -/* Get and update the NSM state. This will call sync() */ nsm_state =nsm_get_state (opt_update_state); -set_kernel_nsm_state (nsm_state); +if (nsm_state ==0 ) +exit (1 ); +nsm_update_kernel_state (nsm_state);if (!opt_debug) {xlog (L_NOTICE ,"Backgrounding to notify hosts...\n" );
@@ -316,7 +327,8 @@ notify(void)if (opt_max_retry) failtime =time (NULL ) + opt_max_retry; -drop_privs (); +if (!nsm_drop_privileges (-1 )) +exit (1 );while (hosts) {struct pollfd pfd;
@@ -554,82 +566,6 @@ fail: /* Re-insert the host */ }/* -* Back up all hosts from the sm directory to sm.bak -*/ -static void -backup_hosts (const char *dirname,const char *bakname) -{ -struct dirent *de; -DIR *dir; - -if (!(dir =opendir (dirname))) { -xlog_warn ("Failed to open %s: %m" , dirname); -return ; - } - -while ((de =readdir (dir)) !=NULL ) { -char src[1024 ], dst[1024 ]; - -if (de->d_name[0 ] =='.' ) -continue ; - -snprintf (src,sizeof (src),"%s/%s" , dirname, de->d_name); -snprintf (dst,sizeof (dst),"%s/%s" , bakname, de->d_name); -if (rename (src, dst) <0 ) -xlog_warn ("Failed to rename %s -> %s: %m" , src, dst); - } -closedir (dir); -} - -/* -* Get all entries from sm.bak and convert them to host entries -*/ -static void -get_hosts (const char *dirname) -{ -struct nsm_host *host; -struct dirent *de; -DIR *dir; - -if (!(dir =opendir (dirname))) { -xlog_warn ("Failed to open %s: %m" , dirname); -return ; - } - - host =NULL ; -while ((de =readdir (dir)) !=NULL ) { -struct stat stb; -char path[1024 ]; - -if (de->d_name[0 ] =='.' ) -continue ; -if (host ==NULL ) - host =calloc (1 ,sizeof (*host)); -if (host ==NULL ) { -xlog_warn ("Unable to allocate memory" ); -return ; - } - -snprintf (path,sizeof (path),"%s/%s" , dirname, de->d_name); -if (stat (path, &stb) <0 ) -continue ; - - host->last_used = stb.st_mtime; - host->timeout =NSM_TIMEOUT ; - host->path =strdup (path); - host->name =strdup (de->d_name); - host->retries =100 ;/* force address retry */ - -insert_host (host); - host =NULL ; - } -closedir (dir); - -if (host) -free (host); -} - -/* * Insert host into sorted list */ static void
@@ -676,60 +612,6 @@ find_host(uint32_t xid)return NULL ; } - -/* -* Retrieve the current NSM state -*/ -static unsigned int -nsm_get_state (int update) -{ -char newfile[PATH_MAX ]; -int fd, state; - -if ((fd =open (_SM_STATE_PATH,O_RDONLY )) <0 ) { -xlog_warn ("%s: %m" , _SM_STATE_PATH); -xlog_warn ("Creating %s, set initial state 1" , - _SM_STATE_PATH); - state =1 ; - update =1 ; - }else { -if (read (fd, &state,sizeof (state)) !=sizeof (state)) { -xlog_warn ("%s: bad file size, setting state = 1" , - _SM_STATE_PATH); - state =1 ; - update =1 ; - }else { -if (!(state &1 )) - state +=1 ; - } -close (fd); - } - -if (update) { - state +=2 ; -snprintf (newfile,sizeof (newfile), -"%s.new" , _SM_STATE_PATH); -if ((fd =open (newfile,O_CREAT |O_WRONLY ,0644 )) <0 ) { -xlog (L_ERROR ,"Cannot create %s: %m" , newfile); -exit (1 ); - } -if (write (fd, &state,sizeof (state)) !=sizeof (state)) { -xlog (L_ERROR , -"Failed to write state to %s" , newfile); -exit (1 ); - } -close (fd); -if (rename (newfile, _SM_STATE_PATH) <0 ) { -xlog (L_ERROR , -"Cannot create %s: %m" , _SM_STATE_PATH); -exit (1 ); - } -sync (); - } - -return state; -} -/* * Record pid in /var/run/sm-notify.pid * This file should remain until a reboot, even if the
@@ -756,47 +638,3 @@ static int record_pid(void) (void )close (fd);return 1 ; } - -/* Drop privileges to match owner of state-directory -* (in case a reply triggers some unknown bug). -*/ -static void drop_privs (void ) -{ -struct stat st; - -if (stat (_SM_DIR_PATH, &st) ==-1 && -stat (_SM_BASE_PATH, &st) ==-1 ) { - st.st_uid =0 ; - st.st_gid =0 ; - } - -if (st.st_uid ==0 ) { -xlog_warn ("Running as 'root'. " -"chown %s to choose different user" , _SM_DIR_PATH); -return ; - } - -setgroups (0 ,NULL ); -if (setgid (st.st_gid) ==-1 - ||setuid (st.st_uid) ==-1 ) { -xlog (L_ERROR ,"Fail to drop privileges" ); -exit (1 ); - } -} - -static void set_kernel_nsm_state (int state) -{ -int fd; -const char *file ="/proc/sys/fs/nfs/nsm_local_state" ; - - fd =open (file ,O_WRONLY ); -if (fd >=0 ) { -char buf[20 ]; -snprintf (buf,sizeof (buf),"%d" , state); -if (write (fd, buf,strlen (buf)) !=strlen (buf)) { -xlog_warn ("Writing to '%s' failed: errno %d (%m)" , - file, errno); - } -close (fd); - } -}
PATCH 3/3 statd: Use the new nsm_ file.c calls in rpc.statd
In reply to a message not in the archiveReplace open-coded accesses to on-disk NSM information in rpc.statd with calls to the new API.
Behavior should be much the same as it was before.
---
utils/statd/misc.c | 24 -------- utils/statd/monitor.c | 140 ++++++++++++++++--------------------------------- utils/statd/statd.c | 116 ++++------------------------------------- utils/statd/statd.h | 23 -------- 4 files changed, 57 insertions(+), 246 deletions(-)
utils/statd/misc.c +0 -24
@@ -49,27 +49,3 @@ xstrdup (const char *string)return (result); } - - -/* -* Unlinking a file. -*/ -void -xunlink (char *path,char *host) -{ -char *tozap; - - tozap =malloc (strlen (path)+strlen (host)+2 ); -if (tozap ==NULL ) { -xlog (L_ERROR ,"xunlink: malloc failed: errno %d (%m)" , errno); -return ; - } -sprintf (tozap,"%s/%s" , path, host); - -if (unlink (tozap) ==-1 ) -xlog (L_ERROR ,"unlink (%s): %m" , tozap); -else -xlog (D_GENERAL ,"Unlinked %s" , tozap); - -free (tozap); -}
utils/statd/monitor.c +45 -95
208 lines not on this page · raw message
utils/statd/statd.c +12 -104
169 lines not on this page · raw message
utils/statd/statd.h +0 -23
@@ -14,28 +14,6 @@#include "xlog.h" /* -* Paths and filenames. -*/ -#if defined(NFS_STATEDIR ) -# define DEFAULT_DIR_BASE NFS_STATEDIR "/" -#else -# define DEFAULT_DIR_BASE "/var/lib/nfs/" -#endif - -#define DEFAULT_SM_DIR DEFAULT_DIR_BASE "sm" -#define DEFAULT_SM_BAK_DIR DEFAULT_DIR_BASE "sm.bak" -#define DEFAULT_SM_STAT_PATH DEFAULT_DIR_BASE "state" - -/* Added to support run-time specification of state directory path. -* [email protected] -*/ - -extern char *DIR_BASE ; -extern char *SM_DIR ; -extern char *SM_BAK_DIR ; -extern char *SM_STAT_PATH ; - -/* * Status definitions. */ #define STAT_FAIL stat_fail
@@ -53,7 +31,6 @@ extern int process_notify_list(void);extern int process_reply (FD_SET_TYPE *);extern char *xstrdup (const char *);extern void *xmalloc (size_t ); -extern void xunlink (char *,char *);extern void load_state (void );/*
Quoted 12 lines · Chuck Lever
The goal of these patches is to replace duplicate code in statd and sm-notify that accesses the local NSM state number and the on-disk monitor and notify lists. This change allows us to fix bugs and add IPv6 support in one place instead of two.
There should be little behavioral change, since the new code in libnsm.a is by and large copied from existing code in statd and sm-notify. Some error checking is enhanced. The sync(2) system call done after an NSM state number update is removed, since the update is already performed with POSIX file system calls that are all synchronous with permanent storage.
Quoted 6 lines
---
Chuck Lever (3):
statd: Use the newnsm_file.ccalls in rpc.statd
statd: Use the newnsm_file.ccalls insm_notifylibnsm.a: Introduce common routines to handle persistent storage
Committed...
steved.