root/source3/smbd/oplock_irix.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. irix_oplocks_available
  2. file_id_create_dev
  3. irix_oplock_receive_message
  4. irix_set_kernel_oplock
  5. irix_release_kernel_oplock
  6. irix_oplocks_read_fde_handler
  7. irix_init_kernel_oplocks
  8. oplock_irix_dummy

   1 /*
   2    Unix SMB/CIFS implementation.
   3    IRIX kernel oplock processing
   4    Copyright (C) Andrew Tridgell 1992-1998
   5    
   6    This program is free software; you can redistribute it and/or modify
   7    it under the terms of the GNU General Public License as published by
   8    the Free Software Foundation; either version 3 of the License, or
   9    (at your option) any later version.
  10    
  11    This program is distributed in the hope that it will be useful,
  12    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14    GNU General Public License for more details.
  15    
  16    You should have received a copy of the GNU General Public License
  17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18 */
  19 
  20 #define DBGC_CLASS DBGC_LOCKING
  21 #include "includes.h"
  22 #include "smbd/globals.h"
  23 
  24 #if HAVE_KERNEL_OPLOCKS_IRIX
  25 
  26 struct irix_oplocks_context {
  27         struct kernel_oplocks *ctx;
  28         int write_fd;
  29         int read_fd;
  30         struct fd_event *read_fde;
  31         bool pending;
  32 };
  33 
  34 /****************************************************************************
  35  Test to see if IRIX kernel oplocks work.
  36 ****************************************************************************/
  37 
  38 static bool irix_oplocks_available(void)
     /* [<][>][^][v][top][bottom][index][help] */
  39 {
  40         int fd;
  41         int pfd[2];
  42         TALLOC_CTX *ctx = talloc_stackframe();
  43         char *tmpname = NULL;
  44 
  45         set_effective_capability(KERNEL_OPLOCK_CAPABILITY);
  46 
  47         tmpname = talloc_asprintf(ctx,
  48                                 "%s/koplock.%d",
  49                                 lp_lockdir(),
  50                                 (int)sys_getpid());
  51         if (!tmpname) {
  52                 TALLOC_FREE(ctx);
  53                 return False;
  54         }
  55 
  56         if(pipe(pfd) != 0) {
  57                 DEBUG(0,("check_kernel_oplocks: Unable to create pipe. Error "
  58                          "was %s\n",
  59                          strerror(errno) ));
  60                 TALLOC_FREE(ctx);
  61                 return False;
  62         }
  63 
  64         if((fd = sys_open(tmpname, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600)) < 0) {
  65                 DEBUG(0,("check_kernel_oplocks: Unable to open temp test file "
  66                          "%s. Error was %s\n",
  67                          tmpname, strerror(errno) ));
  68                 unlink( tmpname );
  69                 close(pfd[0]);
  70                 close(pfd[1]);
  71                 TALLOC_FREE(ctx);
  72                 return False;
  73         }
  74 
  75         unlink(tmpname);
  76 
  77         TALLOC_FREE(ctx);
  78 
  79         if(sys_fcntl_long(fd, F_OPLKREG, pfd[1]) == -1) {
  80                 DEBUG(0,("check_kernel_oplocks: Kernel oplocks are not "
  81                          "available on this machine. Disabling kernel oplock "
  82                          "support.\n" ));
  83                 close(pfd[0]);
  84                 close(pfd[1]);
  85                 close(fd);
  86                 return False;
  87         }
  88 
  89         if(sys_fcntl_long(fd, F_OPLKACK, OP_REVOKE) < 0 ) {
  90                 DEBUG(0,("check_kernel_oplocks: Error when removing kernel "
  91                          "oplock. Error was %s. Disabling kernel oplock "
  92                          "support.\n", strerror(errno) ));
  93                 close(pfd[0]);
  94                 close(pfd[1]);
  95                 close(fd);
  96                 return False;
  97         }
  98 
  99         close(pfd[0]);
 100         close(pfd[1]);
 101         close(fd);
 102 
 103         return True;
 104 }
 105 
 106 /*
 107  * This is bad because the file_id should always be created through the vfs
 108  * layer!  Unfortunately, a conn struct isn't available here.
 109  */
 110 static struct file_id file_id_create_dev(SMB_DEV_T dev, SMB_INO_T inode)
     /* [<][>][^][v][top][bottom][index][help] */
 111 {
 112         struct file_id key;
 113 
 114         /* the ZERO_STRUCT ensures padding doesn't break using the key as a
 115          * blob */
 116         ZERO_STRUCT(key);
 117 
 118         key.devid = dev;
 119         key.inode = inode;
 120 
 121         return key;
 122 }
 123 
 124 /****************************************************************************
 125  * Deal with the IRIX kernel <--> smbd
 126  * oplock break protocol.
 127 ****************************************************************************/
 128 
 129 static files_struct *irix_oplock_receive_message(struct kernel_oplocks *_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 130 {
 131         struct irix_oplocks_context *ctx = talloc_get_type(_ctx->private_data,
 132                                            struct irix_oplocks_context);
 133         oplock_stat_t os;
 134         char dummy;
 135         struct file_id fileid;
 136         files_struct *fsp;
 137 
 138         /*
 139          * TODO: is it correct to assume we only get one
 140          * oplock break, for each byte we read from the pipe?
 141          */
 142         ctx->pending = false;
 143 
 144         /*
 145          * Read one byte of zero to clear the
 146          * kernel break notify message.
 147          */
 148 
 149         if(read(ctx->read_fd, &dummy, 1) != 1) {
 150                 DEBUG(0,("irix_oplock_receive_message: read of kernel "
 151                          "notification failed. Error was %s.\n",
 152                          strerror(errno) ));
 153                 return NULL;
 154         }
 155 
 156         /*
 157          * Do a query to get the
 158          * device and inode of the file that has the break
 159          * request outstanding.
 160          */
 161 
 162         if(sys_fcntl_ptr(ctx->read_fd, F_OPLKSTAT, &os) < 0) {
 163                 DEBUG(0,("irix_oplock_receive_message: fcntl of kernel "
 164                          "notification failed. Error was %s.\n",
 165                          strerror(errno) ));
 166                 if(errno == EAGAIN) {
 167                         /*
 168                          * Duplicate kernel break message - ignore.
 169                          */
 170                         return NULL;
 171                 }
 172                 return NULL;
 173         }
 174 
 175         /*
 176          * We only have device and inode info here - we have to guess that this
 177          * is the first fsp open with this dev,ino pair.
 178          *
 179          * NOTE: this doesn't work if any VFS modules overloads
 180          *       the file_id_create() hook!
 181          */
 182 
 183         fileid = file_id_create_dev((SMB_DEV_T)os.os_dev,
 184                                     (SMB_INO_T)os.os_ino);
 185         if ((fsp = file_find_di_first(fileid)) == NULL) {
 186                 DEBUG(0,("irix_oplock_receive_message: unable to find open "
 187                          "file with dev = %x, inode = %.0f\n",
 188                          (unsigned int)os.os_dev, (double)os.os_ino ));
 189                 return NULL;
 190         }
 191      
 192         DEBUG(5,("irix_oplock_receive_message: kernel oplock break request "
 193                  "received for file_id %s gen_id = %ul",
 194                  file_id_string_tos(&fsp->file_id),
 195                  fsp->fh->gen_id ));
 196 
 197         return fsp;
 198 }
 199 
 200 /****************************************************************************
 201  Attempt to set an kernel oplock on a file.
 202 ****************************************************************************/
 203 
 204 static bool irix_set_kernel_oplock(struct kernel_oplocks *_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 205                                    files_struct *fsp, int oplock_type)
 206 {
 207         struct irix_oplocks_context *ctx = talloc_get_type(_ctx->private_data,
 208                                            struct irix_oplocks_context);
 209 
 210         if (sys_fcntl_long(fsp->fh->fd, F_OPLKREG, ctx->write_fd) == -1) {
 211                 if(errno != EAGAIN) {
 212                         DEBUG(0,("irix_set_kernel_oplock: Unable to get "
 213                                  "kernel oplock on file %s, file_id %s "
 214                                  "gen_id = %ul. Error was %s\n", 
 215                                  fsp->fsp_name, file_id_string_tos(&fsp->file_id), 
 216                                  fsp->fh->gen_id,
 217                                  strerror(errno) ));
 218                 } else {
 219                         DEBUG(5,("irix_set_kernel_oplock: Refused oplock on "
 220                                  "file %s, fd = %d, file_id = %s, "
 221                                  "gen_id = %ul. Another process had the file "
 222                                  "open.\n",
 223                                  fsp->fsp_name, fsp->fh->fd,
 224                                  file_id_string_tos(&fsp->file_id),
 225                                  fsp->fh->gen_id ));
 226                 }
 227                 return False;
 228         }
 229         
 230         DEBUG(10,("irix_set_kernel_oplock: got kernel oplock on file %s, file_id = %s "
 231                   "gen_id = %ul\n",
 232                   fsp->fsp_name, file_id_string_tos(&fsp->file_id),
 233                   fsp->fh->gen_id));
 234 
 235         return True;
 236 }
 237 
 238 /****************************************************************************
 239  Release a kernel oplock on a file.
 240 ****************************************************************************/
 241 
 242 static void irix_release_kernel_oplock(struct kernel_oplocks *_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 243                                        files_struct *fsp, int oplock_type)
 244 {
 245         if (DEBUGLVL(10)) {
 246                 /*
 247                  * Check and print out the current kernel
 248                  * oplock state of this file.
 249                  */
 250                 int state = sys_fcntl_long(fsp->fh->fd, F_OPLKACK, -1);
 251                 dbgtext("irix_release_kernel_oplock: file %s, file_id = %s"
 252                         "gen_id = %ul, has kernel oplock state "
 253                         "of %x.\n", fsp->fsp_name, file_id_string_tos(&fsp->file_id),
 254                         fsp->fh->gen_id, state );
 255         }
 256 
 257         /*
 258          * Remove the kernel oplock on this file.
 259          */
 260         if(sys_fcntl_long(fsp->fh->fd, F_OPLKACK, OP_REVOKE) < 0) {
 261                 if( DEBUGLVL( 0 )) {
 262                         dbgtext("irix_release_kernel_oplock: Error when "
 263                                 "removing kernel oplock on file " );
 264                         dbgtext("%s, file_id = %s gen_id = %ul. "
 265                                 "Error was %s\n",
 266                                 fsp->fsp_name, file_id_string_tos(&fsp->file_id),
 267                                 fsp->fh->gen_id,
 268                                 strerror(errno) );
 269                 }
 270         }
 271 }
 272 
 273 static void irix_oplocks_read_fde_handler(struct event_context *ev,
     /* [<][>][^][v][top][bottom][index][help] */
 274                                           struct fd_event *fde,
 275                                           uint16_t flags,
 276                                           void *private_data)
 277 {
 278         struct irix_oplocks_context *ctx = talloc_get_type(private_data,
 279                                            struct irix_oplocks_context);
 280         files_struct *fsp;
 281 
 282         fsp = irix_oplock_receive_message(ctx->ctx);
 283         break_kernel_oplock(smbd_messaging_context(), fsp);
 284 }
 285 
 286 /****************************************************************************
 287  Setup kernel oplocks.
 288 ****************************************************************************/
 289 
 290 static const struct kernel_oplocks_ops irix_koplocks = {
 291         .set_oplock                     = irix_set_kernel_oplock,
 292         .release_oplock                 = irix_release_kernel_oplock,
 293         .contend_level2_oplocks_begin   = NULL,
 294         .contend_level2_oplocks_end     = NULL,
 295 };
 296 
 297 struct kernel_oplocks *irix_init_kernel_oplocks(TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 298 {
 299         struct kernel_oplocks *_ctx;
 300         struct irix_oplocks_context *ctx;
 301         int pfd[2];
 302 
 303         if (!irix_oplocks_available())
 304                 return NULL;
 305 
 306         _ctx = talloc_zero(mem_ctx, struct kernel_oplocks);
 307         if (!_ctx) {
 308                 return NULL;
 309         }
 310 
 311         ctx = talloc_zero(_ctx, struct irix_oplocks_context);
 312         if (!ctx) {
 313                 talloc_free(_ctx);
 314                 return NULL;
 315         }
 316         _ctx->ops = &irix_koplocks;
 317         _ctx->private_data = ctx;
 318         ctx->ctx = _ctx;
 319 
 320         if(pipe(pfd) != 0) {
 321                 talloc_free(_ctx);
 322                 DEBUG(0,("setup_kernel_oplock_pipe: Unable to create pipe. "
 323                          "Error was %s\n", strerror(errno) ));
 324                 return False;
 325         }
 326 
 327         ctx->read_fd = pfd[0];
 328         ctx->write_fd = pfd[1];
 329 
 330         ctx->read_fde = event_add_fd(smbd_event_context(),
 331                                      ctx,
 332                                      ctx->read_fd,
 333                                      EVENT_FD_READ,
 334                                      irix_oplocks_read_fde_handler,
 335                                      ctx);
 336         return _ctx;
 337 }
 338 #else
 339  void oplock_irix_dummy(void);
 340  void oplock_irix_dummy(void) {}
     /* [<][>][^][v][top][bottom][index][help] */
 341 #endif /* HAVE_KERNEL_OPLOCKS_IRIX */

/* [<][>][^][v][top][bottom][index][help] */