Main Page | Modules | Directories | File List | Globals | Related Pages

relay-app.h

00001 /*
00002  *  relay-app.h - kernel 'library' functions for typical relayfs applications
00003  *
00004  * This program is free software; you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License as published by
00006  * the Free Software Foundation; either version 2 of the License, or
00007  * (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  *
00018  * Copyright (C) IBM Corporation, 2005
00019  *
00020  * 2005-Feb     Created by Tom Zanussi <zanussi@us.ibm.com>
00021  *
00022  * This header file encapsulates the details of channel setup and
00023  * teardown and communication between the kernel and user parts of a
00024  * typical and common type of relayfs application, which is that
00025  * kernel logging is kicked off when a userspace data collection
00026  * application starts and stopped when the collection app exits, and
00027  * data is automatically logged to disk in-between.  Channels are
00028  * created when the collection app is started and destroyed when it
00029  * exits, not when the kernel module is inserted, so different channel
00030  * buffer sizes can be specified for each separate run via
00031  * command-line options for instance.
00032  *
00033  * Writing to the channel is done using 2 macros, relayapp_write() and
00034  * _relayapp_write(), which are just wrappers around relay_write() and
00035  * _relay_write() but without the channel param.  You can safely call
00036  * these at any time - if there's no channel yet, they'll just be
00037  * ignored.
00038  *
00039  * To create a relay-app application, do the following:
00040  *
00041  * In your kernel module:
00042  *
00043  * - #include "relay-app.h"
00044  *
00045  * - Call init_relay_app() in your module_init function, with the
00046  *   names of the directory to create relayfs files in and the base name
00047  *   of the per-cpu relayfs files e.g. to have /mnt/relay/myapp/cpuXXX
00048  *   created call init_relay_app("myapp", "cpu", callbacks).
00049  *
00050  *   NOTE: The callbacks are entirely optional - pass NULL if you
00051  *   don't want to define any.  If you want to define some but not
00052  *   others, just set the ones you want, and ignore or NULL out the
00053  *   others.
00054  *
00055  *   NOTE: This won't actually create the relayfs files - that will
00056  *   happen when the userspace application starts (i.e. you can supply
00057  *   the buffer sizes on the application command-line for each new run
00058  *   of your program).
00059  *
00060  *   NOTE: If you pass in NULL for the directory name, the relay files
00061  *   will be created in the root directory of the relayfs filesystem.
00062  *
00063  * - Call close_relay_app() in your module_exit function - this cleans
00064  *   up the control channel and the relay files from the previous run,
00065  *   if any.
00066  *
00067  * - relay-apps use a control channel to communicate initialization
00068  *   and status information between the kernel module and user space
00069  *   program.  This is hidden beneath the API so you normally don't need
00070  *   to know anything about it, but if you want you can also use it to
00071  *   send user-defined commands from your user space application.  To do
00072  *   this, you need to define a definition for the user_command()
00073  *   callback and in the callback sort out and handle handle the
00074  *   commands you send from user space (via send_request()).  The
00075  *   callback must return 1 if the command was handled, or 0 if not
00076  *   (which will result in a send_error in the user space program,
00077  *   alerting you to the fact that you're sending something bogus).
00078  *
00079  *   NOTE: Currently commands can only be sent before the user space
00080  *   application enters relay_app_main_loop() i.e. for initialization
00081  *   purposes only.
00082  *
00083  * - the app_started() and app_stopped() callbacks provide an
00084  *   opportunity for your kernel module to perform app-specific
00085  *   initialization and cleanup, if desired.  They are purely
00086  *   informational.  app_started() is called when the user space
00087  *   application has started and app_stopped() is called when the user
00088  *   space application has stopped.
00089  *
00090  * In your user space application do the following:
00091  *
00092  * - Call init_relay_app() with the names of the relayfs file base
00093  *   name and the base filename of the output files that will be
00094  *   created, as well as the sub-buffer size and count for the current
00095  *   run (which can be passed in on the command-line if you want).  This
00096  *   will create the channel and set up the ouptut files and buffer
00097  *   mappings.  e.g. to set up reading from the relayfs files specified in the
00098  *   above example and write them to a set of per-cpu output files named
00099  *   myoutputXXX:
00100  * 
00101  *   init_relay_app("/mnt/relay/myapp/cpu", "myoutput",
00102  *                  subbuf_size_opt, n_subbufs_opt, 1);
00103  *
00104  *   (the last parameter just specifies whether or not to print out a
00105  *   summary of the number of buffers processed, and the maximum backlog
00106  *   of sub-buffers encountered e.g. if you have 4 sub-buffers, a
00107  *   maximum backlog of 3 would mean that you came close to having a
00108  *   full buffer, so you might want to use more or bigger sub-buffers
00109  *   next time.  Of course, if the buffers actually filled up, the
00110  *   maximum backlog would be 4 and you'd have lost data).
00111  *
00112  * - Call relay_app_main_loop().  This will set up an infinite loop
00113  *   (press Control-C to break out and finalize the data) which
00114  *   automatically reads the data from the relayfs buffers as it becomes
00115  *   available and and writes it out to per-cpu output files.
00116  *
00117  *   NOTE: The control channel is implemented as a netlink socket.
00118  *   relay-app defaults to using NETLINK_USERSOCK for all
00119  *   applications, which means that you can't have more than 1
00120  *   relay-app in use at a time, unless you use different netlink
00121  *   'units' for each one.  If you want to have more than one
00122  *   relay-app in use at a time, you can specify a different netlink
00123  *   'unit' by using the _init_relay_app() versions of the
00124  *   init_relay_app() functions, on both the kernel and user sides,
00125  *   which are the same as the init_relay_app() functions but add a
00126  *   netlink unit param.  See netlink.h for the currently unused
00127  *   numbers.
00128  */
00129 
00130 #include <linux/inet.h>
00131 #include <linux/ip.h>
00132 #include <linux/netlink.h>
00133 #include <linux/relayfs_fs.h>
00134 
00135 /* relay-app pseudo-API */
00136 
00137 /*
00138  * relay-app callbacks
00139  */
00140 struct relay_app_callbacks
00141 {
00142         /*
00143          *      user_command - app-specific command callback
00144          *      @command: user-defined command id
00145          *      @data: user-defined data associated with the command
00146          *
00147          *      Return value: 1 if this callback handled it, 0 if not
00148          *
00149          *      define this callback to handle user-defined commands sent
00150          *      from the user space application via send_request()
00151          *
00152          *      NOTE: user commands must be >= RELAY_APP_USERCMD_START
00153          */
00154         int (*user_command) (int command, void *data);
00155 
00156         /*
00157          *      app_started - the user-space application has started
00158          *
00159          *      Do app-specific initializations now, if desired
00160          */
00161         void (*app_started) (void);
00162 
00163         /*
00164          *      app_stopped - the user-space application has stopped
00165          *
00166          *      Do app-specific cleanup now, if desired
00167          */
00168         void (*app_stopped) (void);
00169 };
00170 
00171 /*
00172  * relay-app API functions
00173  */
00174 static int init_relay_app(const char *dirname,
00175                           const char *file_basename,
00176                           struct relay_app_callbacks *callbacks);
00177 static void close_relay_app(void);
00178 
00179 /*
00180  * relay-app write wrapper macros - use these instead of directly
00181  * using relay_write() and _relay_write() relayfs functions.
00182  */
00183 #define relayapp_write(data, len) \
00184         if (app.logging) relay_write(app.chan, data, len)
00185 
00186 #define _relayapp_write(data, len) \
00187         if (app.logging) _relay_write(app.chan, data, len)
00188 
00189 /* relay-app control channel command values */
00190 enum
00191 {
00192         RELAY_APP_BUF_INFO = 1,
00193         RELAY_APP_SUBBUFS_CONSUMED,
00194         RELAY_APP_START,
00195         RELAY_APP_STOP,
00196         RELAY_APP_CHAN_CREATE,
00197         RELAY_APP_CHAN_DESTROY,
00198         RELAY_APP_USERCMD_START = 32
00199 };
00200 
00201 /* SystemTap extensions */
00202 enum
00203 {
00204         STP_REALTIME_DATA = RELAY_APP_USERCMD_START,
00205         STP_EXIT,
00206         STP_DONE
00207 };
00208 
00209 /* internal stuff below here */
00210 
00211 /* netlink control channel */
00212 static struct sock *control;
00213 static int seq;
00214 static int stpd_pid = 0;
00215 
00216 /* info for this application */
00217 static struct relay_app
00218 {
00219         char dirname[1024];
00220         char file_basename[1024];
00221         struct relay_app_callbacks *cb;
00222         struct rchan *chan;
00223         struct dentry *dir;
00224         int logging;
00225         int mappings;
00226 } app;
00227 
00228 /*
00229  * subbuf_start() relayfs callback.
00230  */
00231 static int relay_app_subbuf_start(struct rchan_buf *buf,
00232                                   void *subbuf,
00233                                   unsigned prev_subbuf_idx,
00234                                   void *prev_subbuf)
00235 {
00236         unsigned padding = buf->padding[prev_subbuf_idx];
00237         if (prev_subbuf)
00238                 *((unsigned *)prev_subbuf) = padding;
00239 
00240         return sizeof(padding); /* reserve space for padding */
00241 }
00242 
00243 /*
00244  * buf_full() relayfs callback.
00245  */
00246 static void relay_app_buf_full(struct rchan_buf *buf,
00247                                unsigned subbuf_idx,
00248                                void *subbuf)
00249 {
00250         unsigned padding = buf->padding[subbuf_idx];
00251         *((unsigned *)subbuf) = padding;
00252 }
00253 
00254 static void relay_app_buf_mapped(struct rchan_buf *buf, struct file *filp)
00255 {
00256         if (app.cb && app.cb->app_started && !app.mappings++)
00257                 app.cb->app_started();
00258 }
00259 
00260 static void relay_app_buf_unmapped(struct rchan_buf *buf, struct file *filp)
00261 {
00262         if (app.cb && app.cb->app_started && !--app.mappings)
00263                 app.cb->app_stopped();
00264 }
00265 
00266 static struct rchan_callbacks app_rchan_callbacks =
00267 {
00268         .subbuf_start = relay_app_subbuf_start,
00269         .buf_full = relay_app_buf_full,
00270         .buf_mapped = relay_app_buf_mapped,
00271         .buf_unmapped = relay_app_buf_unmapped
00272 };
00273 
00274 /**
00275  *      create_app_chan - creates channel /mnt/relay/dirname/filebaseXXX
00276  *
00277  *      Returns channel on success, NULL otherwise.
00278  */
00279 static struct rchan *create_app_chan(unsigned subbuf_size,
00280                                      unsigned n_subbufs)
00281 {
00282         struct rchan *chan;
00283 
00284         if (strlen(app.dirname)) {
00285                 app.dir = relayfs_create_dir(app.dirname, NULL);
00286                 if (!app.dir) {
00287                         printk("Couldn't create relayfs app directory %s.\n", app.dirname);
00288                         return NULL;
00289                 }
00290         }
00291 
00292         chan = relay_open(app.file_basename, app.dir, subbuf_size,
00293                               n_subbufs, 0, &app_rchan_callbacks);
00294         
00295         if (!chan) {
00296                 printk("relay app channel creation failed\n");
00297                 if (app.dir)
00298                         relayfs_remove_dir(app.dir);
00299                 return NULL;
00300         }
00301 
00302         return chan;
00303 }
00304 
00305 /**
00306  *      destroy_app_chan - destroys channel /mnt/relay/dirname/filebaseXXX
00307  */
00308 static void destroy_app_chan(struct rchan *chan)
00309 {
00310         if (chan)
00311                 relay_close(chan);
00312         if (app.dir)
00313                 relayfs_remove_dir(app.dir);
00314 
00315         app.chan = NULL;
00316         app.dir = NULL;
00317 }
00318 
00319 /* netlink control channel communication with userspace */
00320 
00321 struct buf_info
00322 {
00323         int cpu;
00324         unsigned produced;
00325         unsigned consumed;
00326 };
00327 
00328 struct consumed_info
00329 {
00330         int cpu;
00331         unsigned consumed;
00332 };
00333 
00334 struct channel_create_info
00335 {
00336         unsigned subbuf_size;
00337         unsigned n_subbufs;
00338 };
00339 
00340 /*
00341  * send_reply - send reply to userspace over netlink control channel
00342  */
00343 static int send_reply(int type, void *reply, int len, int pid)
00344 {
00345         struct sk_buff *skb;
00346         struct nlmsghdr *nlh;
00347         void *data;
00348         int size;
00349         int err;
00350                 
00351         size = NLMSG_SPACE(len);
00352         skb = alloc_skb(size, GFP_ATOMIC);
00353         if (!skb)
00354                 return -1;
00355         nlh = NLMSG_PUT(skb, pid, seq++, type, size - sizeof(*nlh));
00356         nlh->nlmsg_flags = 0;
00357         data = NLMSG_DATA(nlh);
00358         memcpy(data, reply, len);
00359         err = netlink_unicast(control, skb, pid, MSG_DONTWAIT);
00360 
00361         return 0;
00362 
00363 nlmsg_failure:
00364         if (skb)
00365                 kfree_skb(skb);
00366         
00367         return -1;
00368 }
00369 
00370 static void handle_buf_info(struct buf_info *in, int pid)
00371 {
00372         struct buf_info out;
00373 
00374         if (!app.chan)
00375                 return;
00376 
00377         out.cpu = in->cpu;
00378         out.produced = atomic_read(&app.chan->buf[in->cpu]->subbufs_produced);
00379         out.consumed = atomic_read(&app.chan->buf[in->cpu]->subbufs_consumed);
00380 
00381         send_reply(RELAY_APP_BUF_INFO, &out, sizeof(out), pid);
00382 }
00383 
00384 static inline void handle_subbufs_consumed(struct consumed_info *info)
00385 {
00386         if (!app.chan)
00387                 return;
00388 
00389         relay_subbufs_consumed(app.chan, info->cpu, info->consumed);
00390 }
00391 
00392 static inline void handle_create(struct channel_create_info *info)
00393 {
00394         destroy_app_chan(app.chan);
00395         app.chan = create_app_chan(info->subbuf_size, info->n_subbufs);
00396         if(!app.chan)
00397                 return;
00398         app.mappings = 0;
00399 }
00400 
00401 /*
00402  * msg_rcv_skb - dispatch userspace requests from netlink control channel
00403  */
00404 static void msg_rcv_skb(struct sk_buff *skb)
00405 {
00406         struct nlmsghdr *nlh = NULL;
00407         int pid, flags;
00408         int nlmsglen, skblen;
00409         void *data;
00410         
00411         skblen = skb->len;
00412         
00413         if (skblen < sizeof (*nlh))
00414                 return; 
00415 
00416         nlh = (struct nlmsghdr *)skb->data;
00417         nlmsglen = nlh->nlmsg_len;
00418         
00419         if (nlmsglen < sizeof(*nlh) || skblen < nlmsglen)
00420                 return;
00421 
00422         stpd_pid = pid = nlh->nlmsg_pid;
00423         flags = nlh->nlmsg_flags;
00424 
00425         if (pid <= 0 || !(flags & NLM_F_REQUEST)) {
00426                 netlink_ack(skb, nlh, -EINVAL);
00427                 return;
00428         }
00429 
00430         if (flags & MSG_TRUNC) {
00431                 netlink_ack(skb, nlh, -ECOMM);
00432                 return;
00433         }
00434         
00435         data = NLMSG_DATA(nlh);
00436 
00437         switch (nlh->nlmsg_type) {
00438         case RELAY_APP_CHAN_CREATE:
00439                 handle_create(data);
00440                 break;
00441         case RELAY_APP_CHAN_DESTROY:
00442                 destroy_app_chan(app.chan);
00443                 break;
00444         case RELAY_APP_START:
00445                 app.logging = 1;
00446                 break;
00447         case RELAY_APP_STOP:
00448                 app.logging = 0;
00449                 relay_flush(app.chan);
00450                 break;
00451         case RELAY_APP_BUF_INFO:
00452                 handle_buf_info(data, pid);
00453                 break;
00454         case RELAY_APP_SUBBUFS_CONSUMED:
00455                 handle_subbufs_consumed(data);
00456                 break;
00457         default:
00458                 if (!app.cb || !app.cb->user_command ||
00459                     !app.cb->user_command(nlh->nlmsg_type, data))
00460                         netlink_ack(skb, nlh, -EINVAL);
00461                 return;
00462         }
00463         
00464         if (flags & NLM_F_ACK)
00465                 netlink_ack(skb, nlh, 0);
00466 }
00467 
00468 /*
00469  * msg_rcv - handle netlink control channel requests
00470  */
00471 static void msg_rcv(struct sock *sk, int len)
00472 {
00473         struct sk_buff *skb;
00474         
00475         while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
00476                 msg_rcv_skb(skb);
00477                 kfree_skb(skb);
00478         }
00479 }
00480 
00481 /*
00482  * _init_relay_app - adds netlink 'unit' if other than NETLINK_USERSOCK wanted
00483  */
00484 static int _init_relay_app(const char *dirname,
00485                            const char *file_basename,
00486                            struct relay_app_callbacks *callbacks,
00487                            int unit)
00488 {
00489         if (!file_basename)
00490                 return -1;
00491 
00492         if (dirname)
00493                 strncpy(app.dirname, dirname, 1024);
00494         strncpy(app.file_basename, file_basename, 1024);
00495         app.cb = callbacks;
00496 
00497         control = netlink_kernel_create(unit, msg_rcv);
00498         if (!control) {
00499                 printk("Couldn't create control channel\n");
00500                 return -1;
00501         }
00502 
00503         return 0;
00504 }
00505 
00506 /**
00507  *      init_relay_app - initialize /mnt/relay/dirname/file_basenameXXX
00508  *      @dirname: the directory to contain relayfs files for this app
00509  *      @file_basename: the base filename of the relayfs files for this app
00510  *      @callbacks: the relay_app_callbacks implemented for this app
00511  *
00512  *      Returns 0 on success, -1 otherwise.
00513  *
00514  *      NOTE: this doesn't create the relayfs files.  That happens via the
00515  *      control channel protocol.
00516  */
00517 static int init_relay_app(const char *dirname,
00518                           const char *file_basename,
00519                           struct relay_app_callbacks *callbacks)
00520 {
00521         return _init_relay_app(dirname, file_basename, callbacks, NETLINK_USERSOCK);
00522 }
00523 
00524 /**
00525  *      close_relay_app - close netlink socket and destroy channel if it exists
00526  *
00527  *      Returns 0 on success, -1 otherwise.
00528  */
00529 static void close_relay_app(void)
00530 {
00531         if (control)
00532                 sock_release(control->sk_socket);
00533         destroy_app_chan(app.chan);
00534 }