1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-15 23:24:37 +03:00

Merge branch 'v4-0-test' of git://git.samba.org/samba into 4-0-local

(This used to be commit e9567e39106efb7443ed2c5df3492208b1c1d766)
This commit is contained in:
Andrew Bartlett 2008-03-13 10:00:57 +11:00
commit 3d9056aa86
16 changed files with 655 additions and 67 deletions

View File

@ -283,7 +283,7 @@ static NTSTATUS odb_oplock_break_send(struct odb_context *odb, struct opendb_ent
*/
static NTSTATUS odb_ctdb_open_file(struct odb_lock *lck,
void *file_handle, const char *path,
bool allow_level_II_oplock,
int *fd, bool allow_level_II_oplock,
uint32_t oplock_level, uint32_t *oplock_granted)
{

View File

@ -20,6 +20,7 @@ interface opendb
uint32 share_access;
uint32 access_mask;
pointer file_handle;
pointer fd;
/* we need a per-entry delete on close, as well as a per-file
one, to cope with strange semantics on open */
boolean8 delete_on_close;

View File

@ -595,6 +595,13 @@ static NTSTATUS cvfs_rename(struct ntvfs_module_context *ntvfs,
SETUP_PID;
if (ren->nttrans.level == RAW_RENAME_NTTRANS) {
struct cvfs_file *f;
f = ntvfs_handle_get_backend_data(ren->nttrans.in.file.ntvfs, ntvfs);
if (!f) return NT_STATUS_INVALID_HANDLE;
ren->nttrans.in.file.fnum = f->fnum;
}
if (!(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
return smb_raw_rename(private->tree, ren);
}

View File

@ -9,7 +9,10 @@ OBJ_FILES = \
opendb.o \
opendb_tdb.o \
notify.o
PUBLIC_DEPENDENCIES = NDR_OPENDB NDR_NOTIFY sys_notify share LIBDBWRAP
PUBLIC_DEPENDENCIES = \
NDR_OPENDB NDR_NOTIFY \
sys_notify sys_lease \
share LIBDBWRAP
PRIVATE_DEPENDENCIES = brlock_ctdb opendb_ctdb
# End LIBRARY ntvfs_common
################################################

View File

@ -97,11 +97,11 @@ _PUBLIC_ DATA_BLOB odb_get_key(TALLOC_CTX *mem_ctx, struct odb_lock *lck)
*/
_PUBLIC_ NTSTATUS odb_open_file(struct odb_lock *lck,
void *file_handle, const char *path,
bool allow_level_II_oplock,
int *fd, bool allow_level_II_oplock,
uint32_t oplock_level, uint32_t *oplock_granted)
{
return ops->odb_open_file(lck, file_handle, path,
allow_level_II_oplock,
fd, allow_level_II_oplock,
oplock_level, oplock_granted);
}

View File

@ -27,7 +27,7 @@ struct opendb_ops {
DATA_BLOB (*odb_get_key)(TALLOC_CTX *mem_ctx, struct odb_lock *lck);
NTSTATUS (*odb_open_file)(struct odb_lock *lck,
void *file_handle, const char *path,
bool allow_level_II_oplock,
int *fd, bool allow_level_II_oplock,
uint32_t oplock_level, uint32_t *oplock_granted);
NTSTATUS (*odb_open_file_pending)(struct odb_lock *lck, void *private);
NTSTATUS (*odb_close_file)(struct odb_lock *lck, void *file_handle,

View File

@ -49,11 +49,13 @@
#include "ntvfs/common/ntvfs_common.h"
#include "cluster/cluster.h"
#include "param/param.h"
#include "ntvfs/sysdep/sys_lease.h"
struct odb_context {
struct tdb_wrap *w;
struct ntvfs_context *ntvfs_ctx;
bool oplocks;
struct sys_lease_context *lease_ctx;
};
/*
@ -72,6 +74,10 @@ struct odb_lock {
} can_open;
};
static NTSTATUS odb_oplock_break_send(struct messaging_context *msg_ctx,
struct opendb_entry *e,
uint8_t level);
/*
Open up the openfiles.tdb database. Close it down using
talloc_free(). We need the messaging_ctx to allow for pending open
@ -98,6 +104,11 @@ static struct odb_context *odb_tdb_init(TALLOC_CTX *mem_ctx,
/* leave oplocks disabled by default until the code is working */
odb->oplocks = lp_parm_bool(ntvfs_ctx->lp_ctx, NULL, "opendb", "oplocks", false);
odb->lease_ctx = sys_lease_context_create(ntvfs_ctx->config, odb,
ntvfs_ctx->event_ctx,
ntvfs_ctx->msg_ctx,
odb_oplock_break_send);
return odb;
}
@ -442,7 +453,7 @@ static NTSTATUS odb_tdb_open_can_internal(struct odb_context *odb,
*/
static NTSTATUS odb_tdb_open_file(struct odb_lock *lck,
void *file_handle, const char *path,
bool allow_level_II_oplock,
int *fd, bool allow_level_II_oplock,
uint32_t oplock_level, uint32_t *oplock_granted)
{
struct odb_context *odb = lck->odb;
@ -491,22 +502,29 @@ static NTSTATUS odb_tdb_open_file(struct odb_lock *lck,
oplock_level = OPLOCK_NONE;
}
lck->can_open.e->file_handle = file_handle;
lck->can_open.e->fd = fd;
lck->can_open.e->allow_level_II_oplock = allow_level_II_oplock;
lck->can_open.e->oplock_level = oplock_level;
if (odb->lease_ctx && fd) {
NTSTATUS status;
status = sys_lease_setup(odb->lease_ctx, lck->can_open.e);
NT_STATUS_NOT_OK_RETURN(status);
}
if (oplock_granted) {
if (oplock_level == OPLOCK_EXCLUSIVE) {
if (lck->can_open.e->oplock_level == OPLOCK_EXCLUSIVE) {
*oplock_granted = EXCLUSIVE_OPLOCK_RETURN;
} else if (oplock_level == OPLOCK_BATCH) {
} else if (lck->can_open.e->oplock_level == OPLOCK_BATCH) {
*oplock_granted = BATCH_OPLOCK_RETURN;
} else if (oplock_level == OPLOCK_LEVEL_II) {
} else if (lck->can_open.e->oplock_level == OPLOCK_LEVEL_II) {
*oplock_granted = LEVEL_II_OPLOCK_RETURN;
} else {
*oplock_granted = NO_OPLOCK_RETURN;
}
}
lck->can_open.e->file_handle = file_handle;
lck->can_open.e->allow_level_II_oplock = allow_level_II_oplock;
lck->can_open.e->oplock_level = oplock_level;
/* it doesn't conflict, so add it to the end */
lck->file.entries = talloc_realloc(lck, lck->file.entries,
struct opendb_entry,
@ -569,6 +587,11 @@ static NTSTATUS odb_tdb_close_file(struct odb_lock *lck, void *file_handle,
if (lck->file.entries[i].delete_on_close) {
lck->file.delete_on_close = true;
}
if (odb->lease_ctx && lck->file.entries[i].fd) {
NTSTATUS status;
status = sys_lease_remove(odb->lease_ctx, &lck->file.entries[i]);
NT_STATUS_NOT_OK_RETURN(status);
}
if (i < lck->file.num_entries-1) {
memmove(lck->file.entries+i, lck->file.entries+i+1,
(lck->file.num_entries - (i+1)) *
@ -622,6 +645,13 @@ static NTSTATUS odb_tdb_update_oplock(struct odb_lock *lck, void *file_handle,
if (file_handle == lck->file.entries[i].file_handle &&
cluster_id_equal(&odb->ntvfs_ctx->server_id, &lck->file.entries[i].server)) {
lck->file.entries[i].oplock_level = oplock_level;
if (odb->lease_ctx && lck->file.entries[i].fd) {
NTSTATUS status;
status = sys_lease_update(odb->lease_ctx, &lck->file.entries[i]);
NT_STATUS_NOT_OK_RETURN(status);
}
break;
}
}
@ -800,6 +830,7 @@ static NTSTATUS odb_tdb_can_open(struct odb_lock *lck,
lck->can_open.e->server = odb->ntvfs_ctx->server_id;
lck->can_open.e->file_handle = NULL;
lck->can_open.e->fd = NULL;
lck->can_open.e->stream_id = stream_id;
lck->can_open.e->share_access = share_access;
lck->can_open.e->access_mask = access_mask;
@ -831,5 +862,6 @@ static const struct opendb_ops opendb_tdb_ops = {
void odb_tdb_init_ops(void)
{
sys_lease_init();
odb_set_ops(&opendb_tdb_ops);
}

View File

@ -300,7 +300,7 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
/* now really mark the file as open */
status = odb_open_file(lck, f->handle, name->full_name,
false, OPLOCK_NONE, NULL);
NULL, false, OPLOCK_NONE, NULL);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(lck);
@ -360,7 +360,7 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
}
status = odb_open_file(lck, f->handle, name->full_name,
false, OPLOCK_NONE, NULL);
NULL, false, OPLOCK_NONE, NULL);
if (!NT_STATUS_IS_OK(status)) {
goto cleanup_delete;
@ -600,7 +600,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
mode = pvfs_fileperms(pvfs, attrib);
/* create the file */
fd = open(name->full_name, flags | O_CREAT | O_EXCL, mode);
fd = open(name->full_name, flags | O_CREAT | O_EXCL| O_NONBLOCK, mode);
if (fd == -1) {
return pvfs_map_errno(pvfs, errno);
}
@ -688,19 +688,6 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
return status;
}
status = odb_open_file(lck, f->handle, name->full_name,
allow_level_II_oplock,
oplock_level, &oplock_granted);
talloc_free(lck);
if (!NT_STATUS_IS_OK(status)) {
/* bad news, we must have hit a race - we don't delete the file
here as the most likely scenario is that someone else created
the file at the same time */
close(fd);
return status;
}
f->ntvfs = h;
f->pvfs = pvfs;
f->pending_list = NULL;
@ -723,6 +710,18 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
f->handle->sticky_write_time = false;
f->handle->open_completed = false;
status = odb_open_file(lck, f->handle, name->full_name,
&f->handle->fd, allow_level_II_oplock,
oplock_level, &oplock_granted);
talloc_free(lck);
if (!NT_STATUS_IS_OK(status)) {
/* bad news, we must have hit a race - we don't delete the file
here as the most likely scenario is that someone else created
the file at the same time */
close(fd);
return status;
}
DLIST_ADD(pvfs->files.list, f);
/* setup a destructor to avoid file descriptor leaks on
@ -859,7 +858,13 @@ NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
/* setup a pending lock */
status = odb_open_file_pending(lck, r);
if (!NT_STATUS_IS_OK(status)) {
if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND,status)) {
/*
* maybe only a unix application
* has the file open
*/
data_blob_free(&r->odb_locking_key);
} else if (!NT_STATUS_IS_OK(status)) {
return status;
}
@ -892,8 +897,14 @@ static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
enum pvfs_wait_notice reason)
{
union smb_open *io = talloc_get_type(_io, union smb_open);
struct timeval *final_timeout = NULL;
NTSTATUS status;
if (private_data) {
final_timeout = talloc_get_type(private_data,
struct timeval);
}
/* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
just a bug in their server, but we better do the same */
if (reason == PVFS_WAIT_CANCEL) {
@ -901,6 +912,16 @@ static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
}
if (reason == PVFS_WAIT_TIMEOUT) {
if (final_timeout &&
!timeval_expired(final_timeout)) {
/*
* we need to retry periodictly
* after an EAGAIN as there's
* no way the kernel tell us
* an oplock is released.
*/
goto retry;
}
/* if it timed out, then give the failure
immediately */
talloc_free(r);
@ -909,6 +930,7 @@ static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
return;
}
retry:
talloc_free(r);
/* try the open again, which could trigger another retry setup
@ -1028,6 +1050,7 @@ static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
struct pvfs_state *pvfs = ntvfs->private_data;
NTSTATUS status;
struct timeval end_time;
struct timeval *final_timeout = NULL;
if (io->generic.in.create_options &
(NTCREATEX_OPTIONS_PRIVATE_DENY_DOS | NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
@ -1048,12 +1071,28 @@ static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
} else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
end_time = timeval_add(&req->statistics.request_time,
pvfs->oplock_break_timeout, 0);
} else if (NT_STATUS_EQUAL(parent_status, STATUS_MORE_ENTRIES)) {
/*
* we got EAGAIN which means a unix application
* has an oplock or share mode
*
* we retry every 4/5 of the sharing violation delay
* to see if the unix application
* has released the oplock or share mode.
*/
final_timeout = talloc(req, struct timeval);
NT_STATUS_HAVE_NO_MEMORY(final_timeout);
*final_timeout = timeval_add(&req->statistics.request_time,
pvfs->oplock_break_timeout,
0);
end_time = timeval_current_ofs(0, (pvfs->sharing_violation_delay*4)/5);
end_time = timeval_min(final_timeout, &end_time);
} else {
return NT_STATUS_INTERNAL_ERROR;
}
return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL,
pvfs_retry_open_sharing);
return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io,
final_timeout, pvfs_retry_open_sharing);
}
/*
@ -1297,9 +1336,34 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
return status;
}
if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
flags |= O_RDWR;
} else {
flags |= O_RDONLY;
}
/* do the actual open */
fd = open(f->handle->name->full_name, flags | O_NONBLOCK);
if (fd == -1) {
status = pvfs_map_errno(f->pvfs, errno);
/*
* STATUS_MORE_ENTRIES is EAGAIN or EWOULDBLOCK
*/
if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES) &&
(req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
}
talloc_free(lck);
return status;
}
f->handle->fd = fd;
/* now really mark the file as open */
status = odb_open_file(lck, f->handle, name->full_name,
allow_level_II_oplock,
&f->handle->fd, allow_level_II_oplock,
oplock_level, &oplock_granted);
if (!NT_STATUS_IS_OK(status)) {
@ -1319,21 +1383,6 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
f->handle->have_opendb_entry = true;
if (access_mask & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA)) {
flags |= O_RDWR;
} else {
flags |= O_RDONLY;
}
/* do the actual open */
fd = open(f->handle->name->full_name, flags);
if (fd == -1) {
talloc_free(lck);
return pvfs_map_errno(f->pvfs, errno);
}
f->handle->fd = fd;
stream_existed = name->stream_exists;
/* if this was a stream create then create the stream as well */

View File

@ -568,6 +568,9 @@ static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs,
NTSTATUS pvfs_rename(struct ntvfs_module_context *ntvfs,
struct ntvfs_request *req, union smb_rename *ren)
{
struct pvfs_state *pvfs = ntvfs->private_data;
struct pvfs_file *f;
switch (ren->generic.level) {
case RAW_RENAME_RENAME:
return pvfs_rename_mv(ntvfs, req, ren);
@ -576,7 +579,13 @@ NTSTATUS pvfs_rename(struct ntvfs_module_context *ntvfs,
return pvfs_rename_nt(ntvfs, req, ren);
case RAW_RENAME_NTTRANS:
return NT_STATUS_NOT_IMPLEMENTED;
f = pvfs_find_fd(pvfs, req, ren->nttrans.in.file.ntvfs);
if (!f) {
return NT_STATUS_INVALID_HANDLE;
}
/* wk23 ignores the request */
return NT_STATUS_OK;
default:
break;

View File

@ -11,3 +11,13 @@ fi
if test x"$ac_cv_header_linux_inotify_h" = x"yes" -a x"$ac_cv_have___NR_inotify_init_decl" = x"yes"; then
SMB_ENABLE(sys_notify_inotify, YES)
fi
AC_HAVE_DECL(F_SETLEASE, [#include <fcntl.h>])
AC_HAVE_DECL(SA_SIGINFO, [#include <signal.h>])
SMB_ENABLE(sys_lease_linux, NO)
if test x"$ac_cv_have_F_SETLEASE_decl" = x"yes" \
-a x"$ac_cv_have_SA_SIGINFO_decl" = x"yes"; then
SMB_ENABLE(sys_lease_linux, YES)
fi

View File

@ -16,3 +16,21 @@ OBJ_FILES = \
PUBLIC_DEPENDENCIES =
# End SUBSYSTEM sys_notify
################################################
################################################
# Start MODULE sys_lease_linux
[MODULE::sys_lease_linux]
SUBSYSTEM = sys_lease
INIT_FUNCTION = sys_lease_linux_init
OBJ_FILES = \
sys_lease_linux.o
# End MODULE sys_lease_linux
################################################
################################################
# Start SUBSYSTEM sys_lease
[SUBSYSTEM::sys_lease]
OBJ_FILES = \
sys_lease.o
# End SUBSYSTEM sys_lease
################################################

View File

@ -0,0 +1,142 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Stefan Metzmacher 2008
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
abstract the various kernel interfaces to leases (oplocks) into a
single Samba friendly interface
*/
#include "includes.h"
#include "system/filesys.h"
#include "ntvfs/sysdep/sys_lease.h"
#include "lib/events/events.h"
#include "lib/util/dlinklist.h"
#include "param/param.h"
#include "build.h"
/* list of registered backends */
static struct sys_lease_ops *backends;
static uint32_t num_backends;
#define LEASE_BACKEND "lease:backend"
/*
initialise a system change notify backend
*/
_PUBLIC_ struct sys_lease_context *sys_lease_context_create(struct share_config *scfg,
TALLOC_CTX *mem_ctx,
struct event_context *ev,
struct messaging_context *msg,
sys_lease_send_break_fn break_send)
{
struct sys_lease_context *ctx;
const char *bname;
int i;
NTSTATUS status;
if (num_backends == 0) {
return NULL;
}
if (ev == NULL) {
ev = event_context_find(mem_ctx);
}
ctx = talloc_zero(mem_ctx, struct sys_lease_context);
if (ctx == NULL) {
return NULL;
}
ctx->event_ctx = ev;
ctx->msg_ctx = msg;
ctx->break_send = break_send;
bname = share_string_option(scfg, LEASE_BACKEND, NULL);
if (!bname) {
talloc_free(ctx);
return NULL;
}
for (i=0;i<num_backends;i++) {
if (strcasecmp(backends[i].name, bname) == 0) {
ctx->ops = &backends[i];
break;
}
}
if (!ctx->ops) {
talloc_free(ctx);
return NULL;
}
status = ctx->ops->init(ctx);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(ctx);
return NULL;
}
return ctx;
}
/*
register a lease backend
*/
_PUBLIC_ NTSTATUS sys_lease_register(const struct sys_lease_ops *backend)
{
struct sys_lease_ops *b;
b = talloc_realloc(talloc_autofree_context(), backends,
struct sys_lease_ops, num_backends+1);
NT_STATUS_HAVE_NO_MEMORY(b);
backends = b;
backends[num_backends] = *backend;
num_backends++;
return NT_STATUS_OK;
}
_PUBLIC_ NTSTATUS sys_lease_init(void)
{
static bool initialized = false;
init_module_fn static_init[] = { STATIC_sys_lease_MODULES };
if (initialized) return NT_STATUS_OK;
initialized = true;
run_init_functions(static_init);
return NT_STATUS_OK;
}
NTSTATUS sys_lease_setup(struct sys_lease_context *ctx,
struct opendb_entry *e)
{
return ctx->ops->setup(ctx, e);
}
NTSTATUS sys_lease_update(struct sys_lease_context *ctx,
struct opendb_entry *e)
{
return ctx->ops->update(ctx, e);
}
NTSTATUS sys_lease_remove(struct sys_lease_context *ctx,
struct opendb_entry *e)
{
return ctx->ops->remove(ctx, e);
}

View File

@ -0,0 +1,65 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Stefan Metzmacher 2008
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "param/share.h"
struct sys_lease_context;
struct opendb_entry;
struct messaging_context;
typedef NTSTATUS (*sys_lease_send_break_fn)(struct messaging_context *,
struct opendb_entry *,
uint8_t level);
struct sys_lease_ops {
const char *name;
NTSTATUS (*init)(struct sys_lease_context *ctx);
NTSTATUS (*setup)(struct sys_lease_context *ctx,
struct opendb_entry *e);
NTSTATUS (*update)(struct sys_lease_context *ctx,
struct opendb_entry *e);
NTSTATUS (*remove)(struct sys_lease_context *ctx,
struct opendb_entry *e);
};
struct sys_lease_context {
struct event_context *event_ctx;
struct messaging_context *msg_ctx;
sys_lease_send_break_fn break_send;
void *private_data; /* for use of backend */
const struct sys_lease_ops *ops;
};
NTSTATUS sys_lease_register(const struct sys_lease_ops *ops);
NTSTATUS sys_lease_init(void);
struct sys_lease_context *sys_lease_context_create(struct share_config *scfg,
TALLOC_CTX *mem_ctx,
struct event_context *ev,
struct messaging_context *msg_ctx,
sys_lease_send_break_fn break_send);
NTSTATUS sys_lease_setup(struct sys_lease_context *ctx,
struct opendb_entry *e);
NTSTATUS sys_lease_update(struct sys_lease_context *ctx,
struct opendb_entry *e);
NTSTATUS sys_lease_remove(struct sys_lease_context *ctx,
struct opendb_entry *e);

View File

@ -0,0 +1,213 @@
/*
Unix SMB/CIFS implementation.
Copyright (C) Stefan Metzmacher 2008
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
lease (oplock) implementation using fcntl F_SETLEASE on linux
*/
#include "includes.h"
#include "system/filesys.h"
#include "lib/events/events.h"
#include "ntvfs/sysdep/sys_lease.h"
#include "ntvfs/ntvfs.h"
#include "librpc/gen_ndr/ndr_opendb.h"
#include "lib/util/dlinklist.h"
#include "cluster/cluster.h"
#define LINUX_LEASE_RT_SIGNAL (SIGRTMIN+1)
struct linux_lease_pending {
struct linux_lease_pending *prev, *next;
struct sys_lease_context *ctx;
struct opendb_entry e;
};
/* the global linked list of pending leases */
static struct linux_lease_pending *leases;
static void linux_lease_signal_handler(struct event_context *ev_ctx,
struct signal_event *se,
int signum, int count,
void *_info, void *private_data)
{
struct sys_lease_context *ctx = talloc_get_type(private_data,
struct sys_lease_context);
siginfo_t *info = (siginfo_t *)_info;
struct linux_lease_pending *c;
int got_fd = info->si_fd;
for (c = leases; c; c = c->next) {
int *fd = (int *)c->e.fd;
if (got_fd == *fd) {
break;
}
}
if (!c) {
return;
}
ctx->break_send(ctx->msg_ctx, &c->e, OPLOCK_BREAK_TO_NONE);
}
static int linux_lease_pending_destructor(struct linux_lease_pending *p)
{
int ret;
int *fd = (int *)p->e.fd;
DLIST_REMOVE(leases, p);
if (*fd == -1) {
return 0;
}
ret = fcntl(*fd, F_SETLEASE, F_UNLCK);
if (ret == -1) {
DEBUG(0,("%s: failed to remove oplock: %s\n",
__FUNCTION__, strerror(errno)));
}
return 0;
}
static NTSTATUS linux_lease_init(struct sys_lease_context *ctx)
{
struct signal_event *se;
se = event_add_signal(ctx->event_ctx, ctx,
LINUX_LEASE_RT_SIGNAL, SA_SIGINFO,
linux_lease_signal_handler, ctx);
NT_STATUS_HAVE_NO_MEMORY(se);
return NT_STATUS_OK;
}
static NTSTATUS linux_lease_setup(struct sys_lease_context *ctx,
struct opendb_entry *e)
{
int ret;
int *fd = (int *)e->fd;
struct linux_lease_pending *p;
if (e->oplock_level == OPLOCK_NONE) {
e->fd = NULL;
return NT_STATUS_OK;
} else if (e->oplock_level == OPLOCK_LEVEL_II) {
/*
* the linux kernel doesn't support level2 oplocks
* so fix up the granted oplock level
*/
e->oplock_level = OPLOCK_NONE;
e->allow_level_II_oplock = false;
e->fd = NULL;
return NT_STATUS_OK;
}
p = talloc(ctx, struct linux_lease_pending);
NT_STATUS_HAVE_NO_MEMORY(p);
p->ctx = ctx;
p->e = *e;
ret = fcntl(*fd, F_SETSIG, LINUX_LEASE_RT_SIGNAL);
if (ret == -1) {
talloc_free(p);
return map_nt_error_from_unix(errno);
}
ret = fcntl(*fd, F_SETLEASE, F_WRLCK);
if (ret == -1) {
talloc_free(p);
return map_nt_error_from_unix(errno);
}
DLIST_ADD(leases, p);
talloc_set_destructor(p, linux_lease_pending_destructor);
return NT_STATUS_OK;
}
static NTSTATUS linux_lease_remove(struct sys_lease_context *ctx,
struct opendb_entry *e);
static NTSTATUS linux_lease_update(struct sys_lease_context *ctx,
struct opendb_entry *e)
{
struct linux_lease_pending *c;
for (c = leases; c; c = c->next) {
if (c->e.fd == e->fd) {
break;
}
}
if (!c) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
/*
* set the fd pointer to NULL so that the caller
* will not call the remove function as the oplock
* is already removed
*/
e->fd = NULL;
talloc_free(c);
return NT_STATUS_OK;
}
static NTSTATUS linux_lease_remove(struct sys_lease_context *ctx,
struct opendb_entry *e)
{
struct linux_lease_pending *c;
for (c = leases; c; c = c->next) {
if (c->e.fd == e->fd) {
break;
}
}
if (!c) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
talloc_free(c);
return NT_STATUS_OK;
}
static struct sys_lease_ops linux_lease_ops = {
.name = "linux",
.init = linux_lease_init,
.setup = linux_lease_setup,
.update = linux_lease_update,
.remove = linux_lease_remove
};
/*
initialialise the linux lease module
*/
NTSTATUS sys_lease_linux_init(void)
{
/* register ourselves as a system lease module */
return sys_lease_register(&linux_lease_ops);
}

View File

@ -2218,7 +2218,7 @@ bool test_nttransrename(struct torture_context *tctx, struct smbcli_state *cli1)
NTSTATUS status;
bool ret = true;
union smb_open io;
union smb_fileinfo qfi;
union smb_fileinfo qfi, qpi;
union smb_rename rn;
uint16_t fnum=0;
@ -2237,7 +2237,7 @@ bool test_nttransrename(struct torture_context *tctx, struct smbcli_state *cli1)
*/
io.generic.level = RAW_OPEN_NTCREATEX;
io.ntcreatex.in.root_fid = 0;
io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
io.ntcreatex.in.access_mask = 0;/* ask for no access at all */;
io.ntcreatex.in.alloc_size = 0;
io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
@ -2256,7 +2256,7 @@ bool test_nttransrename(struct torture_context *tctx, struct smbcli_state *cli1)
fnum = io.ntcreatex.out.file.fnum;
CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
torture_comment(tctx, "nttrans_rename should not trigger a break nor a share mode violation\n");
torture_comment(tctx, "nttrans_rename: should not trigger a break nor a share mode violation\n");
ZERO_STRUCT(rn);
rn.generic.level = RAW_RENAME_NTTRANS;
rn.nttrans.in.file.fnum = fnum;
@ -2268,25 +2268,60 @@ bool test_nttransrename(struct torture_context *tctx, struct smbcli_state *cli1)
CHECK_STATUS(tctx, status, NT_STATUS_OK);
CHECK_VAL(break_info.count, 0);
/* Seems name is only updated on close. */
smbcli_close(cli1->tree, fnum);
/* Check if we can open with the new name. */
io.ntcreatex.in.fname = fname2;
status = smb_raw_open(cli1->tree, tctx, &io);
CHECK_STATUS(tctx, status, NT_STATUS_OK);
fnum = io.ntcreatex.out.file.fnum;
CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
/* w2k3 does nothing, it doesn't rename the file */
torture_comment(tctx, "nttrans_rename: the server should have done nothing\n");
ZERO_STRUCT(qfi);
qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
qfi.generic.in.file.fnum = fnum;
status = smb_raw_fileinfo(cli1->tree, tctx, &qfi);
CHECK_STATUS(tctx, status, NT_STATUS_OK);
CHECK_STRMATCH(qfi.all_info.out.fname.s, fname2);
CHECK_STRMATCH(qfi.all_info.out.fname.s, fname1);
smbcli_close(cli1->tree, fnum);
ZERO_STRUCT(qpi);
qpi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
qpi.generic.in.file.path = fname1;
status = smb_raw_pathinfo(cli1->tree, tctx, &qpi);
CHECK_STATUS(tctx, status, NT_STATUS_OK);
CHECK_STRMATCH(qpi.all_info.out.fname.s, fname1);
ZERO_STRUCT(qpi);
qpi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
qpi.generic.in.file.path = fname2;
status = smb_raw_pathinfo(cli1->tree, tctx, &qpi);
CHECK_STATUS(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
torture_comment(tctx, "nttrans_rename: after closing the file the file is still not renamed\n");
status = smbcli_close(cli1->tree, fnum);
CHECK_STATUS(tctx, status, NT_STATUS_OK);
ZERO_STRUCT(qpi);
qpi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
qpi.generic.in.file.path = fname1;
status = smb_raw_pathinfo(cli1->tree, tctx, &qpi);
CHECK_STATUS(tctx, status, NT_STATUS_OK);
CHECK_STRMATCH(qpi.all_info.out.fname.s, fname1);
ZERO_STRUCT(qpi);
qpi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
qpi.generic.in.file.path = fname2;
status = smb_raw_pathinfo(cli1->tree, tctx, &qpi);
CHECK_STATUS(tctx, status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
torture_comment(tctx, "nttrans_rename: rename with an invalid handle gives NT_STATUS_INVALID_HANDLE\n");
ZERO_STRUCT(rn);
rn.generic.level = RAW_RENAME_NTTRANS;
rn.nttrans.in.file.fnum = fnum+1;
rn.nttrans.in.flags = 0;
rn.nttrans.in.new_name = fname2+strlen(BASEDIR)+1;
status = smb_raw_rename(cli1->tree, &rn);
CHECK_STATUS(tctx, status, NT_STATUS_INVALID_HANDLE);
done:
smb_raw_exit(cli1->session);

View File

@ -356,22 +356,24 @@ static bool test_stream_sharemodes(struct torture_context *tctx,
* A different stream does not give a sharing violation
*/
io.ntcreatex.in.fname = sname2;
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum1 = io.ntcreatex.out.file.fnum;
fnum2 = io.ntcreatex.out.file.fnum;
/*
* ... whereas the same stream does with unchanged access/share_access
* flags
*/
io.ntcreatex.in.fname = sname1;
io.ntcreatex.in.open_disposition = 0;
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
io.ntcreatex.in.fname = sname2;
status = smb_raw_open(cli->tree, mem_ctx, &io);
CHECK_STATUS(status, NT_STATUS_OK);
fnum2 = io.ntcreatex.out.file.fnum;
CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
done:
if (fnum1 != -1) smbcli_close(cli->tree, fnum1);
@ -558,7 +560,9 @@ bool torture_raw_streams(struct torture_context *torture,
}
ret &= test_stream_io(torture, cli, torture);
smb_raw_exit(cli->session);
ret &= test_stream_sharemodes(torture, cli, torture);
smb_raw_exit(cli->session);
if (!torture_setting_bool(torture, "samba4", false)) {
ret &= test_stream_delete(torture, cli, torture);
}