Chapter 3. Oplocks

3.1. What are oplocks?

When a client opens a file it can request an "oplock" or file lease. This is (to simplify a bit) a guarentee that no one else has the file open simultaneously. It allows the client to not send any updates on the file to the server, thus reducing a network file access to local access (once the file is in client cache). An "oplock break" is when the server sends a request to the client to flush all its changes back to the server, so the file is in a consistent state for other opens to succeed. If a client fails to respond to this asynchronous request then the file can be corrupted. Hence the "turn off oplocks" answer if people are having multi-user file access problems.

Unless the kernel is "oplock aware" (SGI IRIX and Linux are the only two UNIXes that are at the moment) then if a local UNIX process accesses the file simultaneously then Samba has no way of telling this is occuring, so the guarentee to the client is broken. This can corrupt the file. Short answer - it you have UNIX clients accessing the same file as smbd locally or via NFS and you're not running Linux or IRIX then turn off oplocks for that file or share.

"Share modes". These are modes of opening a file, that guarentee an invarient - such as DENY_WRITE - which means that if any other opens are requested with write access after this current open has succeeded then they should be denied with a "sharing violation" error message. Samba handles these internally inside smbd. UNIX clients accessing the same file ignore these invarients. Just proving that if you need simultaneous file access from a Windows and UNIX client you *must* have an application that is written to lock records correctly on both sides. Few applications are written like this, and even fewer are cross platform (UNIX and Windows) so in practice this isn't much of a problem.

"Locking". This really means "byte range locking" - such as lock 10 bytes at file offset 24 for write access. This is the area in which well written UNIX and Windows apps will cooperate. Windows locks (at least from NT or above) are 64-bit unsigned offsets. UNIX locks are either 31 bit or 63 bit and are signed (the top bit is used for the sign). Samba handles these by first ensuring that all the Windows locks don't conflict (ie. if other Windows clients have competing locks then just reject immediately) - this allows us to support 64-bit Windows locks on 32-bit filesystems. Secondly any locks that are valid are then mapped onto UNIX fcntl byte range locks. These are the locks that will be seen by UNIX processes. If there is a conflict here the lock is rejected.

Note that if a client has an oplock then it "knows" that no other client can have the file open so usually doesn't bother to send to lock request to the server - this means once again if you need to share files between UNIX and Windows processes either use IRIX or Linux, or turn off oplocks for these files/shares.

46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
/* 
   Unix SMB/CIFS implementation.

   Samba internal rpc code - header

   Copyright (C) Andrew Tridgell 2005
   
   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/>.
*/

#ifndef IRPC_H
#define IRPC_H

#include "librpc/gen_ndr/irpc.h"

/*
  an incoming irpc message
*/
struct irpc_message {
	struct server_id from;
	void *private;
	struct irpc_header header;
	struct ndr_pull *ndr;
	bool defer_reply;
	struct messaging_context *msg_ctx;
	struct irpc_list *irpc;
	void *data;
	struct event_context *ev;
};

/* don't allow calls to take too long */
#define IRPC_CALL_TIMEOUT 10


/* the server function type */
typedef NTSTATUS (*irpc_function_t)(struct irpc_message *, void *r);

/* register a server function with the irpc messaging system */
#define IRPC_REGISTER(msg_ctx, pipename, funcname, function, private) \
   irpc_register(msg_ctx, &ndr_table_ ## pipename, \
                          NDR_ ## funcname, \
			  (irpc_function_t)function, private)

/* make a irpc call */
#define IRPC_CALL(msg_ctx, server_id, pipename, funcname, ptr, ctx) \
   irpc_call(msg_ctx, server_id, &ndr_table_ ## pipename, NDR_ ## funcname, ptr, ctx)

#define IRPC_CALL_SEND(msg_ctx, server_id, pipename, funcname, ptr, ctx) \
   irpc_call_send(msg_ctx, server_id, &ndr_table_ ## pipename, NDR_ ## funcname, ptr, ctx)


/*
  a pending irpc call
*/
struct irpc_request {
	struct messaging_context *msg_ctx;
	const struct ndr_interface_table *table;
	int callnum;
	int callid;
	void *r;
	NTSTATUS status;
	bool done;
	bool reject_free;
	TALLOC_CTX *mem_ctx;
	struct {
		void (*fn)(struct irpc_request *);
		void *private;
	} async;
};

struct loadparm_context;

typedef void (*msg_callback_t)(struct messaging_context *msg, void *private, 
			       uint32_t msg_type, 
			       struct server_id server_id, DATA_BLOB *data);

NTSTATUS messaging_send(struct messaging_context *msg, struct server_id server, 
			uint32_t msg_type, DATA_BLOB *data);
NTSTATUS messaging_register(struct messaging_context *msg, void *private,
			    uint32_t msg_type, 
			    msg_callback_t fn);
NTSTATUS messaging_register_tmp(struct messaging_context *msg, void *private,
				msg_callback_t fn, uint32_t *msg_type);
struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx, 
					 const char *dir,
					 struct server_id server_id, 
					 struct smb_iconv_convenience *iconv_convenience,
					 struct event_context *ev);
struct messaging_context *messaging_client_init(TALLOC_CTX *mem_ctx, 
					 const char *dir,
					 struct smb_iconv_convenience *iconv_convenience,
					 struct event_context *ev);
NTSTATUS messaging_send_ptr(struct messaging_context *msg, struct server_id server, 
			    uint32_t msg_type, void *ptr);
void messaging_deregister(struct messaging_context *msg, uint32_t msg_type, void *private);




NTSTATUS irpc_register(struct messaging_context *msg_ctx, 
		       const struct ndr_interface_table *table, 
		       int call, irpc_function_t fn, void *private);
struct irpc_request *irpc_call_send(struct messaging_context *msg_ctx, 
				    struct server_id server_id, 
				    const struct ndr_interface_table *table, 
				    int callnum, void *r, TALLOC_CTX *ctx);