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 #include "nlm_list.h" 00044 #include "abstract_mem.h" 00045 #include "fsal.h" 00046 #include "nfs_core.h" 00047 #include "log.h" 00048 #include "nfs_rpc_callback.h" 00049 #include "nfs_rpc_callback_simulator.h" 00050 #include "sal_functions.h" 00051 #include "ganesha_dbus.h" 00052 00070 /* XML data to answer org.freedesktop.DBus.Introspectable.Introspect requests */ 00071 static const char* introspection_xml = 00072 "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n" 00073 "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n" 00074 "<node>\n" 00075 " <interface name=\"org.freedesktop.DBus.Introspectable\">\n" 00076 " <method name=\"Introspect\">\n" 00077 " <arg name=\"data\" direction=\"out\" type=\"s\"/>\n" 00078 " </method>\n" 00079 " </interface>\n" 00080 " <interface name=\"org.ganesha.nfsd.cbsim\">\n" 00081 " <method name=\"get_client_ids\">\n" 00082 " <arg name=\"clientids\" direction=\"out\" type=\"at\"/>\n" 00083 " </method>\n" 00084 " <method name=\"fake_recall\">\n" 00085 " <arg name=\"clientid\" direction=\"in\" type=\"t\"/>\n" 00086 " </method>\n" 00087 " </interface>\n" 00088 "</node>\n" 00089 ; 00090 00091 extern hash_table_t *ht_confirmed_client_id; 00092 00093 static DBusHandlerResult 00094 nfs_rpc_cbsim_get_client_ids(DBusConnection *conn, DBusMessage *msg, 00095 void *user_data) 00096 { 00097 DBusMessage* reply; 00098 static uint32_t i, serial = 1; 00099 hash_table_t *ht = ht_confirmed_client_id; 00100 struct rbt_head *head_rbt; 00101 hash_data_t *pdata = NULL; 00102 struct rbt_node *pn; 00103 nfs_client_id_t *pclientid; 00104 uint64_t clientid; 00105 DBusMessageIter iter, sub_iter; 00106 00107 /* create a reply from the message */ 00108 reply = dbus_message_new_method_return(msg); 00109 dbus_message_iter_init_append(reply, &iter); 00110 00111 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, 00112 DBUS_TYPE_UINT64_AS_STRING, &sub_iter); 00113 /* For each bucket of the hashtable */ 00114 for(i = 0; i < ht->parameter.index_size; i++) { 00115 head_rbt = &(ht->partitions[i].rbt); 00116 00117 /* acquire mutex */ 00118 pthread_rwlock_wrlock(&(ht->partitions[i].lock)); 00119 00120 /* go through all entries in the red-black-tree*/ 00121 RBT_LOOP(head_rbt, pn) { 00122 pdata = RBT_OPAQ(pn); 00123 pclientid = 00124 (nfs_client_id_t *)pdata->buffval.pdata; 00125 clientid = pclientid->cid_clientid; 00126 dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_UINT64, &clientid); 00127 RBT_INCREMENT(pn); 00128 } 00129 pthread_rwlock_unlock(&(ht->partitions[i].lock)); 00130 } 00131 dbus_message_iter_close_container(&iter, &sub_iter); 00132 /* send the reply && flush the connection */ 00133 if (!dbus_connection_send(conn, reply, &serial)) { 00134 LogCrit(COMPONENT_DBUS, "reply failed"); 00135 } 00136 dbus_connection_flush(conn); 00137 dbus_message_unref(reply); 00138 serial++; 00139 return (DBUS_HANDLER_RESULT_HANDLED); 00140 } 00141 00142 static int32_t 00143 cbsim_test_bchan(clientid4 clientid) 00144 { 00145 int32_t tries, code = 0; 00146 nfs_client_id_t *pclientid = NULL; 00147 struct timeval CB_TIMEOUT = {15, 0}; 00148 rpc_call_channel_t *chan; 00149 enum clnt_stat stat; 00150 00151 code = nfs_client_id_get_confirmed(clientid, &pclientid); 00152 if (code != CLIENT_ID_SUCCESS) { 00153 LogCrit(COMPONENT_NFS_CB, 00154 "No clid record for %"PRIx64" (%d) code %d", clientid, 00155 (int32_t) clientid, code); 00156 code = EINVAL; 00157 goto out; 00158 } 00159 00160 assert(pclientid); 00161 00162 /* create (fix?) channel */ 00163 for (tries = 0; tries < 2; ++tries) { 00164 00165 chan = nfs_rpc_get_chan(pclientid, NFS_RPC_FLAG_NONE); 00166 if (! chan) { 00167 LogCrit(COMPONENT_NFS_CB, "nfs_rpc_get_chan failed"); 00168 goto out; 00169 } 00170 00171 if (! chan->clnt) { 00172 LogCrit(COMPONENT_NFS_CB, "nfs_rpc_get_chan failed (no clnt)"); 00173 goto out; 00174 } 00175 00176 /* try the CB_NULL proc -- inline here, should be ok-ish */ 00177 stat = rpc_cb_null(chan, CB_TIMEOUT); 00178 LogDebug(COMPONENT_NFS_CB, 00179 "rpc_cb_null on client %"PRIx64" returns %d", 00180 clientid, stat); 00181 00182 00183 /* RPC_INTR indicates that we should refresh the channel 00184 * and retry */ 00185 if (stat != RPC_INTR) 00186 break; 00187 } 00188 00189 out: 00190 return (code); 00191 } 00192 00193 /* 00194 * Demonstration callback invocation. 00195 */ 00196 static void cbsim_free_compound(nfs4_compound_t *cbt) 00197 { 00198 int ix; 00199 nfs_cb_argop4 *argop = NULL; 00200 00201 for (ix = 0; ix < cbt->v_u.v4.args.argarray.argarray_len; ++ix) { 00202 argop = cbt->v_u.v4.args.argarray.argarray_val + ix; 00203 if (argop) { 00204 switch (argop->argop) { 00205 case NFS4_OP_CB_RECALL: 00206 gsh_free(argop->nfs_cb_argop4_u.opcbrecall.fh.nfs_fh4_val); 00207 break; 00208 default: 00209 /* TODO: ahem */ 00210 break; 00211 } 00212 } 00213 } 00214 00215 /* XXX general free (move ?) */ 00216 cb_compound_free(cbt); 00217 } 00218 00219 static int32_t cbsim_completion_func(rpc_call_t* call, rpc_call_hook hook, 00220 void* arg, uint32_t flags) 00221 { 00222 LogDebug(COMPONENT_NFS_CB, "%p %s", call, 00223 (hook == RPC_CALL_ABORT) ? 00224 "RPC_CALL_ABORT" : 00225 "RPC_CALL_COMPLETE"); 00226 switch (hook) { 00227 case RPC_CALL_COMPLETE: 00228 /* potentially, do something more interesting here */ 00229 LogDebug(COMPONENT_NFS_CB, "call result: %d", call->stat); 00230 free_rpc_call(call); 00231 break; 00232 default: 00233 LogDebug(COMPONENT_NFS_CB, "%p unknown hook %d", call, hook); 00234 break; 00235 } 00236 00237 return (0); 00238 } 00239 00240 static int32_t 00241 cbsim_fake_cbrecall(clientid4 clientid) 00242 { 00243 int32_t code = 0; 00244 nfs_client_id_t *pclientid = NULL; 00245 rpc_call_channel_t *chan = NULL; 00246 nfs_cb_argop4 argop[1]; 00247 rpc_call_t *call; 00248 00249 LogDebug(COMPONENT_NFS_CB, 00250 "called with clientid %"PRIx64, clientid); 00251 00252 code = nfs_client_id_get_confirmed(clientid, &pclientid); 00253 if (code != CLIENT_ID_SUCCESS) { 00254 LogCrit(COMPONENT_NFS_CB, 00255 "No clid record for %"PRIx64" (%d) code %d", clientid, 00256 (int32_t) clientid, code); 00257 code = EINVAL; 00258 goto out; 00259 } 00260 00261 assert(pclientid); 00262 00263 chan = nfs_rpc_get_chan(pclientid, NFS_RPC_FLAG_NONE); 00264 if (! chan) { 00265 LogCrit(COMPONENT_NFS_CB, "nfs_rpc_get_chan failed"); 00266 goto out; 00267 } 00268 00269 if (! chan->clnt) { 00270 LogCrit(COMPONENT_NFS_CB, "nfs_rpc_get_chan failed (no clnt)"); 00271 goto out; 00272 } 00273 00274 /* allocate a new call--freed in completion hook */ 00275 call = alloc_rpc_call(); 00276 call->chan = chan; 00277 00278 /* setup a compound */ 00279 cb_compound_init_v4(&call->cbt, 6, 00280 pclientid->cid_cb.cb_u.v40.cb_callback_ident, 00281 "brrring!!!", 10); 00282 00283 /* TODO: api-ify */ 00284 memset(argop, 0, sizeof(nfs_cb_argop4)); 00285 argop->argop = NFS4_OP_CB_RECALL; 00286 argop->nfs_cb_argop4_u.opcbrecall.stateid.seqid = 0xdeadbeef; 00287 strlcpy(argop->nfs_cb_argop4_u.opcbrecall.stateid.other, 00288 "0xdeadbeef", 12); 00289 argop->nfs_cb_argop4_u.opcbrecall.truncate = TRUE; 00290 argop->nfs_cb_argop4_u.opcbrecall.fh.nfs_fh4_len = 11; 00291 /* leaks, sorry */ 00292 argop->nfs_cb_argop4_u.opcbrecall.fh.nfs_fh4_val = gsh_strdup("0xabadcafe"); 00293 00294 /* add ops, till finished (dont exceed count) */ 00295 cb_compound_add_op(&call->cbt, argop); 00296 00297 /* set completion hook */ 00298 call->call_hook = cbsim_completion_func; 00299 00300 /* call it (here, in current thread context) */ 00301 code = nfs_rpc_submit_call(call, 00302 NFS_RPC_FLAG_NONE /* NFS_RPC_CALL_INLINE */); 00303 00304 out: 00305 return (code); 00306 } 00307 00308 static DBusHandlerResult 00309 nfs_rpc_cbsim_fake_recall(DBusConnection *conn, DBusMessage *msg, 00310 void *user_data) 00311 { 00312 DBusMessage* reply; 00313 DBusMessageIter args; 00314 static uint32_t serial = 1; 00315 clientid4 clientid = 9315; /* XXX ew! */ 00316 00317 LogDebug(COMPONENT_NFS_CB, "called!"); 00318 00319 /* read the arguments */ 00320 if (!dbus_message_iter_init(msg, &args)) 00321 LogDebug(COMPONENT_DBUS, "message has no arguments"); 00322 else if (DBUS_TYPE_UINT64 != 00323 dbus_message_iter_get_arg_type(&args)) 00324 LogDebug(COMPONENT_DBUS, "arg not uint64"); 00325 else { 00326 dbus_message_iter_get_basic(&args, &clientid); 00327 LogDebug(COMPONENT_DBUS, "param: %"PRIx64, clientid); 00328 } 00329 00330 (void) cbsim_test_bchan(clientid); 00331 (void) cbsim_fake_cbrecall(clientid); 00332 00333 reply = dbus_message_new_method_return(msg); 00334 if (!dbus_connection_send(conn, reply, &serial)) { 00335 LogCrit(COMPONENT_DBUS, "reply failed"); 00336 } 00337 00338 dbus_connection_flush(conn); 00339 dbus_message_unref(reply); 00340 serial++; 00341 00342 return (DBUS_HANDLER_RESULT_HANDLED); 00343 } 00344 00345 static DBusHandlerResult 00346 nfs_rpc_cbsim_introspection(DBusConnection *conn, DBusMessage *msg, 00347 void *user_data) 00348 { 00349 static uint32_t serial = 1; 00350 DBusMessage* reply; 00351 DBusMessageIter iter; 00352 00353 /* create a reply from the message */ 00354 reply = dbus_message_new_method_return(msg); 00355 dbus_message_iter_init_append(reply, &iter); 00356 dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, 00357 &introspection_xml ); 00358 00359 /* send the reply && flush the connection */ 00360 if (! dbus_connection_send(conn, reply, &serial)) { 00361 LogCrit(COMPONENT_DBUS, "reply failed"); 00362 } 00363 00364 dbus_connection_flush(conn); 00365 dbus_message_unref(reply); 00366 serial++; 00367 00368 return (DBUS_HANDLER_RESULT_HANDLED); 00369 } 00370 00371 static DBusHandlerResult 00372 nfs_rpc_cbsim_entrypoint(DBusConnection *conn, DBusMessage *msg, 00373 void *user_data) 00374 { 00375 const char *interface = dbus_message_get_interface(msg); 00376 const char *method = dbus_message_get_member(msg); 00377 00378 if ((interface && (! strcmp(interface, DBUS_INTERFACE_INTROSPECTABLE))) || 00379 (method && (! strcmp(method, "Introspect")))) { 00380 return(nfs_rpc_cbsim_introspection(conn, msg, user_data)); 00381 } 00382 00383 if (method) { 00384 if (! strcmp(method, "get_client_ids")) 00385 return(nfs_rpc_cbsim_get_client_ids(conn, msg, user_data)); 00386 00387 if (! strcmp(method, "fake_recall")) 00388 return(nfs_rpc_cbsim_fake_recall(conn, msg, user_data)); 00389 } 00390 00391 return (DBUS_HANDLER_RESULT_NOT_YET_HANDLED); 00392 } 00393 00394 /* 00395 * Initialize subsystem 00396 */ 00397 void nfs_rpc_cbsim_pkginit(void) 00398 { 00399 (void) gsh_dbus_register_path("CBSIM", nfs_rpc_cbsim_entrypoint); 00400 LogEvent(COMPONENT_NFS_CB, "Callback Simulator Initialized"); 00401 } 00402 00403 /* 00404 * Shutdown subsystem 00405 */ 00406 void nfs_rpc_cbsim_pkgshutdown(void) 00407 { 00408 00409 }