root/source4/ntvfs/sysdep/sys_lease_linux.c

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

DEFINITIONS

This source file includes following definitions.
  1. linux_lease_signal_handler
  2. linux_lease_pending_destructor
  3. linux_lease_init
  4. linux_lease_setup
  5. linux_lease_update
  6. linux_lease_remove
  7. sys_lease_linux_init

   1 /*
   2    Unix SMB/CIFS implementation.
   3 
   4    Copyright (C) Stefan Metzmacher 2008
   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 /*
  21   lease (oplock) implementation using fcntl F_SETLEASE on linux
  22 */
  23 
  24 #include "includes.h"
  25 #include <tevent.h>
  26 #include "system/filesys.h"
  27 #include "ntvfs/sysdep/sys_lease.h"
  28 #include "ntvfs/ntvfs.h"
  29 #include "librpc/gen_ndr/ndr_opendb.h"
  30 #include "../lib/util/dlinklist.h"
  31 #include "cluster/cluster.h"
  32 
  33 #define LINUX_LEASE_RT_SIGNAL (SIGRTMIN+1)
  34 
  35 struct linux_lease_pending {
  36         struct linux_lease_pending *prev, *next;
  37         struct sys_lease_context *ctx;
  38         struct opendb_entry e;
  39 };
  40 
  41 /* the global linked list of pending leases */
  42 static struct linux_lease_pending *leases;
  43 
  44 static void linux_lease_signal_handler(struct tevent_context *ev_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
  45                                        struct tevent_signal *se,
  46                                        int signum, int count,
  47                                        void *_info, void *private_data)
  48 {
  49         struct sys_lease_context *ctx = talloc_get_type(private_data,
  50                                         struct sys_lease_context);
  51         siginfo_t *info = (siginfo_t *)_info;
  52         struct linux_lease_pending *c;
  53         int got_fd = info->si_fd;
  54 
  55         for (c = leases; c; c = c->next) {
  56                 int *fd = (int *)c->e.fd;
  57 
  58                 if (got_fd == *fd) {
  59                         break;
  60                 }
  61         }
  62 
  63         if (!c) {
  64                 return;
  65         }
  66 
  67         ctx->break_send(ctx->msg_ctx, &c->e, OPLOCK_BREAK_TO_NONE);
  68 }
  69 
  70 static int linux_lease_pending_destructor(struct linux_lease_pending *p)
     /* [<][>][^][v][top][bottom][index][help] */
  71 {
  72         int ret;
  73         int *fd = (int *)p->e.fd;
  74 
  75         DLIST_REMOVE(leases, p);
  76 
  77         if (*fd == -1) {
  78                 return 0;
  79         }
  80 
  81         ret = fcntl(*fd, F_SETLEASE, F_UNLCK);
  82         if (ret == -1) {
  83                 DEBUG(0,("%s: failed to remove oplock: %s\n",
  84                         __FUNCTION__, strerror(errno)));
  85         }
  86 
  87         return 0;
  88 }
  89 
  90 static NTSTATUS linux_lease_init(struct sys_lease_context *ctx)
     /* [<][>][^][v][top][bottom][index][help] */
  91 {
  92         struct tevent_signal *se;
  93 
  94         se = tevent_add_signal(ctx->event_ctx, ctx,
  95                                LINUX_LEASE_RT_SIGNAL, SA_SIGINFO,
  96                                linux_lease_signal_handler, ctx);
  97         NT_STATUS_HAVE_NO_MEMORY(se);
  98 
  99         return NT_STATUS_OK;
 100 }
 101 
 102 static NTSTATUS linux_lease_setup(struct sys_lease_context *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 103                                   struct opendb_entry *e)
 104 {
 105         int ret;
 106         int *fd = (int *)e->fd;
 107         struct linux_lease_pending *p;
 108 
 109         if (e->oplock_level == OPLOCK_NONE) {
 110                 e->fd = NULL;
 111                 return NT_STATUS_OK;
 112         } else if (e->oplock_level == OPLOCK_LEVEL_II) {
 113                 /*
 114                  * the linux kernel doesn't support level2 oplocks
 115                  * so fix up the granted oplock level
 116                  */
 117                 e->oplock_level = OPLOCK_NONE;
 118                 e->allow_level_II_oplock = false;
 119                 e->fd = NULL;
 120                 return NT_STATUS_OK;
 121         }
 122 
 123         p = talloc(ctx, struct linux_lease_pending);
 124         NT_STATUS_HAVE_NO_MEMORY(p);
 125 
 126         p->ctx = ctx;
 127         p->e = *e;
 128 
 129         ret = fcntl(*fd, F_SETSIG, LINUX_LEASE_RT_SIGNAL);
 130         if (ret == -1) {
 131                 talloc_free(p);
 132                 return map_nt_error_from_unix(errno);
 133         }
 134 
 135         ret = fcntl(*fd, F_SETLEASE, F_WRLCK);
 136         if (ret == -1) {
 137                 talloc_free(p);
 138                 return map_nt_error_from_unix(errno);
 139         }
 140 
 141         DLIST_ADD(leases, p);
 142 
 143         talloc_set_destructor(p, linux_lease_pending_destructor);
 144 
 145         return NT_STATUS_OK;
 146 }
 147 
 148 static NTSTATUS linux_lease_remove(struct sys_lease_context *ctx,
 149                                    struct opendb_entry *e);
 150 
 151 static NTSTATUS linux_lease_update(struct sys_lease_context *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 152                                    struct opendb_entry *e)
 153 {
 154         struct linux_lease_pending *c;
 155 
 156         for (c = leases; c; c = c->next) {
 157                 if (c->e.fd == e->fd) {
 158                         break;
 159                 }
 160         }
 161 
 162         if (!c) {
 163                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
 164         }
 165 
 166         /*
 167          * set the fd pointer to NULL so that the caller
 168          * will not call the remove function as the oplock
 169          * is already removed
 170          */
 171         e->fd = NULL;
 172 
 173         talloc_free(c);
 174 
 175         return NT_STATUS_OK;
 176 }
 177 
 178 static NTSTATUS linux_lease_remove(struct sys_lease_context *ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 179                                    struct opendb_entry *e)
 180 {
 181         struct linux_lease_pending *c;
 182 
 183         for (c = leases; c; c = c->next) {
 184                 if (c->e.fd == e->fd) {
 185                         break;
 186                 }
 187         }
 188 
 189         if (!c) {
 190                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
 191         }
 192 
 193         talloc_free(c);
 194 
 195         return NT_STATUS_OK;
 196 }
 197 
 198 static struct sys_lease_ops linux_lease_ops = {
 199         .name   = "linux",
 200         .init   = linux_lease_init,
 201         .setup  = linux_lease_setup,
 202         .update = linux_lease_update,
 203         .remove = linux_lease_remove
 204 };
 205 
 206 /*
 207   initialialise the linux lease module
 208  */
 209 NTSTATUS sys_lease_linux_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 210 {
 211         /* register ourselves as a system lease module */
 212         return sys_lease_register(&linux_lease_ops);
 213 }

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