summaryrefslogtreecommitdiffstats
path: root/fs/ncpfs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-07-08 00:53:00 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-07-08 00:53:00 +0000
commitb8553086288629b4efb77e97f5582e08bc50ad65 (patch)
tree0a19bd1c21e148f35c7a0f76baa4f7a056b966b0 /fs/ncpfs
parent75b6d92f2dd5112b02f4e78cf9f35f9825946ef0 (diff)
Merge with 2.4.0-test3-pre4.
Diffstat (limited to 'fs/ncpfs')
-rw-r--r--fs/ncpfs/dir.c43
-rw-r--r--fs/ncpfs/file.c9
-rw-r--r--fs/ncpfs/inode.c29
-rw-r--r--fs/ncpfs/ncplib_kernel.c8
-rw-r--r--fs/ncpfs/ncplib_kernel.h10
-rw-r--r--fs/ncpfs/sock.c253
6 files changed, 279 insertions, 73 deletions
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 11694e79b..3ea18c96d 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -21,6 +21,7 @@
#include <asm/uaccess.h>
#include <asm/byteorder.h>
#include <linux/locks.h>
+#include <linux/smp_lock.h>
#include <linux/ncp_fs.h>
@@ -253,7 +254,7 @@ leave_me:;
static int
-ncp_lookup_validate(struct dentry * dentry, int flags)
+__ncp_lookup_validate(struct dentry * dentry, int flags)
{
struct ncp_server *server;
struct inode *dir = dentry->d_parent->d_inode;
@@ -315,6 +316,16 @@ finished:
return val;
}
+static int
+ncp_lookup_validate(struct dentry * dentry, int flags)
+{
+ int res;
+ lock_kernel();
+ res = __ncp_lookup_validate(dentry, flags);
+ unlock_kernel();
+ return res;
+}
+
/* most parts from nfsd_d_validate() */
static int
ncp_d_validate(struct dentry *dentry)
@@ -361,26 +372,38 @@ ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
struct dentry *dent = dentry;
struct list_head *next;
- if (ncp_d_validate(dent))
- if ((dent->d_parent == parent) &&
- ((unsigned long)dent->d_fsdata == fpos))
- goto out;
+ if (ncp_d_validate(dent)) {
+ if (dent->d_parent == parent &&
+ (unsigned long)dent->d_fsdata == fpos) {
+ if (!dent->d_inode) {
+ dput(dent);
+ dent = NULL;
+ }
+ return dent;
+ }
+ dput(dent);
+ }
/* If a pointer is invalid, we search the dentry. */
+ spin_lock(&dcache_lock);
next = parent->d_subdirs.next;
while (next != &parent->d_subdirs) {
dent = list_entry(next, struct dentry, d_child);
- if ((unsigned long)dent->d_fsdata == fpos)
+ if ((unsigned long)dent->d_fsdata == fpos) {
+ if (dent->d_inode)
+ dget(dent);
+ else
+ dent = NULL;
+ spin_unlock(&dcache_lock);
goto out;
+ }
next = next->next;
}
+ spin_unlock(&dcache_lock);
return NULL;
out:
- if (dent->d_inode)
- return dget(dent);
-
- return NULL;
+ return dent;
}
static time_t ncp_obtain_mtime(struct dentry *dentry)
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index 3442c3f9f..a5c68e18c 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -17,6 +17,7 @@
#include <linux/mm.h>
#include <linux/locks.h>
#include <linux/malloc.h>
+#include <linux/vmalloc.h>
#include <linux/ncp_fs.h>
#include "ncplib_kernel.h"
@@ -154,7 +155,7 @@ ncp_file_read(struct file *file, char *buf, size_t count, loff_t *ppos)
error = -EIO;
freelen = ncp_read_bounce_size(bufsize);
- freepage = kmalloc(freelen, GFP_NFS);
+ freepage = vmalloc(freelen);
if (!freepage)
goto outrel;
error = 0;
@@ -180,7 +181,7 @@ ncp_file_read(struct file *file, char *buf, size_t count, loff_t *ppos)
break;
}
}
- kfree(freepage);
+ vfree(freepage);
*ppos = pos;
@@ -239,7 +240,7 @@ ncp_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
already_written = 0;
- bouncebuffer = kmalloc(bufsize, GFP_NFS);
+ bouncebuffer = vmalloc(bufsize);
if (!bouncebuffer) {
errno = -EIO; /* -ENOMEM */
goto outrel;
@@ -267,7 +268,7 @@ ncp_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
break;
}
}
- kfree(bouncebuffer);
+ vfree(bouncebuffer);
inode->i_mtime = inode->i_atime = CURRENT_TIME;
*ppos = pos;
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index b6104831e..ff0c1fd03 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -25,6 +25,7 @@
#include <linux/file.h>
#include <linux/fcntl.h>
#include <linux/malloc.h>
+#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/ncp_fs.h>
@@ -261,7 +262,10 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
struct ncp_server *server;
struct file *ncp_filp;
struct inode *root_inode;
+ struct inode *sock_inode;
+ struct socket *sock;
int error;
+ int default_bufsize;
#ifdef CONFIG_NCPFS_PACKET_SIGNING
int options;
#endif
@@ -313,8 +317,17 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
ncp_filp = fget(data.ncp_fd);
if (!ncp_filp)
goto out_bad_file;
- if (!S_ISSOCK(ncp_filp->f_dentry->d_inode->i_mode))
+ sock_inode = ncp_filp->f_dentry->d_inode;
+ if (!S_ISSOCK(sock_inode->i_mode))
goto out_bad_file2;
+ sock = &sock_inode->u.socket_i;
+ if (!sock)
+ goto out_bad_file2;
+
+ if (sock->type == SOCK_STREAM)
+ default_bufsize = 61440;
+ else
+ default_bufsize = 1024;
sb->s_blocksize = 1024; /* Eh... Is this correct? */
sb->s_blocksize_bits = 10;
@@ -364,8 +377,10 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
server->dentry_ttl = 0; /* no caching */
+#undef NCP_PACKET_SIZE
+#define NCP_PACKET_SIZE 65536
server->packet_size = NCP_PACKET_SIZE;
- server->packet = ncp_kmalloc(NCP_PACKET_SIZE, GFP_KERNEL);
+ server->packet = vmalloc(NCP_PACKET_SIZE);
if (server->packet == NULL)
goto out_no_packet;
@@ -377,13 +392,13 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
DPRINTK("ncp_read_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
#ifdef CONFIG_NCPFS_PACKET_SIGNING
- if (ncp_negotiate_size_and_options(server, NCP_DEFAULT_BUFSIZE,
+ if (ncp_negotiate_size_and_options(server, default_bufsize,
NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
{
if (options != NCP_DEFAULT_OPTIONS)
{
if (ncp_negotiate_size_and_options(server,
- NCP_DEFAULT_BUFSIZE,
+ default_bufsize,
options & 2,
&(server->buffer_size), &options) != 0)
@@ -396,7 +411,7 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
}
else
#endif /* CONFIG_NCPFS_PACKET_SIGNING */
- if (ncp_negotiate_buffersize(server, NCP_DEFAULT_BUFSIZE,
+ if (ncp_negotiate_buffersize(server, default_bufsize,
&(server->buffer_size)) != 0)
goto out_no_bufsize;
DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
@@ -447,7 +462,7 @@ out_disconnect:
out_no_connect:
printk(KERN_ERR "ncp_read_super: Failed connection, error=%d\n", error);
out_free_packet:
- ncp_kfree_s(server->packet, server->packet_size);
+ vfree(server->packet);
goto out_free_server;
out_no_packet:
printk(KERN_ERR "ncp_read_super: could not alloc packet\n");
@@ -508,7 +523,7 @@ static void ncp_put_super(struct super_block *sb)
ncp_kfree_s(server->priv.data, server->priv.len);
if (server->auth.object_name)
ncp_kfree_s(server->auth.object_name, server->auth.object_name_len);
- ncp_kfree_s(server->packet, server->packet_size);
+ vfree(server->packet);
}
diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c
index 0353882b9..29e92ea12 100644
--- a/fs/ncpfs/ncplib_kernel.c
+++ b/fs/ncpfs/ncplib_kernel.c
@@ -86,11 +86,11 @@ static inline void ncp_init_request(struct ncp_server *server)
server->has_subfunction = 0;
}
-static void ncp_init_request_s(struct ncp_server *server, int subfunction)
+static inline void ncp_init_request_s(struct ncp_server *server, int subfunction)
{
- ncp_init_request(server);
- ncp_add_word(server, 0); /* preliminary size */
-
+ ncp_lock_server(server);
+
+ server->current_size = sizeof(struct ncp_request_header) + 2;
ncp_add_byte(server, subfunction);
server->has_subfunction = 1;
diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h
index 31797a3c3..6d07ead73 100644
--- a/fs/ncpfs/ncplib_kernel.h
+++ b/fs/ncpfs/ncplib_kernel.h
@@ -157,9 +157,11 @@ static inline void
ncp_renew_dentries(struct dentry *parent)
{
struct ncp_server *server = NCP_SERVER(parent->d_inode);
- struct list_head *next = parent->d_subdirs.next;
+ struct list_head *next;
struct dentry *dentry;
+ spin_lock(&dcache_lock);
+ next = parent->d_subdirs.next;
while (next != &parent->d_subdirs) {
dentry = list_entry(next, struct dentry, d_child);
@@ -170,21 +172,25 @@ ncp_renew_dentries(struct dentry *parent)
next = next->next;
}
+ spin_unlock(&dcache_lock);
}
static inline void
ncp_invalidate_dircache_entries(struct dentry *parent)
{
struct ncp_server *server = NCP_SERVER(parent->d_inode);
- struct list_head *next = parent->d_subdirs.next;
+ struct list_head *next;
struct dentry *dentry;
+ spin_lock(&dcache_lock);
+ next = parent->d_subdirs.next;
while (next != &parent->d_subdirs) {
dentry = list_entry(next, struct dentry, d_child);
dentry->d_fsdata = NULL;
ncp_age_dentry(server, dentry);
next = next->next;
}
+ spin_unlock(&dcache_lock);
}
struct ncp_cache_head {
diff --git a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c
index 3f36db262..c5923a78e 100644
--- a/fs/ncpfs/sock.c
+++ b/fs/ncpfs/sock.c
@@ -79,15 +79,11 @@ static int _send(struct socket *sock, const void *buff, int len)
return err;
}
-#define NCP_SLACK_SPACE 1024
-
static int do_ncp_rpc_call(struct ncp_server *server, int size,
struct ncp_reply_header* reply_buf, int max_reply_size)
{
struct file *file;
- struct inode *inode;
struct socket *sock;
- mm_segment_t fs;
int result;
char *start = server->packet;
poll_table wait_table;
@@ -98,8 +94,6 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size,
int major_timeout_seen;
int acknowledge_seen;
int n;
- sigset_t old_set;
- unsigned long mask, flags;
/* We have to check the result, so store the complete header */
struct ncp_request_header request =
@@ -108,13 +102,7 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size,
struct ncp_reply_header reply;
file = server->ncp_filp;
- inode = file->f_dentry->d_inode;
- sock = &inode->u.socket_i;
- /* N.B. this isn't needed ... check socket type? */
- if (!sock) {
- printk(KERN_ERR "ncp_rpc_call: socki_lookup failed\n");
- return -EBADF;
- }
+ sock = &file->f_dentry->d_inode->u.socket_i;
init_timeout = server->m.time_out;
max_timeout = NCP_MAX_RPC_TIMEOUT;
@@ -122,26 +110,6 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size,
major_timeout_seen = 0;
acknowledge_seen = 0;
- spin_lock_irqsave(&current->sigmask_lock, flags);
- old_set = current->blocked;
- mask = sigmask(SIGKILL) | sigmask(SIGSTOP);
- if (server->m.flags & NCP_MOUNT_INTR) {
- /* FIXME: This doesn't seem right at all. So, like,
- we can't handle SIGINT and get whatever to stop?
- What if we've blocked it ourselves? What about
- alarms? Why, in fact, are we mucking with the
- sigmask at all? -- r~ */
- if (current->sig->action[SIGINT - 1].sa.sa_handler == SIG_DFL)
- mask |= sigmask(SIGINT);
- if (current->sig->action[SIGQUIT - 1].sa.sa_handler == SIG_DFL)
- mask |= sigmask(SIGQUIT);
- }
- siginitsetinv(&current->blocked, mask);
- recalc_sigpending(current);
- spin_unlock_irqrestore(&current->sigmask_lock, flags);
-
- fs = get_fs();
- set_fs(get_ds());
for (n = 0, timeout = init_timeout;; n++, timeout <<= 1) {
/*
DDPRINTK("ncpfs: %08lX:%02X%02X%02X%02X%02X%02X:%04X\n",
@@ -289,15 +257,169 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size,
result = -EIO;
}
- spin_lock_irqsave(&current->sigmask_lock, flags);
- current->blocked = old_set;
- recalc_sigpending(current);
- spin_unlock_irqrestore(&current->sigmask_lock, flags);
-
- set_fs(fs);
return result;
}
+static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len) {
+ poll_table wait_table;
+ struct poll_table_entry entry;
+ struct file *file;
+ struct socket *sock;
+ int init_timeout;
+ size_t dataread;
+ int result = 0;
+
+ file = server->ncp_filp;
+ sock = &file->f_dentry->d_inode->u.socket_i;
+
+ dataread = 0;
+
+ init_timeout = server->m.time_out * 20;
+
+ /* hard-mounted volumes have no timeout, except connection close... */
+ if (!(server->m.flags & NCP_MOUNT_SOFT))
+ init_timeout = 0x7FFF0000;
+
+ while (len) {
+ wait_table.nr = 0;
+ wait_table.entry = &entry;
+ /* mb() is not necessary because ->poll() will serialize
+ instructions adding the wait_table waitqueues in the
+ waitqueue-head before going to calculate the mask-retval. */
+ __set_current_state(TASK_INTERRUPTIBLE);
+ if (!(sock->ops->poll(file, sock, &wait_table) & POLLIN)) {
+ init_timeout = schedule_timeout(init_timeout);
+ remove_wait_queue(entry.wait_address, &entry.wait);
+ fput(file);
+ current->state = TASK_RUNNING;
+ if (signal_pending(current)) {
+ return -ERESTARTSYS;
+ }
+ if (!init_timeout) {
+ return -EIO;
+ }
+ } else if (wait_table.nr) {
+ remove_wait_queue(entry.wait_address, &entry.wait);
+ fput(file);
+ }
+ current->state = TASK_RUNNING;
+
+ result = _recv(sock, buffer, len, MSG_DONTWAIT);
+ if (result < 0) {
+ if (result == -EAGAIN) {
+ DDPRINTK("ncpfs: tcp: bad select ready\n");
+ continue;
+ }
+ return result;
+ }
+ if (result == 0) {
+ printk(KERN_ERR "ncpfs: tcp: EOF on socket\n");
+ return -EIO;
+ }
+ if (result > len) {
+ printk(KERN_ERR "ncpfs: tcp: bug in recvmsg\n");
+ return -EIO;
+ }
+ dataread += result;
+ buffer += result;
+ len -= result;
+ }
+ return 0;
+}
+
+#define NCP_TCP_XMIT_MAGIC (0x446D6454)
+#define NCP_TCP_XMIT_VERSION (1)
+#define NCP_TCP_RCVD_MAGIC (0x744E6350)
+
+static int do_ncp_tcp_rpc_call(struct ncp_server *server, int size,
+ struct ncp_reply_header* reply_buf, int max_reply_size)
+{
+ struct file *file;
+ struct socket *sock;
+ int result;
+ struct iovec iov[2];
+ struct msghdr msg;
+ struct scm_cookie scm;
+ __u32 ncptcp_rcvd_hdr[2];
+ __u32 ncptcp_xmit_hdr[4];
+ int datalen;
+
+ /* We have to check the result, so store the complete header */
+ struct ncp_request_header request =
+ *((struct ncp_request_header *) (server->packet));
+
+ file = server->ncp_filp;
+ sock = &file->f_dentry->d_inode->u.socket_i;
+
+ ncptcp_xmit_hdr[0] = htonl(NCP_TCP_XMIT_MAGIC);
+ ncptcp_xmit_hdr[1] = htonl(size + 16);
+ ncptcp_xmit_hdr[2] = htonl(NCP_TCP_XMIT_VERSION);
+ ncptcp_xmit_hdr[3] = htonl(max_reply_size + 8);
+
+ DDPRINTK("ncpfs: req.typ: %04X, con: %d, "
+ "seq: %d",
+ request.type,
+ (request.conn_high << 8) + request.conn_low,
+ request.sequence);
+ DDPRINTK(" func: %d\n",
+ request.function);
+
+ iov[1].iov_base = (void *) server->packet;
+ iov[1].iov_len = size;
+ iov[0].iov_base = ncptcp_xmit_hdr;
+ iov[0].iov_len = 16;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_control = NULL;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 2;
+ msg.msg_flags = MSG_NOSIGNAL;
+
+ result = scm_send(sock, &msg, &scm);
+ if (result < 0) {
+ return result;
+ }
+ result = sock->ops->sendmsg(sock, &msg, size + 16, &scm);
+ scm_destroy(&scm);
+ if (result < 0) {
+ printk(KERN_ERR "ncpfs: tcp: Send failed: %d\n", result);
+ return result;
+ }
+rstrcv:
+ result = do_tcp_rcv(server, ncptcp_rcvd_hdr, 8);
+ if (result)
+ return result;
+ if (ncptcp_rcvd_hdr[0] != htonl(NCP_TCP_RCVD_MAGIC)) {
+ printk(KERN_ERR "ncpfs: tcp: Unexpected reply type %08X\n", ntohl(ncptcp_rcvd_hdr[0]));
+ return -EIO;
+ }
+ datalen = ntohl(ncptcp_rcvd_hdr[1]);
+ if (datalen < 8 + sizeof(*reply_buf) || datalen > max_reply_size + 8) {
+ printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen);
+ return -EIO;
+ }
+ datalen -= 8;
+ result = do_tcp_rcv(server, reply_buf, datalen);
+ if (result)
+ return result;
+ if (reply_buf->type != NCP_REPLY) {
+ DDPRINTK("ncpfs: tcp: Unexpected NCP type %02X\n", reply_buf->type);
+ goto rstrcv;
+ }
+ if (request.type == NCP_ALLOC_SLOT_REQUEST)
+ return datalen;
+ if (reply_buf->sequence != request.sequence) {
+ printk(KERN_ERR "ncpfs: tcp: Bad sequence number\n");
+ return -EIO;
+ }
+ if ((reply_buf->conn_low != request.conn_low) ||
+ (reply_buf->conn_high != request.conn_high)) {
+ printk(KERN_ERR "ncpfs: tcp: Connection number mismatch\n");
+ return -EIO;
+ }
+ return datalen;
+}
+
/*
* We need the server to be locked here, so check!
*/
@@ -305,6 +427,8 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size,
static int ncp_do_request(struct ncp_server *server, int size,
void* reply, int max_reply_size)
{
+ struct file *file;
+ struct socket *sock;
int result;
if (server->lock == 0) {
@@ -320,7 +444,50 @@ static int ncp_do_request(struct ncp_server *server, int size,
sign_packet(server, &size);
}
#endif /* CONFIG_NCPFS_PACKET_SIGNING */
- result = do_ncp_rpc_call(server, size, reply, max_reply_size);
+ file = server->ncp_filp;
+ sock = &file->f_dentry->d_inode->u.socket_i;
+ /* N.B. this isn't needed ... check socket type? */
+ if (!sock) {
+ printk(KERN_ERR "ncp_rpc_call: socki_lookup failed\n");
+ result = -EBADF;
+ } else {
+ mm_segment_t fs;
+ sigset_t old_set;
+ unsigned long mask, flags;
+
+ spin_lock_irqsave(&current->sigmask_lock, flags);
+ old_set = current->blocked;
+ mask = sigmask(SIGKILL) | sigmask(SIGSTOP);
+ if (server->m.flags & NCP_MOUNT_INTR) {
+ /* FIXME: This doesn't seem right at all. So, like,
+ we can't handle SIGINT and get whatever to stop?
+ What if we've blocked it ourselves? What about
+ alarms? Why, in fact, are we mucking with the
+ sigmask at all? -- r~ */
+ if (current->sig->action[SIGINT - 1].sa.sa_handler == SIG_DFL)
+ mask |= sigmask(SIGINT);
+ if (current->sig->action[SIGQUIT - 1].sa.sa_handler == SIG_DFL)
+ mask |= sigmask(SIGQUIT);
+ }
+ siginitsetinv(&current->blocked, mask);
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(&current->sigmask_lock, flags);
+
+ fs = get_fs();
+ set_fs(get_ds());
+
+ if (sock->type == SOCK_STREAM)
+ result = do_ncp_tcp_rpc_call(server, size, reply, max_reply_size);
+ else
+ result = do_ncp_rpc_call(server, size, reply, max_reply_size);
+
+ set_fs(fs);
+
+ spin_lock_irqsave(&current->sigmask_lock, flags);
+ current->blocked = old_set;
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(&current->sigmask_lock, flags);
+ }
DDPRINTK("do_ncp_rpc_call returned %d\n", result);
@@ -424,12 +591,6 @@ int ncp_disconnect(struct ncp_server *server)
void ncp_lock_server(struct ncp_server *server)
{
-#if 0
- /* For testing, only 1 process */
- if (server->lock != 0) {
- DPRINTK("ncpfs: server locked!!!\n");
- }
-#endif
down(&server->sem);
if (server->lock)
printk(KERN_WARNING "ncp_lock_server: was locked!\n");