1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-11 16:58:40 +03:00

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 commit is contained in:
Alexander Bokovoy 2008-01-29 17:43:49 +03:00
parent 58dce4cdf2
commit 5efb57d904
2 changed files with 78 additions and 19 deletions

View File

@ -141,8 +141,9 @@ static bool tsmsm_is_offline(struct vfs_handle_struct *handle,
size_t dmhandle_len = 0;
size_t rlen;
dm_attrname_t dmname;
int ret;
int ret, lerrno;
bool offline;
char buf[1];
/* if the file has more than FILE_IS_ONLINE_RATIO of blocks available,
then assume it is not offline (it may not be 100%, as it could be sparse) */
@ -179,8 +180,26 @@ static bool tsmsm_is_offline(struct vfs_handle_struct *handle,
memset(&dmname, 0, sizeof(dmname));
strlcpy((char *)&dmname.an_chars[0], tsmd->attrib_name, sizeof(dmname.an_chars));
ret = dm_get_dmattr(*dmsession_id, dmhandle, dmhandle_len,
DM_NO_TOKEN, &dmname, 0, NULL, &rlen);
lerrno = 0;
do {
ret = dm_get_dmattr(*dmsession_id, dmhandle, dmhandle_len,
DM_NO_TOKEN, &dmname, sizeof(buf), buf, &rlen);
if (ret == -1 && errno == EINVAL) {
DEBUG(0, ("Stale DMAPI session, re-creating it.\n"));
lerrno = EINVAL;
if (dmapi_new_session()) {
sessionp = dmapi_get_current_session();
} else {
DEBUG(0,
("Unable to re-create DMAPI session, assuming offline (%s) - %s\n",
path, strerror(errno)));
offline = true;
dm_handle_free(dmhandle, dmhandle_len);
goto done;
}
}
} while (ret == -1 && lerrno == EINVAL);
/* its offline if the specified DMAPI attribute exists */
offline = (ret == 0 || (ret == -1 && errno == E2BIG));

View File

@ -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;
}