From d86fc3ec8c99aaa5ffaa14a97525154507c39df7 Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Wed, 16 Jan 2008 12:17:03 +0300 Subject: Add support for offline files support, remote storage, and Async I/O force operations to VFS Offline files support and remote storage are for allowing communication with backup and archiving tools that mark files moved to a tape library as offline. We translate this info into corresponding CIFS offline file attribute and mark an exported volume as remote storage. Async I/O force is to allow selective redirection of I/O operations to asynchronous processing in case it is viable at VFS module discretion. It is needed for proper handling of offline files as performing regular I/O on offline file will block smbd. Signed-off-by: Alexander Bokovoy (This used to be commit 875208724e39564fe81385dfe36e6c963e79e101) --- source3/smbd/dmapi.c | 71 +++++++++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 31 deletions(-) (limited to 'source3/smbd/dmapi.c') diff --git a/source3/smbd/dmapi.c b/source3/smbd/dmapi.c index 05e9138ea9..620baf199e 100644 --- a/source3/smbd/dmapi.c +++ b/source3/smbd/dmapi.c @@ -46,7 +46,7 @@ bool dmapi_have_session(void) { return False; } #define DMAPI_SESSION_NAME "samba" #define DMAPI_TRACE 10 -static dm_sessid_t dmapi_session = DM_NO_SESSION; +static dm_sessid_t samba_dmapi_session = DM_NO_SESSION; /* Initialise the DMAPI interface. Make sure that we only end up initialising * once per process to avoid resource leaks across different DMAPI @@ -75,7 +75,7 @@ static int init_dmapi_service(void) bool dmapi_have_session(void) { - return dmapi_session != DM_NO_SESSION; + return samba_dmapi_session != DM_NO_SESSION; } static dm_sessid_t *realloc_session_list(dm_sessid_t * sessions, int count) @@ -110,7 +110,7 @@ int dmapi_init_session(void) */ SMB_WARN(getuid() == 0, "dmapi_init_session must be called as root"); - dmapi_session = DM_NO_SESSION; + samba_dmapi_session = DM_NO_SESSION; if (init_dmapi_service() < 0) { return -1; } @@ -139,7 +139,7 @@ retry: err = dm_query_session(sessions[i], sizeof(buf), buf, &buflen); buf[sizeof(buf) - 1] = '\0'; if (err == 0 && strcmp(DMAPI_SESSION_NAME, buf) == 0) { - dmapi_session = sessions[i]; + samba_dmapi_session = sessions[i]; DEBUGADD(DMAPI_TRACE, ("attached to existing DMAPI session " "named '%s'\n", buf)); @@ -150,16 +150,15 @@ retry: TALLOC_FREE(sessions); /* No session already defined. */ - if (dmapi_session == DM_NO_SESSION) { - err = dm_create_session(DM_NO_SESSION, - CONST_DISCARD(char *, - DMAPI_SESSION_NAME), - &dmapi_session); + if (samba_dmapi_session == DM_NO_SESSION) { + err = dm_create_session(DM_NO_SESSION, + CONST_DISCARD(char *, DMAPI_SESSION_NAME), + &samba_dmapi_session); if (err < 0) { DEBUGADD(DMAPI_TRACE, ("failed to create new DMAPI session: %s\n", strerror(errno))); - dmapi_session = DM_NO_SESSION; + samba_dmapi_session = DM_NO_SESSION; return -1; } @@ -185,22 +184,22 @@ static int reattach_dmapi_session(void) char buf[DM_SESSION_INFO_LEN]; size_t buflen; - if (dmapi_session != DM_NO_SESSION ) { + if (samba_dmapi_session != DM_NO_SESSION ) { become_root(); /* NOTE: On Linux, this call opens /dev/dmapi, costing us a * file descriptor. Ideally, we would close this when we fork. */ if (init_dmapi_service() < 0) { - dmapi_session = DM_NO_SESSION; + samba_dmapi_session = DM_NO_SESSION; unbecome_root(); return -1; } - if (dm_query_session(dmapi_session, sizeof(buf), + if (dm_query_session(samba_dmapi_session, sizeof(buf), buf, &buflen) < 0) { /* Session is stale. Disable DMAPI. */ - dmapi_session = DM_NO_SESSION; + samba_dmapi_session = DM_NO_SESSION; unbecome_root(); return -1; } @@ -214,33 +213,42 @@ static int reattach_dmapi_session(void) return 0; } -uint32 dmapi_file_flags(const char * const path) +/* If a DMAPI session has been initialised, then we need to make sure + * we are attached to it and have the correct privileges. This is + * necessary to be able to do DMAPI operations across a fork(2). If + * it fails, there is no likelihood of that failure being transient. + * + * Note that this use of the static attached flag relies on the fact + * that dmapi_file_flags() is never called prior to forking the + * per-client server process. + */ +const void * dmapi_get_current_session(void) { static int attached = 0; + if (dmapi_have_session() && !attached) { + attached++; + if (reattach_dmapi_session() < 0) { + return DM_NO_SESSION; + } + } + return &samba_dmapi_session; +} +uint32 dmapi_file_flags(const char * const path) +{ + dm_sessid_t dmapi_session; int err; dm_eventset_t events = {0}; uint nevents; - void *dm_handle; - size_t dm_handle_len; + void *dm_handle = NULL; + size_t dm_handle_len = 0; uint32 flags = 0; - /* If a DMAPI session has been initialised, then we need to make sure - * we are attached to it and have the correct privileges. This is - * necessary to be able to do DMAPI operations across a fork(2). If - * it fails, there is no liklihood of that failure being transient. - * - * Note that this use of the static attached flag relies on the fact - * that dmapi_file_flags() is never called prior to forking the - * per-client server process. - */ - if (dmapi_have_session() && !attached) { - attached++; - if (reattach_dmapi_session() < 0) { - return 0; - } + dmapi_session = *(dm_sessid_t*) dmapi_get_current_session(); + if (dmapi_session == DM_NO_SESSION) { + return 0; } /* AIX has DMAPI but no POSIX capablities support. In this case, @@ -313,4 +321,5 @@ done: return flags; } + #endif /* USE_DMAPI */ -- cgit From c17c64530ec479334f88679ef780691e06ccd65a Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Fri, 18 Jan 2008 17:34:21 +0300 Subject: Merge DMAPI fixes from CTDB Samba (This used to be commit cf1f90ad7a79dbe5926018790bb50d4e3b36cc7b) --- source3/smbd/dmapi.c | 205 ++++++++++++++++++++------------------------------- 1 file changed, 78 insertions(+), 127 deletions(-) (limited to 'source3/smbd/dmapi.c') diff --git a/source3/smbd/dmapi.c b/source3/smbd/dmapi.c index 620baf199e..a410748ccf 100644 --- a/source3/smbd/dmapi.c +++ b/source3/smbd/dmapi.c @@ -25,9 +25,9 @@ #ifndef USE_DMAPI -int dmapi_init_session(void) { return -1; } uint32 dmapi_file_flags(const char * const path) { return 0; } bool dmapi_have_session(void) { return False; } +const void * dmapi_get_current_session(void) { return NULL; } #else /* USE_DMAPI */ @@ -48,90 +48,48 @@ bool dmapi_have_session(void) { return False; } static dm_sessid_t samba_dmapi_session = DM_NO_SESSION; -/* Initialise the DMAPI interface. Make sure that we only end up initialising - * once per process to avoid resource leaks across different DMAPI - * implementations. - */ -static int init_dmapi_service(void) -{ - static pid_t lastpid; - - pid_t mypid; - - mypid = sys_getpid(); - if (mypid != lastpid) { - char *version; - - lastpid = mypid; - if (dm_init_service(&version) < 0) { - return -1; - } - - DEBUG(0, ("Initializing DMAPI: %s\n", version)); - } - - return 0; -} - -bool dmapi_have_session(void) -{ - return samba_dmapi_session != DM_NO_SESSION; -} - -static dm_sessid_t *realloc_session_list(dm_sessid_t * sessions, int count) -{ - dm_sessid_t *nsessions; - - nsessions = TALLOC_REALLOC_ARRAY(NULL, sessions, dm_sessid_t, count); - if (nsessions == NULL) { - TALLOC_FREE(sessions); - return NULL; - } - return nsessions; -} - -/* Initialise DMAPI session. The session is persistant kernel state, so it - * might already exist, in which case we merely want to reconnect to it. This - * function should be called as root. - */ -int dmapi_init_session(void) +/* + Initialise DMAPI session. The session is persistant kernel state, + so it might already exist, in which case we merely want to + reconnect to it. This function should be called as root. +*/ +static int dmapi_init_session(void) { char buf[DM_SESSION_INFO_LEN]; size_t buflen; - - uint nsessions = 10; + uint nsessions = 5; dm_sessid_t *sessions = NULL; + char *version; int i, err; - /* If we aren't root, something in the following will fail due to lack - * of privileges. Aborting seems a little extreme. - */ - SMB_WARN(getuid() == 0, "dmapi_init_session must be called as root"); - - samba_dmapi_session = DM_NO_SESSION; - if (init_dmapi_service() < 0) { + if (dm_init_service(&version) < 0) { + DEBUG(0, ("dm_init_service failed - disabling DMAPI\n")); return -1; } -retry: + ZERO_STRUCT(buf); - if ((sessions = realloc_session_list(sessions, nsessions)) == NULL) { - return -1; - } - - err = dm_getall_sessions(nsessions, sessions, &nsessions); - if (err < 0) { - if (errno == E2BIG) { - nsessions *= 2; - goto retry; + do { + dm_sessid_t *new_sessions; + nsessions *= 2; + new_sessions = TALLOC_REALLOC_ARRAY(NULL, sessions, + dm_sessid_t, nsessions); + if (new_sessions == NULL) { + talloc_free(sessions); + return -1; } + sessions = new_sessions; + err = dm_getall_sessions(nsessions, sessions, &nsessions); + } while (err == -1 && errno == E2BIG); + + if (err == -1) { DEBUGADD(DMAPI_TRACE, ("failed to retrieve DMAPI sessions: %s\n", strerror(errno))); - TALLOC_FREE(sessions); + talloc_free(sessions); return -1; } @@ -147,7 +105,7 @@ retry: } } - TALLOC_FREE(sessions); + talloc_free(sessions); /* No session already defined. */ if (samba_dmapi_session == DM_NO_SESSION) { @@ -162,91 +120,84 @@ retry: return -1; } - DEBUGADD(DMAPI_TRACE, - ("created new DMAPI session named '%s'\n", - DMAPI_SESSION_NAME)); + DEBUG(0, ("created new DMAPI session named '%s' for %s\n", + DMAPI_SESSION_NAME, version)); + } + + if (samba_dmapi_session != DM_NO_SESSION) { + set_effective_capability(DMAPI_ACCESS_CAPABILITY); } - /* Note that we never end the DMAPI session. This enables child - * processes to continue to use the session after we exit. It also lets - * you run a second Samba server on different ports without any - * conflict. + /* + Note that we never end the DMAPI session. It gets re-used if possiblie. + DMAPI session is a kernel resource that is usually lives until server reboot + and doesn't get destroed when an application finishes. */ return 0; } -/* Reattach to an existing dmapi session. Called from service processes that - * might not be running as root. - */ -static int reattach_dmapi_session(void) +/* + Return a pointer to our DMAPI session, if available. + This assumes that you have called dmapi_have_session() first. +*/ +const void *dmapi_get_current_session(void) { - char buf[DM_SESSION_INFO_LEN]; - size_t buflen; - - if (samba_dmapi_session != DM_NO_SESSION ) { - become_root(); - - /* NOTE: On Linux, this call opens /dev/dmapi, costing us a - * file descriptor. Ideally, we would close this when we fork. - */ - if (init_dmapi_service() < 0) { - samba_dmapi_session = DM_NO_SESSION; - unbecome_root(); - return -1; - } - - if (dm_query_session(samba_dmapi_session, sizeof(buf), - buf, &buflen) < 0) { - /* Session is stale. Disable DMAPI. */ - samba_dmapi_session = DM_NO_SESSION; - unbecome_root(); - return -1; - } - - set_effective_capability(DMAPI_ACCESS_CAPABILITY); - - DEBUG(DMAPI_TRACE, ("reattached DMAPI session\n")); - unbecome_root(); + if (samba_dmapi_session == DM_NO_SESSION) { + return NULL; } - return 0; + return (void *)&samba_dmapi_session; } + +/* + dmapi_have_session() must be the first DMAPI call you make in Samba. It will + initialize DMAPI, if available, and tell you if you can get a DMAPI session. + This should be called in the client-specific child process. +*/ -/* If a DMAPI session has been initialised, then we need to make sure - * we are attached to it and have the correct privileges. This is - * necessary to be able to do DMAPI operations across a fork(2). If - * it fails, there is no likelihood of that failure being transient. - * - * Note that this use of the static attached flag relies on the fact - * that dmapi_file_flags() is never called prior to forking the - * per-client server process. - */ -const void * dmapi_get_current_session(void) +bool dmapi_have_session(void) { - static int attached = 0; - if (dmapi_have_session() && !attached) { - attached++; - if (reattach_dmapi_session() < 0) { - return DM_NO_SESSION; - } + static bool initialized; + if (!initialized) { + initialized = true; + + become_root(); + dmapi_init_session(); + unbecome_root(); + } - return &samba_dmapi_session; + + return samba_dmapi_session != DM_NO_SESSION; } +/* + This is default implementation of dmapi_file_flags() that is + called from VFS is_offline() call to know whether file is offline. + For GPFS-specific version see modules/vfs_tsmsm.c. It might be + that approach on quering existence of a specific attribute that + is used in vfs_tsmsm.c will work with other DMAPI-based HSM + implementations as well. +*/ uint32 dmapi_file_flags(const char * const path) { - dm_sessid_t dmapi_session; int err; dm_eventset_t events = {0}; uint nevents; + dm_sessid_t dmapi_session; + void *dmapi_session_ptr; void *dm_handle = NULL; size_t dm_handle_len = 0; uint32 flags = 0; - dmapi_session = *(dm_sessid_t*) dmapi_get_current_session(); + dmapi_session_ptr = dmapi_get_current_session(); + if (dmapi_session_ptr == NULL) { + return 0; + } + + dmapi_session = *(dm_sessid_t *)dmapi_session_ptr; if (dmapi_session == DM_NO_SESSION) { return 0; } -- cgit From 28b27bfd40d1bfbebaa9f8026efdf169d7bc6b29 Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Tue, 29 Jan 2008 17:43:49 +0300 Subject: Merge DMAPI fixes from Tridge Support cases when existing DMAPI session is stale. In this case we are creating another one. The code differs from 3-0_ctdb branch in that we fail when it is not possible to create more sessions and pretend that file is offline. This allows to escape endless loop in vfs_tsmsm.c. (This used to be commit 5efb57d904e25e68b09a567e260292439ad9c095) --- source3/smbd/dmapi.c | 72 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 16 deletions(-) (limited to 'source3/smbd/dmapi.c') diff --git a/source3/smbd/dmapi.c b/source3/smbd/dmapi.c index a410748ccf..8d43e0a9d1 100644 --- a/source3/smbd/dmapi.c +++ b/source3/smbd/dmapi.c @@ -47,7 +47,7 @@ const void * dmapi_get_current_session(void) { return NULL; } #define DMAPI_TRACE 10 static dm_sessid_t samba_dmapi_session = DM_NO_SESSION; - +static unsigned session_num; /* Initialise DMAPI session. The session is persistant kernel state, @@ -61,23 +61,41 @@ static int dmapi_init_session(void) uint nsessions = 5; dm_sessid_t *sessions = NULL; char *version; + char *session_name; + TALLOC_CTX *tmp_ctx = talloc_new(NULL); int i, err; + if (session_num == 0) { + session_name = DMAPI_SESSION_NAME; + } else { + session_name = talloc_asprintf(tmp_ctx, "%s%u", DMAPI_SESSION_NAME, + session_num); + } + + if (session_name == NULL) { + DEBUG(0,("Out of memory in dmapi_init_session\n")); + talloc_free(tmp_ctx); + return -1; + } + + if (dm_init_service(&version) < 0) { DEBUG(0, ("dm_init_service failed - disabling DMAPI\n")); + talloc_free(tmp_ctx); return -1; } ZERO_STRUCT(buf); + /* Fetch kernel DMAPI sessions until we get any of them */ do { dm_sessid_t *new_sessions; nsessions *= 2; - new_sessions = TALLOC_REALLOC_ARRAY(NULL, sessions, + new_sessions = TALLOC_REALLOC_ARRAY(tmp_ctx, sessions, dm_sessid_t, nsessions); if (new_sessions == NULL) { - talloc_free(sessions); + talloc_free(tmp_ctx); return -1; } @@ -89,14 +107,15 @@ static int dmapi_init_session(void) DEBUGADD(DMAPI_TRACE, ("failed to retrieve DMAPI sessions: %s\n", strerror(errno))); - talloc_free(sessions); + talloc_free(tmp_ctx); return -1; } + /* Look through existing kernel DMAPI sessions to find out ours */ for (i = 0; i < nsessions; ++i) { err = dm_query_session(sessions[i], sizeof(buf), buf, &buflen); buf[sizeof(buf) - 1] = '\0'; - if (err == 0 && strcmp(DMAPI_SESSION_NAME, buf) == 0) { + if (err == 0 && strcmp(session_name, buf) == 0) { samba_dmapi_session = sessions[i]; DEBUGADD(DMAPI_TRACE, ("attached to existing DMAPI session " @@ -105,23 +124,22 @@ static int dmapi_init_session(void) } } - talloc_free(sessions); - /* No session already defined. */ if (samba_dmapi_session == DM_NO_SESSION) { err = dm_create_session(DM_NO_SESSION, - CONST_DISCARD(char *, DMAPI_SESSION_NAME), + session_name, &samba_dmapi_session); if (err < 0) { DEBUGADD(DMAPI_TRACE, ("failed to create new DMAPI session: %s\n", strerror(errno))); samba_dmapi_session = DM_NO_SESSION; + talloc_free(tmp_ctx); return -1; } DEBUG(0, ("created new DMAPI session named '%s' for %s\n", - DMAPI_SESSION_NAME, version)); + session_name, version)); } if (samba_dmapi_session != DM_NO_SESSION) { @@ -132,8 +150,12 @@ static int dmapi_init_session(void) Note that we never end the DMAPI session. It gets re-used if possiblie. DMAPI session is a kernel resource that is usually lives until server reboot and doesn't get destroed when an application finishes. + + However, we free list of references to DMAPI sessions we've got from the kernel + as it is not needed anymore once we have found (or created) our session. */ + talloc_free(tmp_ctx); return 0; } @@ -171,6 +193,25 @@ bool dmapi_have_session(void) return samba_dmapi_session != DM_NO_SESSION; } +/* + only call this when you get back an EINVAL error indicating that the + session you are using is invalid. This destroys the existing session + and creates a new one. + */ +BOOL dmapi_new_session(void) +{ + if (dmapi_have_session()) { + /* try to destroy the old one - this may not succeed */ + dm_destroy_session(samba_dmapi_session); + } + samba_dmapi_session = DM_NO_SESSION; + become_root(); + session_num++; + dmapi_init_session(); + unbecome_root(); + return samba_dmapi_session != DM_NO_SESSION; +} + /* This is default implementation of dmapi_file_flags() that is called from VFS is_offline() call to know whether file is offline. @@ -185,12 +226,12 @@ uint32 dmapi_file_flags(const char * const path) dm_eventset_t events = {0}; uint nevents; - dm_sessid_t dmapi_session; - void *dmapi_session_ptr; - void *dm_handle = NULL; - size_t dm_handle_len = 0; + dm_sessid_t dmapi_session; + const void *dmapi_session_ptr; + void *dm_handle = NULL; + size_t dm_handle_len = 0; - uint32 flags = 0; + uint32 flags = 0; dmapi_session_ptr = dmapi_get_current_session(); if (dmapi_session_ptr == NULL) { @@ -251,8 +292,7 @@ uint32 dmapi_file_flags(const char * const path) * interested in trapping read events is that part of the file is * offline. */ - DEBUG(DMAPI_TRACE, ("DMAPI event list for %s is %#llx\n", - path, events)); + DEBUG(DMAPI_TRACE, ("DMAPI event list for %s\n", path)); if (DMEV_ISSET(DM_EVENT_READ, events)) { flags = FILE_ATTRIBUTE_OFFLINE; } -- cgit From 52c16c95e6e6fa17a7e440b77afdccfd9a7295c9 Mon Sep 17 00:00:00 2001 From: Alexander Bokovoy Date: Tue, 29 Jan 2008 18:01:23 +0300 Subject: Fix BOOL introduced by last commit (This used to be commit 8afb7133e956ec963ac55720fb297b4d5b44702c) --- source3/smbd/dmapi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source3/smbd/dmapi.c') diff --git a/source3/smbd/dmapi.c b/source3/smbd/dmapi.c index 8d43e0a9d1..fab0d5f9ef 100644 --- a/source3/smbd/dmapi.c +++ b/source3/smbd/dmapi.c @@ -198,7 +198,7 @@ bool dmapi_have_session(void) session you are using is invalid. This destroys the existing session and creates a new one. */ -BOOL dmapi_new_session(void) +bool dmapi_new_session(void) { if (dmapi_have_session()) { /* try to destroy the old one - this may not succeed */ -- cgit