~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/ntvfs/sysdep/sys_lease_linux.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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,
 
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)
 
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)
 
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,
 
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,
 
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,
 
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)
 
210
{
 
211
        /* register ourselves as a system lease module */
 
212
        return sys_lease_register(&linux_lease_ops);
 
213
}