summaryrefslogtreecommitdiff
path: root/source4/ntvfs/posix
diff options
context:
space:
mode:
Diffstat (limited to 'source4/ntvfs/posix')
-rw-r--r--source4/ntvfs/posix/config.mk1
-rw-r--r--source4/ntvfs/posix/pvfs_lock.c64
-rw-r--r--source4/ntvfs/posix/pvfs_open.c63
-rw-r--r--source4/ntvfs/posix/pvfs_search.c93
-rw-r--r--source4/ntvfs/posix/vfs_posix.c15
-rw-r--r--source4/ntvfs/posix/vfs_posix.h28
6 files changed, 134 insertions, 130 deletions
diff --git a/source4/ntvfs/posix/config.mk b/source4/ntvfs/posix/config.mk
index b6ba073a99..732e896d2b 100644
--- a/source4/ntvfs/posix/config.mk
+++ b/source4/ntvfs/posix/config.mk
@@ -22,6 +22,7 @@ ADD_OBJ_FILES = \
ntvfs/posix/pvfs_shortname.o \
ntvfs/posix/pvfs_lock.o \
ntvfs/posix/pvfs_wait.o \
+ ntvfs/common/idtree.o \
ntvfs/common/brlock.o
# End MODULE ntvfs_posix
################################################
diff --git a/source4/ntvfs/posix/pvfs_lock.c b/source4/ntvfs/posix/pvfs_lock.c
index e32fcb2e3a..f52e68eeb1 100644
--- a/source4/ntvfs/posix/pvfs_lock.c
+++ b/source4/ntvfs/posix/pvfs_lock.c
@@ -75,6 +75,7 @@ static void pvfs_lock_async_failed(struct pvfs_state *pvfs,
f->fnum,
locks[i].offset,
locks[i].count);
+ f->lock_count--;
}
req->async.status = status;
req->async.send_fn(req);
@@ -117,6 +118,10 @@ static void pvfs_pending_lock_continue(void *private, BOOL timed_out)
locks[pending->pending_lock].count,
rw, NULL);
+ if (NT_STATUS_IS_OK(status)) {
+ f->lock_count++;
+ }
+
/* if we have failed and timed out, or succeeded, then we
don't need the pending lock any more */
if (NT_STATUS_IS_OK(status) || timed_out) {
@@ -182,6 +187,8 @@ static void pvfs_pending_lock_continue(void *private, BOOL timed_out)
pvfs_lock_async_failed(pvfs, req, f, locks, i, status);
return;
}
+
+ f->lock_count++;
}
/* we've managed to get all the locks. Tell the client */
@@ -191,26 +198,28 @@ static void pvfs_pending_lock_continue(void *private, BOOL timed_out)
/*
- called when we close a file that might have pending locks
+ called when we close a file that might have locks
*/
-void pvfs_lock_close_pending(struct pvfs_state *pvfs, struct pvfs_file *f)
+void pvfs_lock_close(struct pvfs_state *pvfs, struct pvfs_file *f)
{
struct pvfs_pending_lock *p, *next;
- NTSTATUS status;
+ if (f->lock_count || f->pending_list) {
+ DEBUG(5,("pvfs_lock: removing %.0f locks on close\n",
+ (double)f->lock_count));
+ brl_close(f->pvfs->brl_context, &f->locking_key, f->fnum);
+ f->lock_count = 0;
+ }
+
+ /* reply to all the pending lock requests, telling them the
+ lock failed */
for (p=f->pending_list;p;p=next) {
next = p->next;
DLIST_REMOVE(f->pending_list, p);
- status = brl_remove_pending(pvfs->brl_context, &f->locking_key, p);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0,("pvfs_lock_close_pending: failed to remove pending lock - %s\n",
- nt_errstr(status)));
- }
talloc_free(p->wait_handle);
p->req->async.status = NT_STATUS_RANGE_NOT_LOCKED;
p->req->async.send_fn(p->req);
}
-
}
@@ -262,6 +271,7 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs,
int i;
enum brl_type rw;
struct pvfs_pending_lock *pending = NULL;
+ NTSTATUS status;
f = pvfs_find_fd(pvfs, req, lck->generic.in.fnum);
if (!f) {
@@ -270,21 +280,29 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs,
switch (lck->generic.level) {
case RAW_LOCK_LOCK:
- return brl_lock(pvfs->brl_context,
- &f->locking_key,
- req->smbpid,
- f->fnum,
- lck->lock.in.offset,
- lck->lock.in.count,
- WRITE_LOCK, NULL);
-
- case RAW_LOCK_UNLOCK:
- return brl_unlock(pvfs->brl_context,
+ status = brl_lock(pvfs->brl_context,
&f->locking_key,
req->smbpid,
f->fnum,
lck->lock.in.offset,
- lck->lock.in.count);
+ lck->lock.in.count,
+ WRITE_LOCK, NULL);
+ if (NT_STATUS_IS_OK(status)) {
+ f->lock_count++;
+ }
+ return status;
+
+ case RAW_LOCK_UNLOCK:
+ status = brl_unlock(pvfs->brl_context,
+ &f->locking_key,
+ req->smbpid,
+ f->fnum,
+ lck->lock.in.offset,
+ lck->lock.in.count);
+ if (NT_STATUS_IS_OK(status)) {
+ f->lock_count--;
+ }
+ return status;
case RAW_LOCK_GENERIC:
return NT_STATUS_INVALID_LEVEL;
@@ -337,7 +355,6 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs,
locks = lck->lockx.in.locks;
for (i=0;i<lck->lockx.in.ulock_cnt;i++) {
- NTSTATUS status;
status = brl_unlock(pvfs->brl_context,
&f->locking_key,
locks[i].pid,
@@ -347,13 +364,12 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs,
if (!NT_STATUS_IS_OK(status)) {
return status;
}
+ f->lock_count--;
}
locks += i;
for (i=0;i<lck->lockx.in.lock_cnt;i++) {
- NTSTATUS status;
-
if (pending) {
pending->pending_lock = i;
}
@@ -387,9 +403,11 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs,
f->fnum,
locks[i].offset,
locks[i].count);
+ f->lock_count--;
}
return status;
}
+ f->lock_count++;
}
return NT_STATUS_OK;
diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c
index 429f519bca..c255558369 100644
--- a/source4/ntvfs/posix/pvfs_open.c
+++ b/source4/ntvfs/posix/pvfs_open.c
@@ -31,16 +31,19 @@ struct pvfs_file *pvfs_find_fd(struct pvfs_state *pvfs,
struct smbsrv_request *req, uint16_t fnum)
{
struct pvfs_file *f;
- for (f=pvfs->open_files;f;f=f->next) {
- if (f->fnum == fnum) {
- if (req->session != f->session) {
- DEBUG(2,("pvfs_find_fd: attempt to use wrong session for fnum %d\n", fnum));
- return NULL;
- }
- return f;
- }
+
+ f = idr_find(pvfs->idtree_fnum, fnum);
+ if (f == NULL) {
+ return NULL;
}
- return NULL;
+
+ if (req->session != f->session) {
+ DEBUG(2,("pvfs_find_fd: attempt to use wrong session for fnum %d\n",
+ fnum));
+ return NULL;
+ }
+
+ return f;
}
/*
@@ -52,14 +55,15 @@ static int pvfs_fd_destructor(void *p)
{
struct pvfs_file *f = p;
- pvfs_lock_close_pending(f->pvfs, f);
-
- brl_close(f->pvfs->brl_context, &f->locking_key, f->fnum);
+ pvfs_lock_close(f->pvfs, f);
if (f->fd != -1) {
close(f->fd);
f->fd = -1;
}
+
+ idr_remove(f->pvfs->idtree_fnum, f->fnum);
+
return 0;
}
@@ -80,6 +84,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
dev_t device;
ino_t inode;
} lock_context;
+ int fnum;
if (io->generic.level != RAW_OPEN_GENERIC) {
return ntvfs_map_open(req, io, ntvfs);
@@ -147,6 +152,17 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
}
}
+ f = talloc_p(pvfs, struct pvfs_file);
+ if (f == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ fnum = idr_get_new(pvfs->idtree_fnum, f, 0x10000);
+ if (fnum == -1) {
+ talloc_free(f);
+ return NT_STATUS_TOO_MANY_OPENED_FILES;
+ }
+
do_open:
fd = open(name->full_name, flags, 0644);
if (fd == -1) {
@@ -155,25 +171,20 @@ do_open:
return pvfs_map_errno(pvfs,errno);
}
- f = talloc_p(pvfs, struct pvfs_file);
- if (f == NULL) {
- close(fd);
- return NT_STATUS_NO_MEMORY;
- }
-
/* re-resolve the open fd */
status = pvfs_resolve_name_fd(pvfs, fd, name);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- f->fnum = fd;
+ f->fnum = fnum;
f->fd = fd;
f->name = talloc_steal(f, name);
f->session = req->session;
f->smbpid = req->smbpid;
f->pvfs = pvfs;
f->pending_list = NULL;
+ f->lock_count = 0;
/* we must zero here to take account of padding */
ZERO_STRUCT(lock_context);
@@ -223,22 +234,16 @@ NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
return NT_STATUS_INVALID_HANDLE;
}
- pvfs_lock_close_pending(pvfs, f);
-
- status = brl_close(pvfs->brl_context, &f->locking_key, f->fnum);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
if (close(f->fd) != 0) {
status = pvfs_map_errno(pvfs, errno);
} else {
status = NT_STATUS_OK;
}
-
- talloc_set_destructor(f, NULL);
+ f->fd = -1;
DLIST_REMOVE(pvfs->open_files, f);
+
+ /* the destructor takes care of the rest */
talloc_free(f);
return status;
@@ -257,7 +262,6 @@ NTSTATUS pvfs_logoff(struct ntvfs_module_context *ntvfs,
for (f=pvfs->open_files;f;f=next) {
next = f->next;
if (f->session == req->session) {
- talloc_set_destructor(f, NULL);
DLIST_REMOVE(pvfs->open_files, f);
talloc_free(f);
}
@@ -279,7 +283,6 @@ NTSTATUS pvfs_exit(struct ntvfs_module_context *ntvfs,
for (f=pvfs->open_files;f;f=next) {
next = f->next;
if (f->smbpid == req->smbpid) {
- talloc_set_destructor(f, NULL);
DLIST_REMOVE(pvfs->open_files, f);
talloc_free(f);
}
diff --git a/source4/ntvfs/posix/pvfs_search.c b/source4/ntvfs/posix/pvfs_search.c
index 07f2a0f127..7b0da321d3 100644
--- a/source4/ntvfs/posix/pvfs_search.c
+++ b/source4/ntvfs/posix/pvfs_search.c
@@ -23,6 +23,17 @@
#include "include/includes.h"
#include "vfs_posix.h"
+
+/*
+ destroy an open search
+*/
+static int pvfs_search_destructor(void *ptr)
+{
+ struct pvfs_search_state *search = ptr;
+ idr_remove(search->pvfs->idtree_search, search->handle);
+ return 0;
+}
+
/*
fill in a single search result for a given info level
*/
@@ -224,32 +235,6 @@ static NTSTATUS pvfs_search_fill(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
return NT_STATUS_OK;
}
-/*
- return the next available search handle
-*/
-static NTSTATUS pvfs_next_search_handle(struct pvfs_state *pvfs, uint16_t *handle,
- uint_t max_handles)
-{
- struct pvfs_search_state *search;
-
- if (pvfs->search.num_active_searches >= max_handles) {
- return NT_STATUS_INSUFFICIENT_RESOURCES;
- }
-
- (*handle) = (pvfs->search.next_search_handle) & (max_handles-1);
-again:
- for (search=pvfs->search.open_searches;search;search=search->next) {
- if (*handle == search->handle) {
- *handle = ((*handle)+1) & (max_handles-1);
- goto again;
- }
- }
- pvfs->search.next_search_handle = ((*handle)+1) & (max_handles-1);
-
- return NT_STATUS_OK;
-}
-
-
/*
list files in a directory matching a wildcard pattern - old SMBsearch interface
*/
@@ -266,6 +251,7 @@ static NTSTATUS pvfs_search_first_old(struct ntvfs_module_context *ntvfs,
const char *pattern;
NTSTATUS status;
struct pvfs_filename *name;
+ int id;
search_attrib = io->search_first.in.search_attrib;
pattern = io->search_first.in.pattern;
@@ -301,15 +287,19 @@ static NTSTATUS pvfs_search_first_old(struct ntvfs_module_context *ntvfs,
/* we need to give a handle back to the client so it
can continue a search */
- status = pvfs_next_search_handle(pvfs, &search->handle, 0x100);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
+ id = idr_get_new(pvfs->idtree_search, search, 0x100);
+ if (id == -1) {
+ return NT_STATUS_INSUFFICIENT_RESOURCES;
}
-
+
+ search->pvfs = pvfs;
+ search->handle = id;
search->dir = dir;
search->current_index = 0;
search->search_attrib = search_attrib;
+ talloc_set_destructor(search, pvfs_search_destructor);
+
status = pvfs_search_fill(pvfs, req, io->search_first.in.max_count, search, io->generic.level,
&reply_count, search_private, callback);
if (!NT_STATUS_IS_OK(status)) {
@@ -323,9 +313,7 @@ static NTSTATUS pvfs_search_first_old(struct ntvfs_module_context *ntvfs,
return STATUS_NO_MORE_FILES;
}
- pvfs->search.num_active_searches++;
talloc_steal(pvfs, search);
- DLIST_ADD(pvfs->search.open_searches, search);
return NT_STATUS_OK;
}
@@ -346,11 +334,8 @@ static NTSTATUS pvfs_search_next_old(struct ntvfs_module_context *ntvfs,
handle = io->search_next.in.id.handle;
max_count = io->search_next.in.max_count;
- for (search=pvfs->search.open_searches; search; search = search->next) {
- if (search->handle == handle) break;
- }
-
- if (!search) {
+ search = idr_find(pvfs->idtree_search, handle);
+ if (search == NULL) {
/* we didn't find the search handle */
return NT_STATUS_INVALID_HANDLE;
}
@@ -369,7 +354,6 @@ static NTSTATUS pvfs_search_next_old(struct ntvfs_module_context *ntvfs,
/* not matching any entries means end of search */
if (reply_count == 0) {
- DLIST_REMOVE(pvfs->search.open_searches, search);
talloc_free(search);
}
@@ -392,6 +376,7 @@ NTSTATUS pvfs_search_first(struct ntvfs_module_context *ntvfs,
const char *pattern;
NTSTATUS status;
struct pvfs_filename *name;
+ int id;
if (io->generic.level >= RAW_SEARCH_SEARCH) {
return pvfs_search_first_old(ntvfs, req, io, search_private, callback);
@@ -430,17 +415,19 @@ NTSTATUS pvfs_search_first(struct ntvfs_module_context *ntvfs,
return status;
}
- /* we need to give a handle back to the client so it
- can continue a search */
- status = pvfs_next_search_handle(pvfs, &search->handle, 0x10000);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
+ id = idr_get_new(pvfs->idtree_search, search, 0x10000);
+ if (id == -1) {
+ return NT_STATUS_INSUFFICIENT_RESOURCES;
}
-
+
+ search->pvfs = pvfs;
+ search->handle = id;
search->dir = dir;
search->current_index = 0;
search->search_attrib = search_attrib;
+ talloc_set_destructor(search, pvfs_search_destructor);
+
status = pvfs_search_fill(pvfs, req, max_count, search, io->generic.level,
&reply_count, search_private, callback);
if (!NT_STATUS_IS_OK(status)) {
@@ -463,9 +450,7 @@ NTSTATUS pvfs_search_first(struct ntvfs_module_context *ntvfs,
io->t2ffirst.out.end_of_search)) {
talloc_free(search);
} else {
- pvfs->search.num_active_searches++;
talloc_steal(pvfs, search);
- DLIST_ADD(pvfs->search.open_searches, search);
}
return NT_STATUS_OK;
@@ -491,11 +476,8 @@ NTSTATUS pvfs_search_next(struct ntvfs_module_context *ntvfs,
handle = io->t2fnext.in.handle;
- for (search=pvfs->search.open_searches; search; search = search->next) {
- if (search->handle == handle) break;
- }
-
- if (!search) {
+ search = idr_find(pvfs->idtree_search, handle);
+ if (search == NULL) {
/* we didn't find the search handle */
return NT_STATUS_INVALID_HANDLE;
}
@@ -544,7 +526,6 @@ found:
if ((io->t2fnext.in.flags & FLAG_TRANS2_FIND_CLOSE) ||
((io->t2fnext.in.flags & FLAG_TRANS2_FIND_CLOSE_IF_END) &&
io->t2fnext.out.end_of_search)) {
- DLIST_REMOVE(pvfs->search.open_searches, search);
talloc_free(search);
}
@@ -565,16 +546,12 @@ NTSTATUS pvfs_search_close(struct ntvfs_module_context *ntvfs,
handle = io->findclose.in.handle;
}
- for (search=pvfs->search.open_searches; search; search = search->next) {
- if (search->handle == handle) break;
- }
-
- if (!search) {
+ search = idr_find(pvfs->idtree_search, handle);
+ if (search == NULL) {
/* we didn't find the search handle */
return NT_STATUS_INVALID_HANDLE;
}
- DLIST_REMOVE(pvfs->search.open_searches, search);
talloc_free(search);
return NT_STATUS_OK;
diff --git a/source4/ntvfs/posix/vfs_posix.c b/source4/ntvfs/posix/vfs_posix.c
index e989f8de67..8aa028919c 100644
--- a/source4/ntvfs/posix/vfs_posix.c
+++ b/source4/ntvfs/posix/vfs_posix.c
@@ -61,11 +61,10 @@ static NTSTATUS pvfs_connect(struct ntvfs_module_context *ntvfs,
char *base_directory;
NTSTATUS status;
- pvfs = talloc_p(tcon, struct pvfs_state);
+ pvfs = talloc_zero_p(tcon, struct pvfs_state);
if (pvfs == NULL) {
return NT_STATUS_NO_MEMORY;
}
- ZERO_STRUCTP(pvfs);
/* for simplicity of path construction, remove any trailing slash now */
base_directory = talloc_strdup(pvfs, lp_pathname(tcon->service));
@@ -95,6 +94,18 @@ static NTSTATUS pvfs_connect(struct ntvfs_module_context *ntvfs,
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
+ /* allocate the fnum id -> ptr tree */
+ pvfs->idtree_fnum = idr_init(pvfs);
+ if (pvfs->idtree_fnum == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* allocate the search handle -> ptr tree */
+ pvfs->idtree_search = idr_init(pvfs);
+ if (pvfs->idtree_search == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
status = pvfs_mangle_init(pvfs);
if (!NT_STATUS_IS_OK(status)) {
return status;
diff --git a/source4/ntvfs/posix/vfs_posix.h b/source4/ntvfs/posix/vfs_posix.h
index 6aaa43a213..ae601c60c7 100644
--- a/source4/ntvfs/posix/vfs_posix.h
+++ b/source4/ntvfs/posix/vfs_posix.h
@@ -32,27 +32,17 @@ struct pvfs_state {
const char *share_name;
uint_t flags;
- struct {
- /* a linked list of open searches */
- struct pvfs_search_state *open_searches;
-
- /* search handles are returned to the clients so they
- can continue searches */
- uint16_t next_search_handle;
-
- /* count of active searches */
- uint_t num_active_searches;
-
- /* during trans2 search continuations we need to use
- the initial search attributes */
- uint16_t search_attrib;
- } search;
-
struct pvfs_file *open_files;
struct pvfs_mangle_context *mangle_ctx;
void *brl_context;
+
+ /* an id tree mapping open search ID to a pvfs_search_state structure */
+ void *idtree_search;
+
+ /* an id tree mapping open file handle -> struct pvfs_file */
+ void *idtree_fnum;
};
@@ -95,7 +85,7 @@ struct pvfs_dir {
/* the state of a search started with pvfs_search_first() */
struct pvfs_search_state {
- struct pvfs_search_state *next, *prev;
+ struct pvfs_state *pvfs;
uint16_t handle;
uint_t current_index;
uint16_t search_attrib;
@@ -126,6 +116,10 @@ struct pvfs_file {
/* a list of pending locks - used for locking cancel operations */
struct pvfs_pending_lock *pending_list;
+
+ /* a count of active locks - used to avoid calling brl_close on
+ file close */
+ uint64_t lock_count;
};