nfs-ganesha 1.4
|
00001 /* 00002 * vim:expandtab:shiftwidth=8:tabstop=8: 00003 * 00004 * Copyright (C) 2010, The Linux Box Corporation 00005 * Contributor : Matt Benjamin <matt@linuxbox.com> 00006 * 00007 * Some portions Copyright CEA/DAM/DIF (2008) 00008 * contributeur : Philippe DENIEL philippe.deniel@cea.fr 00009 * Thomas LEIBOVICI thomas.leibovici@cea.fr 00010 * 00011 * 00012 * This program is free software; you can redistribute it and/or 00013 * modify it under the terms of the GNU Lesser General Public 00014 * License as published by the Free Software Foundation; either 00015 * version 3 of the License, or (at your option) any later version. 00016 * 00017 * This program is distributed in the hope that it will be useful, 00018 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00020 * Lesser General Public License for more details. 00021 * 00022 * You should have received a copy of the GNU Lesser General Public 00023 * License along with this library; if not, write to the Free Software 00024 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00025 * 00026 * ------------- 00027 */ 00028 00029 #ifdef HAVE_CONFIG_H 00030 #include "config.h" 00031 #endif 00032 00033 #ifdef _SOLARIS 00034 #include "solaris_port.h" 00035 #endif /* _SOLARIS */ 00036 00037 #include <unistd.h> 00038 #include <sys/types.h> 00039 #include <sys/param.h> 00040 #include <time.h> 00041 #include <pthread.h> 00042 #include <assert.h> 00043 #if defined(USE_DBUS) 00044 #include <dbus/dbus.h> 00045 #endif /* USE_DBUS */ 00046 #include "nlm_list.h" 00047 #include "fsal.h" 00048 #include "nfs_core.h" 00049 #include "log.h" 00050 #include "nfs_rpc_callback.h" 00051 #include "ganesha_dbus.h" 00052 00070 #define GSH_DBUS_NONE 0x0000 00071 #define GSH_DBUS_SHUTDOWN 0x0001 00072 #define GSH_DBUS_SLEEPING 0x0002 00073 00074 struct ganesha_dbus_handler 00075 { 00076 char *name; 00077 struct avltree_node node_k; 00078 DBusObjectPathVTable vtable; 00079 }; 00080 typedef struct ganesha_dbus_handler ganesha_dbus_handler_t; 00081 00082 struct _dbus_thread_state 00083 { 00084 int initialized; 00085 pthread_t thread_id; 00086 wait_entry_t we; 00087 DBusConnection* dbus_conn; 00088 DBusError dbus_err; 00089 uint32_t dbus_serial; 00090 struct avltree callouts; 00091 uint32_t flags; 00092 }; 00093 00094 static struct _dbus_thread_state thread_state; 00095 00096 static inline int 00097 dbus_callout_cmpf(const struct avltree_node *lhs, 00098 const struct avltree_node *rhs) 00099 { 00100 ganesha_dbus_handler_t *lk, *rk; 00101 00102 lk = avltree_container_of(lhs, ganesha_dbus_handler_t, node_k); 00103 rk = avltree_container_of(rhs, ganesha_dbus_handler_t, node_k); 00104 00105 return (strcmp(lk->name, rk->name)); 00106 } 00107 00108 void gsh_dbus_pkginit(void) 00109 { 00110 char regbuf[128]; 00111 int code = 0; 00112 00113 LogDebug(COMPONENT_DBUS, "init"); 00114 00115 avltree_init(&thread_state.callouts, dbus_callout_cmpf, 0 /* must be 0 */); 00116 00117 dbus_error_init(&thread_state.dbus_err); /* sigh */ 00118 thread_state.dbus_conn = dbus_bus_get(DBUS_BUS_SESSION, 00119 &thread_state.dbus_err); 00120 if (dbus_error_is_set(&thread_state.dbus_err)) { 00121 LogCrit(COMPONENT_DBUS, 00122 "dbus_bus_get failed (%s)", thread_state.dbus_err.message); 00123 dbus_error_free(&thread_state.dbus_err); 00124 goto out; 00125 } 00126 00127 snprintf(regbuf, 128, "org.ganesha.nfsd"); 00128 code = dbus_bus_request_name(thread_state.dbus_conn, regbuf, 00129 DBUS_NAME_FLAG_REPLACE_EXISTING , 00130 &thread_state.dbus_err); 00131 if (dbus_error_is_set(&thread_state.dbus_err)) { 00132 LogCrit(COMPONENT_DBUS, "server bus reg failed (%s, %s)", regbuf, 00133 thread_state.dbus_err.message); 00134 dbus_error_free(&thread_state.dbus_err); 00135 if (! code) 00136 code = EINVAL; 00137 goto out; 00138 } 00139 if (code != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { 00140 LogCrit(COMPONENT_DBUS, "server failed becoming primary bus owner " 00141 "(%s, %d)", regbuf, code); 00142 goto out; 00143 } 00144 00145 thread_state.initialized = TRUE; 00146 00147 out: 00148 return; 00149 } 00150 00151 static void 00152 path_unregistered_func (DBusConnection *connection, 00153 void *user_data) 00154 { 00155 /* connection was finalized -- do nothing */ 00156 } 00157 00158 int32_t gsh_dbus_register_path(const char *name, 00159 DBusObjectPathMessageFunction method) 00160 { 00161 ganesha_dbus_handler_t *handler; 00162 struct avltree_node *node; 00163 char path[512]; 00164 int code = 0; 00165 00166 /* XXX if this works, add ifc level */ 00167 snprintf(path, 512, "/org/ganesha/nfsd/%s", name); 00168 00169 handler = (ganesha_dbus_handler_t *) 00170 gsh_malloc(sizeof(ganesha_dbus_handler_t)); 00171 handler->name = gsh_strdup(path); 00172 handler->vtable.unregister_function = path_unregistered_func; 00173 handler->vtable.message_function = method; 00174 00175 if (!thread_state.dbus_conn) { 00176 LogCrit(COMPONENT_DBUS, "dbus_connection_register_object_path " 00177 "called with no DBUS connection"); 00178 goto out; 00179 } 00180 00181 code = dbus_connection_register_object_path (thread_state.dbus_conn, 00182 handler->name, 00183 &handler->vtable, 00184 (void*) 0xdeadbeef); 00185 if (! code) { 00186 LogFatal(COMPONENT_DBUS, "dbus_connection_register_object_path " 00187 "failed"); 00188 gsh_free(handler); 00189 goto out; 00190 } 00191 00192 node = avltree_insert(&handler->node_k, &thread_state.callouts); 00193 if (node) { 00194 LogFatal(COMPONENT_DBUS, "failed inserting method %s", path); 00195 code = EINVAL; 00196 } 00197 00198 LogDebug(COMPONENT_DBUS, "registered handler for %s", path); 00199 00200 out: 00201 return (code); 00202 } 00203 00204 void gsh_dbus_pkgshutdown(void) 00205 { 00206 struct avltree_node *node, *onode; 00207 ganesha_dbus_handler_t *handler; 00208 00209 LogDebug(COMPONENT_DBUS, "shutdown"); 00210 00211 /* remove and free handlers */ 00212 onode = NULL; 00213 node = avltree_first(&thread_state.callouts); 00214 do { 00215 if (onode) { 00216 handler = avltree_container_of(onode, ganesha_dbus_handler_t, 00217 node_k); 00218 dbus_bus_release_name(thread_state.dbus_conn, handler->name, 00219 &thread_state.dbus_err); 00220 if (dbus_error_is_set(&thread_state.dbus_err)) { 00221 LogCrit(COMPONENT_DBUS, "err releasing name (%s, %s)", 00222 handler->name, thread_state.dbus_err.message); 00223 dbus_error_free(&thread_state.dbus_err); 00224 } 00225 gsh_free(handler->name); 00226 gsh_free(handler); 00227 } 00228 } while ((onode = node) && (node = avltree_next(node))); 00229 if (onode) { 00230 handler = avltree_container_of(onode, ganesha_dbus_handler_t, 00231 node_k); 00232 dbus_bus_release_name(thread_state.dbus_conn, handler->name, 00233 &thread_state.dbus_err); 00234 if (dbus_error_is_set(&thread_state.dbus_err)) { 00235 LogCrit(COMPONENT_DBUS, "err releasing name (%s, %s)", 00236 handler->name, thread_state.dbus_err.message); 00237 dbus_error_free(&thread_state.dbus_err); 00238 } 00239 gsh_free(handler->name); 00240 gsh_free(handler); 00241 } 00242 avltree_init(&thread_state.callouts, dbus_callout_cmpf, 0); 00243 00244 /* shutdown bus */ 00245 if (thread_state.dbus_conn) 00246 dbus_connection_close(thread_state.dbus_conn); 00247 } 00248 00249 void *gsh_dbus_thread(void *arg) 00250 { 00251 struct avltree_node *node; 00252 ganesha_dbus_handler_t hk, *handler; 00253 DBusMessage* msg; 00254 00255 SetNameFunction("gsh_dbus_thread"); 00256 00257 if (! thread_state.dbus_conn) { 00258 LogCrit(COMPONENT_DBUS, "DBUS not initialized, service thread " 00259 "exiting"); 00260 goto out; 00261 } 00262 00263 while (1) { 00264 if (thread_state.flags & GSH_DBUS_SHUTDOWN) 00265 break; 00266 00267 LogFullDebug(COMPONENT_DBUS, "top of poll loop"); 00268 00269 /* do stuff */ 00270 dbus_connection_read_write_dispatch(thread_state.dbus_conn, 30*1000); 00271 00272 /* deal with message (ignore timeouts) */ 00273 msg = dbus_connection_pop_message(thread_state.dbus_conn); 00274 if (! msg) 00275 continue; 00276 00277 hk.name = (char *) dbus_message_get_path(msg); 00278 if (! hk.name) { 00279 LogDebug(COMPONENT_DBUS, "dbus_msg_get_path returned NULL"); 00280 continue; 00281 } 00282 LogFullDebug(COMPONENT_DBUS, "recv msg: %s", hk.name); 00283 node = avltree_lookup(&hk.node_k, &thread_state.callouts); 00284 if (node) { 00285 handler = avltree_container_of(node, ganesha_dbus_handler_t, 00286 node_k); 00287 /* we are serialized by the bus */ 00288 /* XXX libdbus call it in this configuration? */ 00289 handler->vtable.message_function(thread_state.dbus_conn, msg, 0); 00290 } else { 00291 LogDebug(COMPONENT_DBUS, "msg for unknown handler %s", 00292 hk.name); 00293 } 00294 } /* 1 */ 00295 00296 out: 00297 LogCrit(COMPONENT_DBUS, "shutdown"); 00298 00299 return (NULL); 00300 } 00301 00302 void gsh_dbus_wake_thread(uint32_t flags) 00303 { 00304 if (thread_state.flags & GSH_DBUS_SLEEPING) 00305 pthread_cond_signal(&thread_state.we.cv); 00306 }