diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-07-08 00:53:00 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-07-08 00:53:00 +0000 |
commit | b8553086288629b4efb77e97f5582e08bc50ad65 (patch) | |
tree | 0a19bd1c21e148f35c7a0f76baa4f7a056b966b0 /fs/ncpfs | |
parent | 75b6d92f2dd5112b02f4e78cf9f35f9825946ef0 (diff) |
Merge with 2.4.0-test3-pre4.
Diffstat (limited to 'fs/ncpfs')
-rw-r--r-- | fs/ncpfs/dir.c | 43 | ||||
-rw-r--r-- | fs/ncpfs/file.c | 9 | ||||
-rw-r--r-- | fs/ncpfs/inode.c | 29 | ||||
-rw-r--r-- | fs/ncpfs/ncplib_kernel.c | 8 | ||||
-rw-r--r-- | fs/ncpfs/ncplib_kernel.h | 10 | ||||
-rw-r--r-- | fs/ncpfs/sock.c | 253 |
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(¤t->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(¤t->blocked, mask); - recalc_sigpending(current); - spin_unlock_irqrestore(¤t->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(¤t->sigmask_lock, flags); - current->blocked = old_set; - recalc_sigpending(current); - spin_unlock_irqrestore(¤t->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(¤t->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(¤t->blocked, mask); + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->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(¤t->sigmask_lock, flags); + current->blocked = old_set; + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->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"); |