aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ncpfs
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /fs/ncpfs
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'fs/ncpfs')
-rw-r--r--fs/ncpfs/Makefile2
-rw-r--r--fs/ncpfs/dir.c267
-rw-r--r--fs/ncpfs/file.c29
-rw-r--r--fs/ncpfs/inode.c93
-rw-r--r--fs/ncpfs/ioctl.c475
-rw-r--r--fs/ncpfs/mmap.c6
-rw-r--r--fs/ncpfs/ncp_fs.h98
-rw-r--r--fs/ncpfs/ncp_fs_i.h29
-rw-r--r--fs/ncpfs/ncp_fs_sb.h176
-rw-r--r--fs/ncpfs/ncplib_kernel.c103
-rw-r--r--fs/ncpfs/ncplib_kernel.h33
-rw-r--r--fs/ncpfs/ncpsign_kernel.c11
-rw-r--r--fs/ncpfs/ncpsign_kernel.h2
-rw-r--r--fs/ncpfs/sock.c3
-rw-r--r--fs/ncpfs/symlink.c4
15 files changed, 858 insertions, 473 deletions
diff --git a/fs/ncpfs/Makefile b/fs/ncpfs/Makefile
index 68ea095100a8..c66af563f2ce 100644
--- a/fs/ncpfs/Makefile
+++ b/fs/ncpfs/Makefile
@@ -11,6 +11,6 @@ ncpfs-$(CONFIG_NCPFS_EXTRAS) += symlink.o
11ncpfs-$(CONFIG_NCPFS_NFS_NS) += symlink.o 11ncpfs-$(CONFIG_NCPFS_NFS_NS) += symlink.o
12 12
13# If you want debugging output, please uncomment the following line 13# If you want debugging output, please uncomment the following line
14# EXTRA_CFLAGS += -DDEBUG_NCP=1 14# ccflags-y := -DDEBUG_NCP=1
15 15
16CFLAGS_ncplib_kernel.o := -finline-functions 16CFLAGS_ncplib_kernel.o := -finline-functions
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 9578cbe0cd58..9c51f621e901 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -17,13 +17,11 @@
17#include <linux/kernel.h> 17#include <linux/kernel.h>
18#include <linux/vmalloc.h> 18#include <linux/vmalloc.h>
19#include <linux/mm.h> 19#include <linux/mm.h>
20#include <linux/namei.h>
20#include <asm/uaccess.h> 21#include <asm/uaccess.h>
21#include <asm/byteorder.h> 22#include <asm/byteorder.h>
22#include <linux/smp_lock.h>
23 23
24#include <linux/ncp_fs.h> 24#include "ncp_fs.h"
25
26#include "ncplib_kernel.h"
27 25
28static void ncp_read_volume_list(struct file *, void *, filldir_t, 26static void ncp_read_volume_list(struct file *, void *, filldir_t,
29 struct ncp_cache_control *); 27 struct ncp_cache_control *);
@@ -75,11 +73,14 @@ const struct inode_operations ncp_dir_inode_operations =
75 * Dentry operations routines 73 * Dentry operations routines
76 */ 74 */
77static int ncp_lookup_validate(struct dentry *, struct nameidata *); 75static int ncp_lookup_validate(struct dentry *, struct nameidata *);
78static int ncp_hash_dentry(struct dentry *, struct qstr *); 76static int ncp_hash_dentry(const struct dentry *, const struct inode *,
79static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *); 77 struct qstr *);
80static int ncp_delete_dentry(struct dentry *); 78static int ncp_compare_dentry(const struct dentry *, const struct inode *,
81 79 const struct dentry *, const struct inode *,
82static const struct dentry_operations ncp_dentry_operations = 80 unsigned int, const char *, const struct qstr *);
81static int ncp_delete_dentry(const struct dentry *);
82
83const struct dentry_operations ncp_dentry_operations =
83{ 84{
84 .d_revalidate = ncp_lookup_validate, 85 .d_revalidate = ncp_lookup_validate,
85 .d_hash = ncp_hash_dentry, 86 .d_hash = ncp_hash_dentry,
@@ -87,28 +88,49 @@ static const struct dentry_operations ncp_dentry_operations =
87 .d_delete = ncp_delete_dentry, 88 .d_delete = ncp_delete_dentry,
88}; 89};
89 90
90const struct dentry_operations ncp_root_dentry_operations = 91#define ncp_namespace(i) (NCP_SERVER(i)->name_space[NCP_FINFO(i)->volNumber])
92
93static inline int ncp_preserve_entry_case(struct inode *i, __u32 nscreator)
91{ 94{
92 .d_hash = ncp_hash_dentry, 95#ifdef CONFIG_NCPFS_SMALLDOS
93 .d_compare = ncp_compare_dentry, 96 int ns = ncp_namespace(i);
94 .d_delete = ncp_delete_dentry, 97
95}; 98 if ((ns == NW_NS_DOS)
99#ifdef CONFIG_NCPFS_OS2_NS
100 || ((ns == NW_NS_OS2) && (nscreator == NW_NS_DOS))
101#endif /* CONFIG_NCPFS_OS2_NS */
102 )
103 return 0;
104#endif /* CONFIG_NCPFS_SMALLDOS */
105 return 1;
106}
96 107
108#define ncp_preserve_case(i) (ncp_namespace(i) != NW_NS_DOS)
109
110static inline int ncp_case_sensitive(const struct inode *i)
111{
112#ifdef CONFIG_NCPFS_NFS_NS
113 return ncp_namespace(i) == NW_NS_NFS;
114#else
115 return 0;
116#endif /* CONFIG_NCPFS_NFS_NS */
117}
97 118
98/* 119/*
99 * Note: leave the hash unchanged if the directory 120 * Note: leave the hash unchanged if the directory
100 * is case-sensitive. 121 * is case-sensitive.
101 */ 122 */
102static int 123static int
103ncp_hash_dentry(struct dentry *dentry, struct qstr *this) 124ncp_hash_dentry(const struct dentry *dentry, const struct inode *inode,
125 struct qstr *this)
104{ 126{
105 struct nls_table *t; 127 if (!ncp_case_sensitive(inode)) {
106 unsigned long hash; 128 struct super_block *sb = dentry->d_sb;
107 int i; 129 struct nls_table *t;
108 130 unsigned long hash;
109 t = NCP_IO_TABLE(dentry); 131 int i;
110 132
111 if (!ncp_case_sensitive(dentry->d_inode)) { 133 t = NCP_IO_TABLE(sb);
112 hash = init_name_hash(); 134 hash = init_name_hash();
113 for (i=0; i<this->len ; i++) 135 for (i=0; i<this->len ; i++)
114 hash = partial_name_hash(ncp_tolower(t, this->name[i]), 136 hash = partial_name_hash(ncp_tolower(t, this->name[i]),
@@ -119,15 +141,17 @@ ncp_hash_dentry(struct dentry *dentry, struct qstr *this)
119} 141}
120 142
121static int 143static int
122ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) 144ncp_compare_dentry(const struct dentry *parent, const struct inode *pinode,
145 const struct dentry *dentry, const struct inode *inode,
146 unsigned int len, const char *str, const struct qstr *name)
123{ 147{
124 if (a->len != b->len) 148 if (len != name->len)
125 return 1; 149 return 1;
126 150
127 if (ncp_case_sensitive(dentry->d_inode)) 151 if (ncp_case_sensitive(pinode))
128 return strncmp(a->name, b->name, a->len); 152 return strncmp(str, name->name, len);
129 153
130 return ncp_strnicmp(NCP_IO_TABLE(dentry), a->name, b->name, a->len); 154 return ncp_strnicmp(NCP_IO_TABLE(pinode->i_sb), str, name->name, len);
131} 155}
132 156
133/* 157/*
@@ -136,7 +160,7 @@ ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b)
136 * Closing files can be safely postponed until iput() - it's done there anyway. 160 * Closing files can be safely postponed until iput() - it's done there anyway.
137 */ 161 */
138static int 162static int
139ncp_delete_dentry(struct dentry * dentry) 163ncp_delete_dentry(const struct dentry * dentry)
140{ 164{
141 struct inode *inode = dentry->d_inode; 165 struct inode *inode = dentry->d_inode;
142 166
@@ -266,7 +290,7 @@ leave_me:;
266 290
267 291
268static int 292static int
269__ncp_lookup_validate(struct dentry *dentry) 293ncp_lookup_validate(struct dentry *dentry, struct nameidata *nd)
270{ 294{
271 struct ncp_server *server; 295 struct ncp_server *server;
272 struct dentry *parent; 296 struct dentry *parent;
@@ -275,6 +299,12 @@ __ncp_lookup_validate(struct dentry *dentry)
275 int res, val = 0, len; 299 int res, val = 0, len;
276 __u8 __name[NCP_MAXPATHLEN + 1]; 300 __u8 __name[NCP_MAXPATHLEN + 1];
277 301
302 if (dentry == dentry->d_sb->s_root)
303 return 1;
304
305 if (nd->flags & LOOKUP_RCU)
306 return -ECHILD;
307
278 parent = dget_parent(dentry); 308 parent = dget_parent(dentry);
279 dir = parent->d_inode; 309 dir = parent->d_inode;
280 310
@@ -283,9 +313,6 @@ __ncp_lookup_validate(struct dentry *dentry)
283 313
284 server = NCP_SERVER(dir); 314 server = NCP_SERVER(dir);
285 315
286 if (!ncp_conn_valid(server))
287 goto finished;
288
289 /* 316 /*
290 * Inspired by smbfs: 317 * Inspired by smbfs:
291 * The default validation is based on dentry age: 318 * The default validation is based on dentry age:
@@ -304,8 +331,11 @@ __ncp_lookup_validate(struct dentry *dentry)
304 if (ncp_is_server_root(dir)) { 331 if (ncp_is_server_root(dir)) {
305 res = ncp_io2vol(server, __name, &len, dentry->d_name.name, 332 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
306 dentry->d_name.len, 1); 333 dentry->d_name.len, 1);
307 if (!res) 334 if (!res) {
308 res = ncp_lookup_volume(server, __name, &(finfo.i)); 335 res = ncp_lookup_volume(server, __name, &(finfo.i));
336 if (!res)
337 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
338 }
309 } else { 339 } else {
310 res = ncp_io2vol(server, __name, &len, dentry->d_name.name, 340 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
311 dentry->d_name.len, !ncp_preserve_case(dir)); 341 dentry->d_name.len, !ncp_preserve_case(dir));
@@ -320,13 +350,17 @@ __ncp_lookup_validate(struct dentry *dentry)
320 * what we remember, it's not valid any more. 350 * what we remember, it's not valid any more.
321 */ 351 */
322 if (!res) { 352 if (!res) {
323 if (finfo.i.dirEntNum == NCP_FINFO(dentry->d_inode)->dirEntNum) { 353 struct inode *inode = dentry->d_inode;
354
355 mutex_lock(&inode->i_mutex);
356 if (finfo.i.dirEntNum == NCP_FINFO(inode)->dirEntNum) {
324 ncp_new_dentry(dentry); 357 ncp_new_dentry(dentry);
325 val=1; 358 val=1;
326 } else 359 } else
327 DDPRINTK("ncp_lookup_validate: found, but dirEntNum changed\n"); 360 DDPRINTK("ncp_lookup_validate: found, but dirEntNum changed\n");
328 361
329 ncp_update_inode2(dentry->d_inode, &finfo); 362 ncp_update_inode2(inode, &finfo);
363 mutex_unlock(&inode->i_mutex);
330 } 364 }
331 365
332finished: 366finished:
@@ -335,16 +369,6 @@ finished:
335 return val; 369 return val;
336} 370}
337 371
338static int
339ncp_lookup_validate(struct dentry * dentry, struct nameidata *nd)
340{
341 int res;
342 lock_kernel();
343 res = __ncp_lookup_validate(dentry);
344 unlock_kernel();
345 return res;
346}
347
348static struct dentry * 372static struct dentry *
349ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) 373ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
350{ 374{
@@ -364,21 +388,21 @@ ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
364 } 388 }
365 389
366 /* If a pointer is invalid, we search the dentry. */ 390 /* If a pointer is invalid, we search the dentry. */
367 spin_lock(&dcache_lock); 391 spin_lock(&parent->d_lock);
368 next = parent->d_subdirs.next; 392 next = parent->d_subdirs.next;
369 while (next != &parent->d_subdirs) { 393 while (next != &parent->d_subdirs) {
370 dent = list_entry(next, struct dentry, d_u.d_child); 394 dent = list_entry(next, struct dentry, d_u.d_child);
371 if ((unsigned long)dent->d_fsdata == fpos) { 395 if ((unsigned long)dent->d_fsdata == fpos) {
372 if (dent->d_inode) 396 if (dent->d_inode)
373 dget_locked(dent); 397 dget(dent);
374 else 398 else
375 dent = NULL; 399 dent = NULL;
376 spin_unlock(&dcache_lock); 400 spin_unlock(&parent->d_lock);
377 goto out; 401 goto out;
378 } 402 }
379 next = next->next; 403 next = next->next;
380 } 404 }
381 spin_unlock(&dcache_lock); 405 spin_unlock(&parent->d_lock);
382 return NULL; 406 return NULL;
383 407
384out: 408out:
@@ -411,8 +435,6 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
411 int result, mtime_valid = 0; 435 int result, mtime_valid = 0;
412 time_t mtime = 0; 436 time_t mtime = 0;
413 437
414 lock_kernel();
415
416 ctl.page = NULL; 438 ctl.page = NULL;
417 ctl.cache = NULL; 439 ctl.cache = NULL;
418 440
@@ -421,6 +443,7 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
421 (int) filp->f_pos); 443 (int) filp->f_pos);
422 444
423 result = -EIO; 445 result = -EIO;
446 /* Do not generate '.' and '..' when server is dead. */
424 if (!ncp_conn_valid(server)) 447 if (!ncp_conn_valid(server))
425 goto out; 448 goto out;
426 449
@@ -532,6 +555,12 @@ read_really:
532 ctl.head.end = ctl.fpos - 1; 555 ctl.head.end = ctl.fpos - 1;
533 ctl.head.eof = ctl.valid; 556 ctl.head.eof = ctl.valid;
534finished: 557finished:
558 if (ctl.page) {
559 kunmap(ctl.page);
560 SetPageUptodate(ctl.page);
561 unlock_page(ctl.page);
562 page_cache_release(ctl.page);
563 }
535 if (page) { 564 if (page) {
536 cache->head = ctl.head; 565 cache->head = ctl.head;
537 kunmap(page); 566 kunmap(page);
@@ -539,23 +568,17 @@ finished:
539 unlock_page(page); 568 unlock_page(page);
540 page_cache_release(page); 569 page_cache_release(page);
541 } 570 }
542 if (ctl.page) {
543 kunmap(ctl.page);
544 SetPageUptodate(ctl.page);
545 unlock_page(ctl.page);
546 page_cache_release(ctl.page);
547 }
548out: 571out:
549 unlock_kernel();
550 return result; 572 return result;
551} 573}
552 574
553static int 575static int
554ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, 576ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
555 struct ncp_cache_control *ctrl, struct ncp_entry_info *entry) 577 struct ncp_cache_control *ctrl, struct ncp_entry_info *entry,
578 int inval_childs)
556{ 579{
557 struct dentry *newdent, *dentry = filp->f_path.dentry; 580 struct dentry *newdent, *dentry = filp->f_path.dentry;
558 struct inode *newino, *inode = dentry->d_inode; 581 struct inode *dir = dentry->d_inode;
559 struct ncp_cache_control ctl = *ctrl; 582 struct ncp_cache_control ctl = *ctrl;
560 struct qstr qname; 583 struct qstr qname;
561 int valid = 0; 584 int valid = 0;
@@ -564,16 +587,16 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
564 __u8 __name[NCP_MAXPATHLEN + 1]; 587 __u8 __name[NCP_MAXPATHLEN + 1];
565 588
566 qname.len = sizeof(__name); 589 qname.len = sizeof(__name);
567 if (ncp_vol2io(NCP_SERVER(inode), __name, &qname.len, 590 if (ncp_vol2io(NCP_SERVER(dir), __name, &qname.len,
568 entry->i.entryName, entry->i.nameLen, 591 entry->i.entryName, entry->i.nameLen,
569 !ncp_preserve_entry_case(inode, entry->i.NSCreator))) 592 !ncp_preserve_entry_case(dir, entry->i.NSCreator)))
570 return 1; /* I'm not sure */ 593 return 1; /* I'm not sure */
571 594
572 qname.name = __name; 595 qname.name = __name;
573 qname.hash = full_name_hash(qname.name, qname.len); 596 qname.hash = full_name_hash(qname.name, qname.len);
574 597
575 if (dentry->d_op && dentry->d_op->d_hash) 598 if (dentry->d_op && dentry->d_op->d_hash)
576 if (dentry->d_op->d_hash(dentry, &qname) != 0) 599 if (dentry->d_op->d_hash(dentry, dentry->d_inode, &qname) != 0)
577 goto end_advance; 600 goto end_advance;
578 601
579 newdent = d_lookup(dentry, &qname); 602 newdent = d_lookup(dentry, &qname);
@@ -584,22 +607,40 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
584 goto end_advance; 607 goto end_advance;
585 } else { 608 } else {
586 hashed = 1; 609 hashed = 1;
587 memcpy((char *) newdent->d_name.name, qname.name, 610
588 newdent->d_name.len); 611 /* If case sensitivity changed for this volume, all entries below this one
612 should be thrown away. This entry itself is not affected, as its case
613 sensitivity is controlled by its own parent. */
614 if (inval_childs)
615 shrink_dcache_parent(newdent);
616
617 /*
618 * NetWare's OS2 namespace is case preserving yet case
619 * insensitive. So we update dentry's name as received from
620 * server. Parent dir's i_mutex is locked because we're in
621 * readdir.
622 */
623 dentry_update_name_case(newdent, &qname);
589 } 624 }
590 625
591 if (!newdent->d_inode) { 626 if (!newdent->d_inode) {
627 struct inode *inode;
628
592 entry->opened = 0; 629 entry->opened = 0;
593 entry->ino = iunique(inode->i_sb, 2); 630 entry->ino = iunique(dir->i_sb, 2);
594 newino = ncp_iget(inode->i_sb, entry); 631 inode = ncp_iget(dir->i_sb, entry);
595 if (newino) { 632 if (inode) {
596 newdent->d_op = &ncp_dentry_operations; 633 d_instantiate(newdent, inode);
597 d_instantiate(newdent, newino);
598 if (!hashed) 634 if (!hashed)
599 d_rehash(newdent); 635 d_rehash(newdent);
600 } 636 }
601 } else 637 } else {
602 ncp_update_inode2(newdent->d_inode, entry); 638 struct inode *inode = newdent->d_inode;
639
640 mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
641 ncp_update_inode2(inode, entry);
642 mutex_unlock(&inode->i_mutex);
643 }
603 644
604 if (newdent->d_inode) { 645 if (newdent->d_inode) {
605 ino = newdent->d_inode->i_ino; 646 ino = newdent->d_inode->i_ino;
@@ -617,7 +658,7 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
617 ctl.cache = NULL; 658 ctl.cache = NULL;
618 ctl.idx -= NCP_DIRCACHE_SIZE; 659 ctl.idx -= NCP_DIRCACHE_SIZE;
619 ctl.ofs += 1; 660 ctl.ofs += 1;
620 ctl.page = grab_cache_page(&inode->i_data, ctl.ofs); 661 ctl.page = grab_cache_page(&dir->i_data, ctl.ofs);
621 if (ctl.page) 662 if (ctl.page)
622 ctl.cache = kmap(ctl.page); 663 ctl.cache = kmap(ctl.page);
623 } 664 }
@@ -633,7 +674,7 @@ end_advance:
633 if (!ino) 674 if (!ino)
634 ino = find_inode_number(dentry, &qname); 675 ino = find_inode_number(dentry, &qname);
635 if (!ino) 676 if (!ino)
636 ino = iunique(inode->i_sb, 2); 677 ino = iunique(dir->i_sb, 2);
637 ctl.filled = filldir(dirent, qname.name, qname.len, 678 ctl.filled = filldir(dirent, qname.name, qname.len,
638 filp->f_pos, ino, DT_UNKNOWN); 679 filp->f_pos, ino, DT_UNKNOWN);
639 if (!ctl.filled) 680 if (!ctl.filled)
@@ -660,6 +701,7 @@ ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir,
660 (unsigned long) filp->f_pos); 701 (unsigned long) filp->f_pos);
661 702
662 for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) { 703 for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
704 int inval_dentry;
663 705
664 if (ncp_get_volume_info_with_number(server, i, &info) != 0) 706 if (ncp_get_volume_info_with_number(server, i, &info) != 0)
665 return; 707 return;
@@ -675,8 +717,9 @@ ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir,
675 info.volume_name); 717 info.volume_name);
676 continue; 718 continue;
677 } 719 }
720 inval_dentry = ncp_update_known_namespace(server, entry.i.volNumber, NULL);
678 entry.volume = entry.i.volNumber; 721 entry.volume = entry.i.volNumber;
679 if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry)) 722 if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry, inval_dentry))
680 return; 723 return;
681 } 724 }
682} 725}
@@ -739,7 +782,7 @@ ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir,
739 rpl += onerpl; 782 rpl += onerpl;
740 rpls -= onerpl; 783 rpls -= onerpl;
741 entry.volume = entry.i.volNumber; 784 entry.volume = entry.i.volNumber;
742 if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry)) 785 if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry, 0))
743 break; 786 break;
744 } 787 }
745 } while (more); 788 } while (more);
@@ -775,17 +818,19 @@ int ncp_conn_logged_in(struct super_block *sb)
775 if (dent) { 818 if (dent) {
776 struct inode* ino = dent->d_inode; 819 struct inode* ino = dent->d_inode;
777 if (ino) { 820 if (ino) {
821 ncp_update_known_namespace(server, volNumber, NULL);
778 NCP_FINFO(ino)->volNumber = volNumber; 822 NCP_FINFO(ino)->volNumber = volNumber;
779 NCP_FINFO(ino)->dirEntNum = dirEntNum; 823 NCP_FINFO(ino)->dirEntNum = dirEntNum;
780 NCP_FINFO(ino)->DosDirNum = DosDirNum; 824 NCP_FINFO(ino)->DosDirNum = DosDirNum;
825 result = 0;
781 } else { 826 } else {
782 DPRINTK("ncpfs: sb->s_root->d_inode == NULL!\n"); 827 DPRINTK("ncpfs: sb->s_root->d_inode == NULL!\n");
783 } 828 }
784 } else { 829 } else {
785 DPRINTK("ncpfs: sb->s_root == NULL!\n"); 830 DPRINTK("ncpfs: sb->s_root == NULL!\n");
786 } 831 }
787 } 832 } else
788 result = 0; 833 result = 0;
789 834
790out: 835out:
791 return result; 836 return result;
@@ -799,7 +844,6 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, struc
799 int error, res, len; 844 int error, res, len;
800 __u8 __name[NCP_MAXPATHLEN + 1]; 845 __u8 __name[NCP_MAXPATHLEN + 1];
801 846
802 lock_kernel();
803 error = -EIO; 847 error = -EIO;
804 if (!ncp_conn_valid(server)) 848 if (!ncp_conn_valid(server))
805 goto finished; 849 goto finished;
@@ -813,6 +857,8 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, struc
813 dentry->d_name.len, 1); 857 dentry->d_name.len, 1);
814 if (!res) 858 if (!res)
815 res = ncp_lookup_volume(server, __name, &(finfo.i)); 859 res = ncp_lookup_volume(server, __name, &(finfo.i));
860 if (!res)
861 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
816 } else { 862 } else {
817 res = ncp_io2vol(server, __name, &len, dentry->d_name.name, 863 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
818 dentry->d_name.len, !ncp_preserve_case(dir)); 864 dentry->d_name.len, !ncp_preserve_case(dir));
@@ -839,14 +885,12 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, struc
839 if (inode) { 885 if (inode) {
840 ncp_new_dentry(dentry); 886 ncp_new_dentry(dentry);
841add_entry: 887add_entry:
842 dentry->d_op = &ncp_dentry_operations;
843 d_add(dentry, inode); 888 d_add(dentry, inode);
844 error = 0; 889 error = 0;
845 } 890 }
846 891
847finished: 892finished:
848 PPRINTK("ncp_lookup: result=%d\n", error); 893 PPRINTK("ncp_lookup: result=%d\n", error);
849 unlock_kernel();
850 return ERR_PTR(error); 894 return ERR_PTR(error);
851} 895}
852 896
@@ -887,11 +931,6 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode,
887 PPRINTK("ncp_create_new: creating %s/%s, mode=%x\n", 931 PPRINTK("ncp_create_new: creating %s/%s, mode=%x\n",
888 dentry->d_parent->d_name.name, dentry->d_name.name, mode); 932 dentry->d_parent->d_name.name, dentry->d_name.name, mode);
889 933
890 error = -EIO;
891 lock_kernel();
892 if (!ncp_conn_valid(server))
893 goto out;
894
895 ncp_age_dentry(server, dentry); 934 ncp_age_dentry(server, dentry);
896 len = sizeof(__name); 935 len = sizeof(__name);
897 error = ncp_io2vol(server, __name, &len, dentry->d_name.name, 936 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
@@ -917,6 +956,8 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode,
917 if (result) { 956 if (result) {
918 if (result == 0x87) 957 if (result == 0x87)
919 error = -ENAMETOOLONG; 958 error = -ENAMETOOLONG;
959 else if (result < 0)
960 error = result;
920 DPRINTK("ncp_create: %s/%s failed\n", 961 DPRINTK("ncp_create: %s/%s failed\n",
921 dentry->d_parent->d_name.name, dentry->d_name.name); 962 dentry->d_parent->d_name.name, dentry->d_name.name);
922 goto out; 963 goto out;
@@ -935,7 +976,6 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode,
935 976
936 error = ncp_instantiate(dir, dentry, &finfo); 977 error = ncp_instantiate(dir, dentry, &finfo);
937out: 978out:
938 unlock_kernel();
939 return error; 979 return error;
940} 980}
941 981
@@ -955,11 +995,6 @@ static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
955 DPRINTK("ncp_mkdir: making %s/%s\n", 995 DPRINTK("ncp_mkdir: making %s/%s\n",
956 dentry->d_parent->d_name.name, dentry->d_name.name); 996 dentry->d_parent->d_name.name, dentry->d_name.name);
957 997
958 error = -EIO;
959 lock_kernel();
960 if (!ncp_conn_valid(server))
961 goto out;
962
963 ncp_age_dentry(server, dentry); 998 ncp_age_dentry(server, dentry);
964 len = sizeof(__name); 999 len = sizeof(__name);
965 error = ncp_io2vol(server, __name, &len, dentry->d_name.name, 1000 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
@@ -967,12 +1002,11 @@ static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
967 if (error) 1002 if (error)
968 goto out; 1003 goto out;
969 1004
970 error = -EACCES; 1005 error = ncp_open_create_file_or_subdir(server, dir, __name,
971 if (ncp_open_create_file_or_subdir(server, dir, __name,
972 OC_MODE_CREATE, aDIR, 1006 OC_MODE_CREATE, aDIR,
973 cpu_to_le16(0xffff), 1007 cpu_to_le16(0xffff),
974 &finfo) == 0) 1008 &finfo);
975 { 1009 if (error == 0) {
976 if (ncp_is_nfs_extras(server, finfo.volume)) { 1010 if (ncp_is_nfs_extras(server, finfo.volume)) {
977 mode |= S_IFDIR; 1011 mode |= S_IFDIR;
978 finfo.i.nfs.mode = mode; 1012 finfo.i.nfs.mode = mode;
@@ -983,9 +1017,10 @@ static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
983 goto out; 1017 goto out;
984 } 1018 }
985 error = ncp_instantiate(dir, dentry, &finfo); 1019 error = ncp_instantiate(dir, dentry, &finfo);
1020 } else if (error > 0) {
1021 error = -EACCES;
986 } 1022 }
987out: 1023out:
988 unlock_kernel();
989 return error; 1024 return error;
990} 1025}
991 1026
@@ -998,11 +1033,11 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
998 DPRINTK("ncp_rmdir: removing %s/%s\n", 1033 DPRINTK("ncp_rmdir: removing %s/%s\n",
999 dentry->d_parent->d_name.name, dentry->d_name.name); 1034 dentry->d_parent->d_name.name, dentry->d_name.name);
1000 1035
1001 error = -EIO; 1036 /*
1002 lock_kernel(); 1037 * fail with EBUSY if there are still references to this
1003 if (!ncp_conn_valid(server)) 1038 * directory.
1004 goto out; 1039 */
1005 1040 dentry_unhash(dentry);
1006 error = -EBUSY; 1041 error = -EBUSY;
1007 if (!d_unhashed(dentry)) 1042 if (!d_unhashed(dentry))
1008 goto out; 1043 goto out;
@@ -1036,11 +1071,10 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
1036 error = -ENOENT; 1071 error = -ENOENT;
1037 break; 1072 break;
1038 default: 1073 default:
1039 error = -EACCES; 1074 error = result < 0 ? result : -EACCES;
1040 break; 1075 break;
1041 } 1076 }
1042out: 1077out:
1043 unlock_kernel();
1044 return error; 1078 return error;
1045} 1079}
1046 1080
@@ -1050,15 +1084,10 @@ static int ncp_unlink(struct inode *dir, struct dentry *dentry)
1050 struct ncp_server *server; 1084 struct ncp_server *server;
1051 int error; 1085 int error;
1052 1086
1053 lock_kernel();
1054 server = NCP_SERVER(dir); 1087 server = NCP_SERVER(dir);
1055 DPRINTK("ncp_unlink: unlinking %s/%s\n", 1088 DPRINTK("ncp_unlink: unlinking %s/%s\n",
1056 dentry->d_parent->d_name.name, dentry->d_name.name); 1089 dentry->d_parent->d_name.name, dentry->d_name.name);
1057 1090
1058 error = -EIO;
1059 if (!ncp_conn_valid(server))
1060 goto out;
1061
1062 /* 1091 /*
1063 * Check whether to close the file ... 1092 * Check whether to close the file ...
1064 */ 1093 */
@@ -1097,12 +1126,9 @@ static int ncp_unlink(struct inode *dir, struct dentry *dentry)
1097 error = -ENOENT; 1126 error = -ENOENT;
1098 break; 1127 break;
1099 default: 1128 default:
1100 error = -EACCES; 1129 error = error < 0 ? error : -EACCES;
1101 break; 1130 break;
1102 } 1131 }
1103
1104out:
1105 unlock_kernel();
1106 return error; 1132 return error;
1107} 1133}
1108 1134
@@ -1118,10 +1144,16 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
1118 old_dentry->d_parent->d_name.name, old_dentry->d_name.name, 1144 old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
1119 new_dentry->d_parent->d_name.name, new_dentry->d_name.name); 1145 new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
1120 1146
1121 error = -EIO; 1147 if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode)) {
1122 lock_kernel(); 1148 /*
1123 if (!ncp_conn_valid(server)) 1149 * fail with EBUSY if there are still references to this
1124 goto out; 1150 * directory.
1151 */
1152 dentry_unhash(new_dentry);
1153 error = -EBUSY;
1154 if (!d_unhashed(new_dentry))
1155 goto out;
1156 }
1125 1157
1126 ncp_age_dentry(server, old_dentry); 1158 ncp_age_dentry(server, old_dentry);
1127 ncp_age_dentry(server, new_dentry); 1159 ncp_age_dentry(server, new_dentry);
@@ -1161,11 +1193,10 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
1161 error = -ENOENT; 1193 error = -ENOENT;
1162 break; 1194 break;
1163 default: 1195 default:
1164 error = -EACCES; 1196 error = error < 0 ? error : -EACCES;
1165 break; 1197 break;
1166 } 1198 }
1167out: 1199out:
1168 unlock_kernel();
1169 return error; 1200 return error;
1170} 1201}
1171 1202
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index 3639cc5cbdae..0ed65e0c3dfe 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -17,10 +17,8 @@
17#include <linux/mm.h> 17#include <linux/mm.h>
18#include <linux/vmalloc.h> 18#include <linux/vmalloc.h>
19#include <linux/sched.h> 19#include <linux/sched.h>
20#include <linux/smp_lock.h>
21 20
22#include <linux/ncp_fs.h> 21#include "ncp_fs.h"
23#include "ncplib_kernel.h"
24 22
25static int ncp_fsync(struct file *file, int datasync) 23static int ncp_fsync(struct file *file, int datasync)
26{ 24{
@@ -113,9 +111,6 @@ ncp_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
113 DPRINTK("ncp_file_read: enter %s/%s\n", 111 DPRINTK("ncp_file_read: enter %s/%s\n",
114 dentry->d_parent->d_name.name, dentry->d_name.name); 112 dentry->d_parent->d_name.name, dentry->d_name.name);
115 113
116 if (!ncp_conn_valid(NCP_SERVER(inode)))
117 return -EIO;
118
119 pos = *ppos; 114 pos = *ppos;
120 115
121 if ((ssize_t) count < 0) { 116 if ((ssize_t) count < 0) {
@@ -192,13 +187,11 @@ ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *
192 187
193 DPRINTK("ncp_file_write: enter %s/%s\n", 188 DPRINTK("ncp_file_write: enter %s/%s\n",
194 dentry->d_parent->d_name.name, dentry->d_name.name); 189 dentry->d_parent->d_name.name, dentry->d_name.name);
195 if (!ncp_conn_valid(NCP_SERVER(inode)))
196 return -EIO;
197 if ((ssize_t) count < 0) 190 if ((ssize_t) count < 0)
198 return -EINVAL; 191 return -EINVAL;
199 pos = *ppos; 192 pos = *ppos;
200 if (file->f_flags & O_APPEND) { 193 if (file->f_flags & O_APPEND) {
201 pos = inode->i_size; 194 pos = i_size_read(inode);
202 } 195 }
203 196
204 if (pos + count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) { 197 if (pos + count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) {
@@ -264,8 +257,11 @@ ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *
264 257
265 *ppos = pos; 258 *ppos = pos;
266 259
267 if (pos > inode->i_size) { 260 if (pos > i_size_read(inode)) {
268 inode->i_size = pos; 261 mutex_lock(&inode->i_mutex);
262 if (pos > i_size_read(inode))
263 i_size_write(inode, pos);
264 mutex_unlock(&inode->i_mutex);
269 } 265 }
270 DPRINTK("ncp_file_write: exit %s/%s\n", 266 DPRINTK("ncp_file_write: exit %s/%s\n",
271 dentry->d_parent->d_name.name, dentry->d_name.name); 267 dentry->d_parent->d_name.name, dentry->d_name.name);
@@ -281,18 +277,9 @@ static int ncp_release(struct inode *inode, struct file *file) {
281 return 0; 277 return 0;
282} 278}
283 279
284static loff_t ncp_remote_llseek(struct file *file, loff_t offset, int origin)
285{
286 loff_t ret;
287 lock_kernel();
288 ret = generic_file_llseek_unlocked(file, offset, origin);
289 unlock_kernel();
290 return ret;
291}
292
293const struct file_operations ncp_file_operations = 280const struct file_operations ncp_file_operations =
294{ 281{
295 .llseek = ncp_remote_llseek, 282 .llseek = generic_file_llseek,
296 .read = ncp_file_read, 283 .read = ncp_file_read,
297 .write = ncp_file_write, 284 .write = ncp_file_write,
298 .unlocked_ioctl = ncp_ioctl, 285 .unlocked_ioctl = ncp_ioctl,
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index b4de38cf49f5..202f370526a7 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -26,16 +26,14 @@
26#include <linux/slab.h> 26#include <linux/slab.h>
27#include <linux/vmalloc.h> 27#include <linux/vmalloc.h>
28#include <linux/init.h> 28#include <linux/init.h>
29#include <linux/smp_lock.h>
30#include <linux/vfs.h> 29#include <linux/vfs.h>
31#include <linux/mount.h> 30#include <linux/mount.h>
32#include <linux/seq_file.h> 31#include <linux/seq_file.h>
33 32#include <linux/namei.h>
34#include <linux/ncp_fs.h>
35 33
36#include <net/sock.h> 34#include <net/sock.h>
37 35
38#include "ncplib_kernel.h" 36#include "ncp_fs.h"
39#include "getopt.h" 37#include "getopt.h"
40 38
41#define NCP_DEFAULT_FILE_MODE 0600 39#define NCP_DEFAULT_FILE_MODE 0600
@@ -59,11 +57,18 @@ static struct inode *ncp_alloc_inode(struct super_block *sb)
59 return &ei->vfs_inode; 57 return &ei->vfs_inode;
60} 58}
61 59
62static void ncp_destroy_inode(struct inode *inode) 60static void ncp_i_callback(struct rcu_head *head)
63{ 61{
62 struct inode *inode = container_of(head, struct inode, i_rcu);
63 INIT_LIST_HEAD(&inode->i_dentry);
64 kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode)); 64 kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
65} 65}
66 66
67static void ncp_destroy_inode(struct inode *inode)
68{
69 call_rcu(&inode->i_rcu, ncp_i_callback);
70}
71
67static void init_once(void *foo) 72static void init_once(void *foo)
68{ 73{
69 struct ncp_inode_info *ei = (struct ncp_inode_info *) foo; 74 struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
@@ -139,7 +144,7 @@ static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
139 inode->i_mode = nwi->nfs.mode; 144 inode->i_mode = nwi->nfs.mode;
140 } 145 }
141 146
142 inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT; 147 inode->i_blocks = (i_size_read(inode) + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
143 148
144 inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate); 149 inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate);
145 inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate); 150 inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate);
@@ -158,18 +163,21 @@ static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo)
158 inode->i_mode = server->m.dir_mode; 163 inode->i_mode = server->m.dir_mode;
159 /* for directories dataStreamSize seems to be some 164 /* for directories dataStreamSize seems to be some
160 Object ID ??? */ 165 Object ID ??? */
161 inode->i_size = NCP_BLOCK_SIZE; 166 i_size_write(inode, NCP_BLOCK_SIZE);
162 } else { 167 } else {
168 u32 size;
169
163 inode->i_mode = server->m.file_mode; 170 inode->i_mode = server->m.file_mode;
164 inode->i_size = le32_to_cpu(nwi->dataStreamSize); 171 size = le32_to_cpu(nwi->dataStreamSize);
172 i_size_write(inode, size);
165#ifdef CONFIG_NCPFS_EXTRAS 173#ifdef CONFIG_NCPFS_EXTRAS
166 if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS)) 174 if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS))
167 && (nwi->attributes & aSHARED)) { 175 && (nwi->attributes & aSHARED)) {
168 switch (nwi->attributes & (aHIDDEN|aSYSTEM)) { 176 switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
169 case aHIDDEN: 177 case aHIDDEN:
170 if (server->m.flags & NCP_MOUNT_SYMLINKS) { 178 if (server->m.flags & NCP_MOUNT_SYMLINKS) {
171 if (/* (inode->i_size >= NCP_MIN_SYMLINK_SIZE) 179 if (/* (size >= NCP_MIN_SYMLINK_SIZE)
172 && */ (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) { 180 && */ (size <= NCP_MAX_SYMLINK_SIZE)) {
173 inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK; 181 inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
174 NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK; 182 NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK;
175 break; 183 break;
@@ -208,7 +216,7 @@ void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
208} 216}
209 217
210/* 218/*
211 * Fill in the inode based on the ncp_entry_info structure. 219 * Fill in the inode based on the ncp_entry_info structure. Used only for brand new inodes.
212 */ 220 */
213static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo) 221static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
214{ 222{
@@ -254,6 +262,7 @@ ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
254 if (inode) { 262 if (inode) {
255 atomic_set(&NCP_FINFO(inode)->opened, info->opened); 263 atomic_set(&NCP_FINFO(inode)->opened, info->opened);
256 264
265 inode->i_mapping->backing_dev_info = sb->s_bdi;
257 inode->i_ino = info->ino; 266 inode->i_ino = info->ino;
258 ncp_set_attr(inode, info); 267 ncp_set_attr(inode, info);
259 if (S_ISREG(inode->i_mode)) { 268 if (S_ISREG(inode->i_mode)) {
@@ -299,12 +308,19 @@ ncp_evict_inode(struct inode *inode)
299 308
300static void ncp_stop_tasks(struct ncp_server *server) { 309static void ncp_stop_tasks(struct ncp_server *server) {
301 struct sock* sk = server->ncp_sock->sk; 310 struct sock* sk = server->ncp_sock->sk;
302 311
312 lock_sock(sk);
303 sk->sk_error_report = server->error_report; 313 sk->sk_error_report = server->error_report;
304 sk->sk_data_ready = server->data_ready; 314 sk->sk_data_ready = server->data_ready;
305 sk->sk_write_space = server->write_space; 315 sk->sk_write_space = server->write_space;
316 release_sock(sk);
306 del_timer_sync(&server->timeout_tm); 317 del_timer_sync(&server->timeout_tm);
307 flush_scheduled_work(); 318
319 flush_work_sync(&server->rcv.tq);
320 if (sk->sk_socket->type == SOCK_STREAM)
321 flush_work_sync(&server->tx.tq);
322 else
323 flush_work_sync(&server->timeout_tq);
308} 324}
309 325
310static int ncp_show_options(struct seq_file *seq, struct vfsmount *mnt) 326static int ncp_show_options(struct seq_file *seq, struct vfsmount *mnt)
@@ -445,7 +461,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
445#endif 461#endif
446 struct ncp_entry_info finfo; 462 struct ncp_entry_info finfo;
447 463
448 data.wdog_pid = NULL; 464 memset(&data, 0, sizeof(data));
449 server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL); 465 server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
450 if (!server) 466 if (!server)
451 return -ENOMEM; 467 return -ENOMEM;
@@ -480,7 +496,6 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
480 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data; 496 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
481 497
482 data.flags = md->flags; 498 data.flags = md->flags;
483 data.int_flags = 0;
484 data.mounted_uid = md->mounted_uid; 499 data.mounted_uid = md->mounted_uid;
485 data.wdog_pid = find_get_pid(md->wdog_pid); 500 data.wdog_pid = find_get_pid(md->wdog_pid);
486 data.ncp_fd = md->ncp_fd; 501 data.ncp_fd = md->ncp_fd;
@@ -491,7 +506,6 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
491 data.file_mode = md->file_mode; 506 data.file_mode = md->file_mode;
492 data.dir_mode = md->dir_mode; 507 data.dir_mode = md->dir_mode;
493 data.info_fd = -1; 508 data.info_fd = -1;
494 data.mounted_vol[0] = 0;
495 } 509 }
496 break; 510 break;
497 default: 511 default:
@@ -526,6 +540,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
526 sb->s_blocksize_bits = 10; 540 sb->s_blocksize_bits = 10;
527 sb->s_magic = NCP_SUPER_MAGIC; 541 sb->s_magic = NCP_SUPER_MAGIC;
528 sb->s_op = &ncp_sops; 542 sb->s_op = &ncp_sops;
543 sb->s_d_op = &ncp_dentry_operations;
529 sb->s_bdi = &server->bdi; 544 sb->s_bdi = &server->bdi;
530 545
531 server = NCP_SBP(sb); 546 server = NCP_SBP(sb);
@@ -565,10 +580,12 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
565/* server->conn_status = 0; */ 580/* server->conn_status = 0; */
566/* server->root_dentry = NULL; */ 581/* server->root_dentry = NULL; */
567/* server->root_setuped = 0; */ 582/* server->root_setuped = 0; */
583 mutex_init(&server->root_setup_lock);
568#ifdef CONFIG_NCPFS_PACKET_SIGNING 584#ifdef CONFIG_NCPFS_PACKET_SIGNING
569/* server->sign_wanted = 0; */ 585/* server->sign_wanted = 0; */
570/* server->sign_active = 0; */ 586/* server->sign_active = 0; */
571#endif 587#endif
588 init_rwsem(&server->auth_rwsem);
572 server->auth.auth_type = NCP_AUTH_NONE; 589 server->auth.auth_type = NCP_AUTH_NONE;
573/* server->auth.object_name_len = 0; */ 590/* server->auth.object_name_len = 0; */
574/* server->auth.object_name = NULL; */ 591/* server->auth.object_name = NULL; */
@@ -577,7 +594,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
577/* server->priv.data = NULL; */ 594/* server->priv.data = NULL; */
578 595
579 server->m = data; 596 server->m = data;
580 /* Althought anything producing this is buggy, it happens 597 /* Although anything producing this is buggy, it happens
581 now because of PATH_MAX changes.. */ 598 now because of PATH_MAX changes.. */
582 if (server->m.time_out < 1) { 599 if (server->m.time_out < 1) {
583 server->m.time_out = 10; 600 server->m.time_out = 10;
@@ -593,16 +610,12 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
593 server->nls_io = load_nls_default(); 610 server->nls_io = load_nls_default();
594#endif /* CONFIG_NCPFS_NLS */ 611#endif /* CONFIG_NCPFS_NLS */
595 612
596 server->dentry_ttl = 0; /* no caching */ 613 atomic_set(&server->dentry_ttl, 0); /* no caching */
597 614
598 INIT_LIST_HEAD(&server->tx.requests); 615 INIT_LIST_HEAD(&server->tx.requests);
599 mutex_init(&server->rcv.creq_mutex); 616 mutex_init(&server->rcv.creq_mutex);
600 server->tx.creq = NULL; 617 server->tx.creq = NULL;
601 server->rcv.creq = NULL; 618 server->rcv.creq = NULL;
602 server->data_ready = sock->sk->sk_data_ready;
603 server->write_space = sock->sk->sk_write_space;
604 server->error_report = sock->sk->sk_error_report;
605 sock->sk->sk_user_data = server;
606 619
607 init_timer(&server->timeout_tm); 620 init_timer(&server->timeout_tm);
608#undef NCP_PACKET_SIZE 621#undef NCP_PACKET_SIZE
@@ -619,6 +632,11 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
619 if (server->rxbuf == NULL) 632 if (server->rxbuf == NULL)
620 goto out_txbuf; 633 goto out_txbuf;
621 634
635 lock_sock(sock->sk);
636 server->data_ready = sock->sk->sk_data_ready;
637 server->write_space = sock->sk->sk_write_space;
638 server->error_report = sock->sk->sk_error_report;
639 sock->sk->sk_user_data = server;
622 sock->sk->sk_data_ready = ncp_tcp_data_ready; 640 sock->sk->sk_data_ready = ncp_tcp_data_ready;
623 sock->sk->sk_error_report = ncp_tcp_error_report; 641 sock->sk->sk_error_report = ncp_tcp_error_report;
624 if (sock->type == SOCK_STREAM) { 642 if (sock->type == SOCK_STREAM) {
@@ -634,6 +652,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
634 server->timeout_tm.data = (unsigned long)server; 652 server->timeout_tm.data = (unsigned long)server;
635 server->timeout_tm.function = ncpdgram_timeout_call; 653 server->timeout_tm.function = ncpdgram_timeout_call;
636 } 654 }
655 release_sock(sock->sk);
637 656
638 ncp_lock_server(server); 657 ncp_lock_server(server);
639 error = ncp_connect(server); 658 error = ncp_connect(server);
@@ -658,8 +677,10 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
658 goto out_disconnect; 677 goto out_disconnect;
659 } 678 }
660 } 679 }
680 ncp_lock_server(server);
661 if (options & 2) 681 if (options & 2)
662 server->sign_wanted = 1; 682 server->sign_wanted = 1;
683 ncp_unlock_server(server);
663 } 684 }
664 else 685 else
665#endif /* CONFIG_NCPFS_PACKET_SIGNING */ 686#endif /* CONFIG_NCPFS_PACKET_SIGNING */
@@ -699,7 +720,6 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
699 sb->s_root = d_alloc_root(root_inode); 720 sb->s_root = d_alloc_root(root_inode);
700 if (!sb->s_root) 721 if (!sb->s_root)
701 goto out_no_root; 722 goto out_no_root;
702 sb->s_root->d_op = &ncp_root_dentry_operations;
703 return 0; 723 return 0;
704 724
705out_no_root: 725out_no_root:
@@ -720,6 +740,9 @@ out_nls:
720 unload_nls(server->nls_io); 740 unload_nls(server->nls_io);
721 unload_nls(server->nls_vol); 741 unload_nls(server->nls_vol);
722#endif 742#endif
743 mutex_destroy(&server->rcv.creq_mutex);
744 mutex_destroy(&server->root_setup_lock);
745 mutex_destroy(&server->mutex);
723out_fput2: 746out_fput2:
724 if (server->info_filp) 747 if (server->info_filp)
725 fput(server->info_filp); 748 fput(server->info_filp);
@@ -743,8 +766,6 @@ static void ncp_put_super(struct super_block *sb)
743{ 766{
744 struct ncp_server *server = NCP_SBP(sb); 767 struct ncp_server *server = NCP_SBP(sb);
745 768
746 lock_kernel();
747
748 ncp_lock_server(server); 769 ncp_lock_server(server);
749 ncp_disconnect(server); 770 ncp_disconnect(server);
750 ncp_unlock_server(server); 771 ncp_unlock_server(server);
@@ -756,6 +777,9 @@ static void ncp_put_super(struct super_block *sb)
756 unload_nls(server->nls_vol); 777 unload_nls(server->nls_vol);
757 unload_nls(server->nls_io); 778 unload_nls(server->nls_io);
758#endif /* CONFIG_NCPFS_NLS */ 779#endif /* CONFIG_NCPFS_NLS */
780 mutex_destroy(&server->rcv.creq_mutex);
781 mutex_destroy(&server->root_setup_lock);
782 mutex_destroy(&server->mutex);
759 783
760 if (server->info_filp) 784 if (server->info_filp)
761 fput(server->info_filp); 785 fput(server->info_filp);
@@ -771,8 +795,6 @@ static void ncp_put_super(struct super_block *sb)
771 vfree(server->packet); 795 vfree(server->packet);
772 sb->s_fs_info = NULL; 796 sb->s_fs_info = NULL;
773 kfree(server); 797 kfree(server);
774
775 unlock_kernel();
776} 798}
777 799
778static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf) 800static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
@@ -851,10 +873,8 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
851 873
852 result = -EIO; 874 result = -EIO;
853 875
854 lock_kernel();
855
856 server = NCP_SERVER(inode); 876 server = NCP_SERVER(inode);
857 if ((!server) || !ncp_conn_valid(server)) 877 if (!server) /* How this could happen? */
858 goto out; 878 goto out;
859 879
860 /* ageing the dentry to force validation */ 880 /* ageing the dentry to force validation */
@@ -981,8 +1001,6 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
981 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode), 1001 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
982 inode, info_mask, &info); 1002 inode, info_mask, &info);
983 if (result != 0) { 1003 if (result != 0) {
984 result = -EACCES;
985
986 if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) { 1004 if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
987 /* NetWare seems not to allow this. I 1005 /* NetWare seems not to allow this. I
988 do not know why. So, just tell the 1006 do not know why. So, just tell the
@@ -1005,20 +1023,21 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
1005 mark_inode_dirty(inode); 1023 mark_inode_dirty(inode);
1006 1024
1007out: 1025out:
1008 unlock_kernel(); 1026 if (result > 0)
1027 result = -EACCES;
1009 return result; 1028 return result;
1010} 1029}
1011 1030
1012static int ncp_get_sb(struct file_system_type *fs_type, 1031static struct dentry *ncp_mount(struct file_system_type *fs_type,
1013 int flags, const char *dev_name, void *data, struct vfsmount *mnt) 1032 int flags, const char *dev_name, void *data)
1014{ 1033{
1015 return get_sb_nodev(fs_type, flags, data, ncp_fill_super, mnt); 1034 return mount_nodev(fs_type, flags, data, ncp_fill_super);
1016} 1035}
1017 1036
1018static struct file_system_type ncp_fs_type = { 1037static struct file_system_type ncp_fs_type = {
1019 .owner = THIS_MODULE, 1038 .owner = THIS_MODULE,
1020 .name = "ncpfs", 1039 .name = "ncpfs",
1021 .get_sb = ncp_get_sb, 1040 .mount = ncp_mount,
1022 .kill_sb = kill_anon_super, 1041 .kill_sb = kill_anon_super,
1023 .fs_flags = FS_BINARY_MOUNTDATA, 1042 .fs_flags = FS_BINARY_MOUNTDATA,
1024}; 1043};
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index 84a8cfc4e38e..790e92a9ec63 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -17,15 +17,12 @@
17#include <linux/mount.h> 17#include <linux/mount.h>
18#include <linux/slab.h> 18#include <linux/slab.h>
19#include <linux/highuid.h> 19#include <linux/highuid.h>
20#include <linux/smp_lock.h>
21#include <linux/vmalloc.h> 20#include <linux/vmalloc.h>
22#include <linux/sched.h> 21#include <linux/sched.h>
23 22
24#include <linux/ncp_fs.h>
25
26#include <asm/uaccess.h> 23#include <asm/uaccess.h>
27 24
28#include "ncplib_kernel.h" 25#include "ncp_fs.h"
29 26
30/* maximum limit for ncp_objectname_ioctl */ 27/* maximum limit for ncp_objectname_ioctl */
31#define NCP_OBJECT_NAME_MAX_LEN 4096 28#define NCP_OBJECT_NAME_MAX_LEN 4096
@@ -35,16 +32,11 @@
35#define NCP_PACKET_SIZE_INTERNAL 65536 32#define NCP_PACKET_SIZE_INTERNAL 65536
36 33
37static int 34static int
38ncp_get_fs_info(struct ncp_server * server, struct file *file, 35ncp_get_fs_info(struct ncp_server * server, struct inode *inode,
39 struct ncp_fs_info __user *arg) 36 struct ncp_fs_info __user *arg)
40{ 37{
41 struct inode *inode = file->f_path.dentry->d_inode;
42 struct ncp_fs_info info; 38 struct ncp_fs_info info;
43 39
44 if (file_permission(file, MAY_WRITE) != 0
45 && current_uid() != server->m.mounted_uid)
46 return -EACCES;
47
48 if (copy_from_user(&info, arg, sizeof(info))) 40 if (copy_from_user(&info, arg, sizeof(info)))
49 return -EFAULT; 41 return -EFAULT;
50 42
@@ -65,16 +57,11 @@ ncp_get_fs_info(struct ncp_server * server, struct file *file,
65} 57}
66 58
67static int 59static int
68ncp_get_fs_info_v2(struct ncp_server * server, struct file *file, 60ncp_get_fs_info_v2(struct ncp_server * server, struct inode *inode,
69 struct ncp_fs_info_v2 __user * arg) 61 struct ncp_fs_info_v2 __user * arg)
70{ 62{
71 struct inode *inode = file->f_path.dentry->d_inode;
72 struct ncp_fs_info_v2 info2; 63 struct ncp_fs_info_v2 info2;
73 64
74 if (file_permission(file, MAY_WRITE) != 0
75 && current_uid() != server->m.mounted_uid)
76 return -EACCES;
77
78 if (copy_from_user(&info2, arg, sizeof(info2))) 65 if (copy_from_user(&info2, arg, sizeof(info2)))
79 return -EFAULT; 66 return -EFAULT;
80 67
@@ -136,16 +123,11 @@ struct compat_ncp_privatedata_ioctl
136#define NCP_IOC_SETPRIVATEDATA_32 _IOR('n', 10, struct compat_ncp_privatedata_ioctl) 123#define NCP_IOC_SETPRIVATEDATA_32 _IOR('n', 10, struct compat_ncp_privatedata_ioctl)
137 124
138static int 125static int
139ncp_get_compat_fs_info_v2(struct ncp_server * server, struct file *file, 126ncp_get_compat_fs_info_v2(struct ncp_server * server, struct inode *inode,
140 struct compat_ncp_fs_info_v2 __user * arg) 127 struct compat_ncp_fs_info_v2 __user * arg)
141{ 128{
142 struct inode *inode = file->f_path.dentry->d_inode;
143 struct compat_ncp_fs_info_v2 info2; 129 struct compat_ncp_fs_info_v2 info2;
144 130
145 if (file_permission(file, MAY_WRITE) != 0
146 && current_uid() != server->m.mounted_uid)
147 return -EACCES;
148
149 if (copy_from_user(&info2, arg, sizeof(info2))) 131 if (copy_from_user(&info2, arg, sizeof(info2)))
150 return -EFAULT; 132 return -EFAULT;
151 133
@@ -182,11 +164,8 @@ ncp_set_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg)
182 struct nls_table *iocharset; 164 struct nls_table *iocharset;
183 struct nls_table *oldset_io; 165 struct nls_table *oldset_io;
184 struct nls_table *oldset_cp; 166 struct nls_table *oldset_cp;
185 167 int utf8;
186 if (!capable(CAP_SYS_ADMIN)) 168 int err;
187 return -EACCES;
188 if (server->root_setuped)
189 return -EBUSY;
190 169
191 if (copy_from_user(&user, arg, sizeof(user))) 170 if (copy_from_user(&user, arg, sizeof(user)))
192 return -EFAULT; 171 return -EFAULT;
@@ -206,28 +185,40 @@ ncp_set_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg)
206 user.iocharset[NCP_IOCSNAME_LEN] = 0; 185 user.iocharset[NCP_IOCSNAME_LEN] = 0;
207 if (!user.iocharset[0] || !strcmp(user.iocharset, "default")) { 186 if (!user.iocharset[0] || !strcmp(user.iocharset, "default")) {
208 iocharset = load_nls_default(); 187 iocharset = load_nls_default();
209 NCP_CLR_FLAG(server, NCP_FLAG_UTF8); 188 utf8 = 0;
210 } else if (!strcmp(user.iocharset, "utf8")) { 189 } else if (!strcmp(user.iocharset, "utf8")) {
211 iocharset = load_nls_default(); 190 iocharset = load_nls_default();
212 NCP_SET_FLAG(server, NCP_FLAG_UTF8); 191 utf8 = 1;
213 } else { 192 } else {
214 iocharset = load_nls(user.iocharset); 193 iocharset = load_nls(user.iocharset);
215 if (!iocharset) { 194 if (!iocharset) {
216 unload_nls(codepage); 195 unload_nls(codepage);
217 return -EBADRQC; 196 return -EBADRQC;
218 } 197 }
219 NCP_CLR_FLAG(server, NCP_FLAG_UTF8); 198 utf8 = 0;
220 } 199 }
221 200
222 oldset_cp = server->nls_vol; 201 mutex_lock(&server->root_setup_lock);
223 server->nls_vol = codepage; 202 if (server->root_setuped) {
224 oldset_io = server->nls_io; 203 oldset_cp = codepage;
225 server->nls_io = iocharset; 204 oldset_io = iocharset;
226 205 err = -EBUSY;
206 } else {
207 if (utf8)
208 NCP_SET_FLAG(server, NCP_FLAG_UTF8);
209 else
210 NCP_CLR_FLAG(server, NCP_FLAG_UTF8);
211 oldset_cp = server->nls_vol;
212 server->nls_vol = codepage;
213 oldset_io = server->nls_io;
214 server->nls_io = iocharset;
215 err = 0;
216 }
217 mutex_unlock(&server->root_setup_lock);
227 unload_nls(oldset_cp); 218 unload_nls(oldset_cp);
228 unload_nls(oldset_io); 219 unload_nls(oldset_io);
229 220
230 return 0; 221 return err;
231} 222}
232 223
233static int 224static int
@@ -237,6 +228,7 @@ ncp_get_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg)
237 int len; 228 int len;
238 229
239 memset(&user, 0, sizeof(user)); 230 memset(&user, 0, sizeof(user));
231 mutex_lock(&server->root_setup_lock);
240 if (server->nls_vol && server->nls_vol->charset) { 232 if (server->nls_vol && server->nls_vol->charset) {
241 len = strlen(server->nls_vol->charset); 233 len = strlen(server->nls_vol->charset);
242 if (len > NCP_IOCSNAME_LEN) 234 if (len > NCP_IOCSNAME_LEN)
@@ -254,6 +246,7 @@ ncp_get_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg)
254 strncpy(user.iocharset, server->nls_io->charset, len); 246 strncpy(user.iocharset, server->nls_io->charset, len);
255 user.iocharset[len] = 0; 247 user.iocharset[len] = 0;
256 } 248 }
249 mutex_unlock(&server->root_setup_lock);
257 250
258 if (copy_to_user(arg, &user, sizeof(user))) 251 if (copy_to_user(arg, &user, sizeof(user)))
259 return -EFAULT; 252 return -EFAULT;
@@ -261,25 +254,19 @@ ncp_get_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg)
261} 254}
262#endif /* CONFIG_NCPFS_NLS */ 255#endif /* CONFIG_NCPFS_NLS */
263 256
264static long __ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 257static long __ncp_ioctl(struct inode *inode, unsigned int cmd, unsigned long arg)
265{ 258{
266 struct inode *inode = filp->f_dentry->d_inode;
267 struct ncp_server *server = NCP_SERVER(inode); 259 struct ncp_server *server = NCP_SERVER(inode);
268 int result; 260 int result;
269 struct ncp_ioctl_request request; 261 struct ncp_ioctl_request request;
270 char* bouncebuffer; 262 char* bouncebuffer;
271 void __user *argp = (void __user *)arg; 263 void __user *argp = (void __user *)arg;
272 uid_t uid = current_uid();
273 264
274 switch (cmd) { 265 switch (cmd) {
275#ifdef CONFIG_COMPAT 266#ifdef CONFIG_COMPAT
276 case NCP_IOC_NCPREQUEST_32: 267 case NCP_IOC_NCPREQUEST_32:
277#endif 268#endif
278 case NCP_IOC_NCPREQUEST: 269 case NCP_IOC_NCPREQUEST:
279 if (file_permission(filp, MAY_WRITE) != 0
280 && uid != server->m.mounted_uid)
281 return -EACCES;
282
283#ifdef CONFIG_COMPAT 270#ifdef CONFIG_COMPAT
284 if (cmd == NCP_IOC_NCPREQUEST_32) { 271 if (cmd == NCP_IOC_NCPREQUEST_32) {
285 struct compat_ncp_ioctl_request request32; 272 struct compat_ncp_ioctl_request request32;
@@ -314,7 +301,7 @@ static long __ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
314 server->current_size = request.size; 301 server->current_size = request.size;
315 memcpy(server->packet, bouncebuffer, request.size); 302 memcpy(server->packet, bouncebuffer, request.size);
316 303
317 result = ncp_request2(server, request.function, 304 result = ncp_request2(server, request.function,
318 bouncebuffer, NCP_PACKET_SIZE_INTERNAL); 305 bouncebuffer, NCP_PACKET_SIZE_INTERNAL);
319 if (result < 0) 306 if (result < 0)
320 result = -EIO; 307 result = -EIO;
@@ -331,69 +318,69 @@ static long __ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
331 318
332 case NCP_IOC_CONN_LOGGED_IN: 319 case NCP_IOC_CONN_LOGGED_IN:
333 320
334 if (!capable(CAP_SYS_ADMIN))
335 return -EACCES;
336 if (!(server->m.int_flags & NCP_IMOUNT_LOGGEDIN_POSSIBLE)) 321 if (!(server->m.int_flags & NCP_IMOUNT_LOGGEDIN_POSSIBLE))
337 return -EINVAL; 322 return -EINVAL;
323 mutex_lock(&server->root_setup_lock);
338 if (server->root_setuped) 324 if (server->root_setuped)
339 return -EBUSY; 325 result = -EBUSY;
340 server->root_setuped = 1; 326 else {
341 return ncp_conn_logged_in(inode->i_sb); 327 result = ncp_conn_logged_in(inode->i_sb);
328 if (result == 0)
329 server->root_setuped = 1;
330 }
331 mutex_unlock(&server->root_setup_lock);
332 return result;
342 333
343 case NCP_IOC_GET_FS_INFO: 334 case NCP_IOC_GET_FS_INFO:
344 return ncp_get_fs_info(server, filp, argp); 335 return ncp_get_fs_info(server, inode, argp);
345 336
346 case NCP_IOC_GET_FS_INFO_V2: 337 case NCP_IOC_GET_FS_INFO_V2:
347 return ncp_get_fs_info_v2(server, filp, argp); 338 return ncp_get_fs_info_v2(server, inode, argp);
348 339
349#ifdef CONFIG_COMPAT 340#ifdef CONFIG_COMPAT
350 case NCP_IOC_GET_FS_INFO_V2_32: 341 case NCP_IOC_GET_FS_INFO_V2_32:
351 return ncp_get_compat_fs_info_v2(server, filp, argp); 342 return ncp_get_compat_fs_info_v2(server, inode, argp);
352#endif 343#endif
353 /* we have too many combinations of CONFIG_COMPAT, 344 /* we have too many combinations of CONFIG_COMPAT,
354 * CONFIG_64BIT and CONFIG_UID16, so just handle 345 * CONFIG_64BIT and CONFIG_UID16, so just handle
355 * any of the possible ioctls */ 346 * any of the possible ioctls */
356 case NCP_IOC_GETMOUNTUID16: 347 case NCP_IOC_GETMOUNTUID16:
357 case NCP_IOC_GETMOUNTUID32: 348 {
358 case NCP_IOC_GETMOUNTUID64:
359 if (file_permission(filp, MAY_READ) != 0
360 && uid != server->m.mounted_uid)
361 return -EACCES;
362
363 if (cmd == NCP_IOC_GETMOUNTUID16) {
364 u16 uid; 349 u16 uid;
350
365 SET_UID(uid, server->m.mounted_uid); 351 SET_UID(uid, server->m.mounted_uid);
366 if (put_user(uid, (u16 __user *)argp)) 352 if (put_user(uid, (u16 __user *)argp))
367 return -EFAULT; 353 return -EFAULT;
368 } else if (cmd == NCP_IOC_GETMOUNTUID32) { 354 return 0;
369 if (put_user(server->m.mounted_uid,
370 (u32 __user *)argp))
371 return -EFAULT;
372 } else {
373 if (put_user(server->m.mounted_uid,
374 (u64 __user *)argp))
375 return -EFAULT;
376 } 355 }
356 case NCP_IOC_GETMOUNTUID32:
357 if (put_user(server->m.mounted_uid,
358 (u32 __user *)argp))
359 return -EFAULT;
360 return 0;
361 case NCP_IOC_GETMOUNTUID64:
362 if (put_user(server->m.mounted_uid,
363 (u64 __user *)argp))
364 return -EFAULT;
377 return 0; 365 return 0;
378 366
379 case NCP_IOC_GETROOT: 367 case NCP_IOC_GETROOT:
380 { 368 {
381 struct ncp_setroot_ioctl sr; 369 struct ncp_setroot_ioctl sr;
382 370
383 if (file_permission(filp, MAY_READ) != 0 371 result = -EACCES;
384 && uid != server->m.mounted_uid) 372 mutex_lock(&server->root_setup_lock);
385 return -EACCES;
386
387 if (server->m.mounted_vol[0]) { 373 if (server->m.mounted_vol[0]) {
388 struct dentry* dentry = inode->i_sb->s_root; 374 struct dentry* dentry = inode->i_sb->s_root;
389 375
390 if (dentry) { 376 if (dentry) {
391 struct inode* s_inode = dentry->d_inode; 377 struct inode* s_inode = dentry->d_inode;
392 378
393 if (s_inode) { 379 if (s_inode) {
394 sr.volNumber = NCP_FINFO(s_inode)->volNumber; 380 sr.volNumber = NCP_FINFO(s_inode)->volNumber;
395 sr.dirEntNum = NCP_FINFO(s_inode)->dirEntNum; 381 sr.dirEntNum = NCP_FINFO(s_inode)->dirEntNum;
396 sr.namespace = server->name_space[sr.volNumber]; 382 sr.namespace = server->name_space[sr.volNumber];
383 result = 0;
397 } else 384 } else
398 DPRINTK("ncpfs: s_root->d_inode==NULL\n"); 385 DPRINTK("ncpfs: s_root->d_inode==NULL\n");
399 } else 386 } else
@@ -402,10 +389,12 @@ static long __ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
402 sr.volNumber = -1; 389 sr.volNumber = -1;
403 sr.namespace = 0; 390 sr.namespace = 0;
404 sr.dirEntNum = 0; 391 sr.dirEntNum = 0;
392 result = 0;
405 } 393 }
406 if (copy_to_user(argp, &sr, sizeof(sr))) 394 mutex_unlock(&server->root_setup_lock);
407 return -EFAULT; 395 if (!result && copy_to_user(argp, &sr, sizeof(sr)))
408 return 0; 396 result = -EFAULT;
397 return result;
409 } 398 }
410 399
411 case NCP_IOC_SETROOT: 400 case NCP_IOC_SETROOT:
@@ -416,103 +405,114 @@ static long __ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
416 __le32 dosde; 405 __le32 dosde;
417 struct dentry* dentry; 406 struct dentry* dentry;
418 407
419 if (!capable(CAP_SYS_ADMIN))
420 {
421 return -EACCES;
422 }
423 if (server->root_setuped) return -EBUSY;
424 if (copy_from_user(&sr, argp, sizeof(sr))) 408 if (copy_from_user(&sr, argp, sizeof(sr)))
425 return -EFAULT; 409 return -EFAULT;
426 if (sr.volNumber < 0) { 410 mutex_lock(&server->root_setup_lock);
427 server->m.mounted_vol[0] = 0; 411 if (server->root_setuped)
428 vnum = NCP_NUMBER_OF_VOLUMES; 412 result = -EBUSY;
429 de = 0; 413 else {
430 dosde = 0; 414 if (sr.volNumber < 0) {
431 } else if (sr.volNumber >= NCP_NUMBER_OF_VOLUMES) { 415 server->m.mounted_vol[0] = 0;
432 return -EINVAL; 416 vnum = NCP_NUMBER_OF_VOLUMES;
433 } else if (ncp_mount_subdir(server, sr.volNumber, 417 de = 0;
434 sr.namespace, sr.dirEntNum, 418 dosde = 0;
435 &vnum, &de, &dosde)) { 419 result = 0;
436 return -ENOENT; 420 } else if (sr.volNumber >= NCP_NUMBER_OF_VOLUMES) {
437 } 421 result = -EINVAL;
438 422 } else if (ncp_mount_subdir(server, sr.volNumber,
439 dentry = inode->i_sb->s_root; 423 sr.namespace, sr.dirEntNum,
440 server->root_setuped = 1; 424 &vnum, &de, &dosde)) {
441 if (dentry) { 425 result = -ENOENT;
442 struct inode* s_inode = dentry->d_inode;
443
444 if (s_inode) {
445 NCP_FINFO(s_inode)->volNumber = vnum;
446 NCP_FINFO(s_inode)->dirEntNum = de;
447 NCP_FINFO(s_inode)->DosDirNum = dosde;
448 } else 426 } else
449 DPRINTK("ncpfs: s_root->d_inode==NULL\n"); 427 result = 0;
450 } else 428
451 DPRINTK("ncpfs: s_root==NULL\n"); 429 if (result == 0) {
430 dentry = inode->i_sb->s_root;
431 if (dentry) {
432 struct inode* s_inode = dentry->d_inode;
433
434 if (s_inode) {
435 NCP_FINFO(s_inode)->volNumber = vnum;
436 NCP_FINFO(s_inode)->dirEntNum = de;
437 NCP_FINFO(s_inode)->DosDirNum = dosde;
438 server->root_setuped = 1;
439 } else {
440 DPRINTK("ncpfs: s_root->d_inode==NULL\n");
441 result = -EIO;
442 }
443 } else {
444 DPRINTK("ncpfs: s_root==NULL\n");
445 result = -EIO;
446 }
447 }
448 result = 0;
449 }
450 mutex_unlock(&server->root_setup_lock);
452 451
453 return 0; 452 return result;
454 } 453 }
455 454
456#ifdef CONFIG_NCPFS_PACKET_SIGNING 455#ifdef CONFIG_NCPFS_PACKET_SIGNING
457 case NCP_IOC_SIGN_INIT: 456 case NCP_IOC_SIGN_INIT:
458 if (file_permission(filp, MAY_WRITE) != 0 457 {
459 && uid != server->m.mounted_uid) 458 struct ncp_sign_init sign;
460 return -EACCES;
461
462 if (argp) {
463 if (server->sign_wanted)
464 {
465 struct ncp_sign_init sign;
466 459
460 if (argp)
467 if (copy_from_user(&sign, argp, sizeof(sign))) 461 if (copy_from_user(&sign, argp, sizeof(sign)))
468 return -EFAULT; 462 return -EFAULT;
469 memcpy(server->sign_root,sign.sign_root,8); 463 ncp_lock_server(server);
470 memcpy(server->sign_last,sign.sign_last,16); 464 mutex_lock(&server->rcv.creq_mutex);
471 server->sign_active = 1; 465 if (argp) {
466 if (server->sign_wanted) {
467 memcpy(server->sign_root,sign.sign_root,8);
468 memcpy(server->sign_last,sign.sign_last,16);
469 server->sign_active = 1;
470 }
471 /* ignore when signatures not wanted */
472 } else {
473 server->sign_active = 0;
472 } 474 }
473 /* ignore when signatures not wanted */ 475 mutex_unlock(&server->rcv.creq_mutex);
474 } else { 476 ncp_unlock_server(server);
475 server->sign_active = 0; 477 return 0;
476 } 478 }
477 return 0; 479
478
479 case NCP_IOC_SIGN_WANTED: 480 case NCP_IOC_SIGN_WANTED:
480 if (file_permission(filp, MAY_READ) != 0 481 {
481 && uid != server->m.mounted_uid) 482 int state;
482 return -EACCES; 483
483 484 ncp_lock_server(server);
484 if (put_user(server->sign_wanted, (int __user *)argp)) 485 state = server->sign_wanted;
485 return -EFAULT; 486 ncp_unlock_server(server);
486 return 0; 487 if (put_user(state, (int __user *)argp))
488 return -EFAULT;
489 return 0;
490 }
487 491
488 case NCP_IOC_SET_SIGN_WANTED: 492 case NCP_IOC_SET_SIGN_WANTED:
489 { 493 {
490 int newstate; 494 int newstate;
491 495
492 if (file_permission(filp, MAY_WRITE) != 0
493 && uid != server->m.mounted_uid)
494 return -EACCES;
495
496 /* get only low 8 bits... */ 496 /* get only low 8 bits... */
497 if (get_user(newstate, (unsigned char __user *)argp)) 497 if (get_user(newstate, (unsigned char __user *)argp))
498 return -EFAULT; 498 return -EFAULT;
499 result = 0;
500 ncp_lock_server(server);
499 if (server->sign_active) { 501 if (server->sign_active) {
500 /* cannot turn signatures OFF when active */ 502 /* cannot turn signatures OFF when active */
501 if (!newstate) return -EINVAL; 503 if (!newstate)
504 result = -EINVAL;
502 } else { 505 } else {
503 server->sign_wanted = newstate != 0; 506 server->sign_wanted = newstate != 0;
504 } 507 }
505 return 0; 508 ncp_unlock_server(server);
509 return result;
506 } 510 }
507 511
508#endif /* CONFIG_NCPFS_PACKET_SIGNING */ 512#endif /* CONFIG_NCPFS_PACKET_SIGNING */
509 513
510#ifdef CONFIG_NCPFS_IOCTL_LOCKING 514#ifdef CONFIG_NCPFS_IOCTL_LOCKING
511 case NCP_IOC_LOCKUNLOCK: 515 case NCP_IOC_LOCKUNLOCK:
512 if (file_permission(filp, MAY_WRITE) != 0
513 && uid != server->m.mounted_uid)
514 return -EACCES;
515
516 { 516 {
517 struct ncp_lock_ioctl rqdata; 517 struct ncp_lock_ioctl rqdata;
518 518
@@ -541,16 +541,13 @@ static long __ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
541 { 541 {
542 return result; 542 return result;
543 } 543 }
544 result = -EIO;
545 if (!ncp_conn_valid(server))
546 goto outrel;
547 result = -EISDIR; 544 result = -EISDIR;
548 if (!S_ISREG(inode->i_mode)) 545 if (!S_ISREG(inode->i_mode))
549 goto outrel; 546 goto outrel;
550 if (rqdata.cmd == NCP_LOCK_CLEAR) 547 if (rqdata.cmd == NCP_LOCK_CLEAR)
551 { 548 {
552 result = ncp_ClearPhysicalRecord(NCP_SERVER(inode), 549 result = ncp_ClearPhysicalRecord(NCP_SERVER(inode),
553 NCP_FINFO(inode)->file_handle, 550 NCP_FINFO(inode)->file_handle,
554 rqdata.offset, 551 rqdata.offset,
555 rqdata.length); 552 rqdata.length);
556 if (result > 0) result = 0; /* no such lock */ 553 if (result > 0) result = 0; /* no such lock */
@@ -573,7 +570,7 @@ static long __ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
573 rqdata.timeout); 570 rqdata.timeout);
574 if (result > 0) result = -EAGAIN; 571 if (result > 0) result = -EAGAIN;
575 } 572 }
576outrel: 573outrel:
577 ncp_inode_close(inode); 574 ncp_inode_close(inode);
578 return result; 575 return result;
579 } 576 }
@@ -581,60 +578,62 @@ outrel:
581 578
582#ifdef CONFIG_COMPAT 579#ifdef CONFIG_COMPAT
583 case NCP_IOC_GETOBJECTNAME_32: 580 case NCP_IOC_GETOBJECTNAME_32:
584 if (uid != server->m.mounted_uid)
585 return -EACCES;
586 { 581 {
587 struct compat_ncp_objectname_ioctl user; 582 struct compat_ncp_objectname_ioctl user;
588 size_t outl; 583 size_t outl;
589 584
590 if (copy_from_user(&user, argp, sizeof(user))) 585 if (copy_from_user(&user, argp, sizeof(user)))
591 return -EFAULT; 586 return -EFAULT;
587 down_read(&server->auth_rwsem);
592 user.auth_type = server->auth.auth_type; 588 user.auth_type = server->auth.auth_type;
593 outl = user.object_name_len; 589 outl = user.object_name_len;
594 user.object_name_len = server->auth.object_name_len; 590 user.object_name_len = server->auth.object_name_len;
595 if (outl > user.object_name_len) 591 if (outl > user.object_name_len)
596 outl = user.object_name_len; 592 outl = user.object_name_len;
593 result = 0;
597 if (outl) { 594 if (outl) {
598 if (copy_to_user(compat_ptr(user.object_name), 595 if (copy_to_user(compat_ptr(user.object_name),
599 server->auth.object_name, 596 server->auth.object_name,
600 outl)) return -EFAULT; 597 outl))
598 result = -EFAULT;
601 } 599 }
602 if (copy_to_user(argp, &user, sizeof(user))) 600 up_read(&server->auth_rwsem);
603 return -EFAULT; 601 if (!result && copy_to_user(argp, &user, sizeof(user)))
604 return 0; 602 result = -EFAULT;
603 return result;
605 } 604 }
606#endif 605#endif
607 606
608 case NCP_IOC_GETOBJECTNAME: 607 case NCP_IOC_GETOBJECTNAME:
609 if (uid != server->m.mounted_uid)
610 return -EACCES;
611 { 608 {
612 struct ncp_objectname_ioctl user; 609 struct ncp_objectname_ioctl user;
613 size_t outl; 610 size_t outl;
614 611
615 if (copy_from_user(&user, argp, sizeof(user))) 612 if (copy_from_user(&user, argp, sizeof(user)))
616 return -EFAULT; 613 return -EFAULT;
614 down_read(&server->auth_rwsem);
617 user.auth_type = server->auth.auth_type; 615 user.auth_type = server->auth.auth_type;
618 outl = user.object_name_len; 616 outl = user.object_name_len;
619 user.object_name_len = server->auth.object_name_len; 617 user.object_name_len = server->auth.object_name_len;
620 if (outl > user.object_name_len) 618 if (outl > user.object_name_len)
621 outl = user.object_name_len; 619 outl = user.object_name_len;
620 result = 0;
622 if (outl) { 621 if (outl) {
623 if (copy_to_user(user.object_name, 622 if (copy_to_user(user.object_name,
624 server->auth.object_name, 623 server->auth.object_name,
625 outl)) return -EFAULT; 624 outl))
625 result = -EFAULT;
626 } 626 }
627 if (copy_to_user(argp, &user, sizeof(user))) 627 up_read(&server->auth_rwsem);
628 return -EFAULT; 628 if (!result && copy_to_user(argp, &user, sizeof(user)))
629 return 0; 629 result = -EFAULT;
630 return result;
630 } 631 }
631 632
632#ifdef CONFIG_COMPAT 633#ifdef CONFIG_COMPAT
633 case NCP_IOC_SETOBJECTNAME_32: 634 case NCP_IOC_SETOBJECTNAME_32:
634#endif 635#endif
635 case NCP_IOC_SETOBJECTNAME: 636 case NCP_IOC_SETOBJECTNAME:
636 if (uid != server->m.mounted_uid)
637 return -EACCES;
638 { 637 {
639 struct ncp_objectname_ioctl user; 638 struct ncp_objectname_ioctl user;
640 void* newname; 639 void* newname;
@@ -666,9 +665,7 @@ outrel:
666 } else { 665 } else {
667 newname = NULL; 666 newname = NULL;
668 } 667 }
669 /* enter critical section */ 668 down_write(&server->auth_rwsem);
670 /* maybe that kfree can sleep so do that this way */
671 /* it is at least more SMP friendly (in future...) */
672 oldname = server->auth.object_name; 669 oldname = server->auth.object_name;
673 oldnamelen = server->auth.object_name_len; 670 oldnamelen = server->auth.object_name_len;
674 oldprivate = server->priv.data; 671 oldprivate = server->priv.data;
@@ -678,7 +675,7 @@ outrel:
678 server->auth.object_name = newname; 675 server->auth.object_name = newname;
679 server->priv.len = 0; 676 server->priv.len = 0;
680 server->priv.data = NULL; 677 server->priv.data = NULL;
681 /* leave critical section */ 678 up_write(&server->auth_rwsem);
682 kfree(oldprivate); 679 kfree(oldprivate);
683 kfree(oldname); 680 kfree(oldname);
684 return 0; 681 return 0;
@@ -688,8 +685,6 @@ outrel:
688 case NCP_IOC_GETPRIVATEDATA_32: 685 case NCP_IOC_GETPRIVATEDATA_32:
689#endif 686#endif
690 case NCP_IOC_GETPRIVATEDATA: 687 case NCP_IOC_GETPRIVATEDATA:
691 if (uid != server->m.mounted_uid)
692 return -EACCES;
693 { 688 {
694 struct ncp_privatedata_ioctl user; 689 struct ncp_privatedata_ioctl user;
695 size_t outl; 690 size_t outl;
@@ -706,14 +701,20 @@ outrel:
706 if (copy_from_user(&user, argp, sizeof(user))) 701 if (copy_from_user(&user, argp, sizeof(user)))
707 return -EFAULT; 702 return -EFAULT;
708 703
704 down_read(&server->auth_rwsem);
709 outl = user.len; 705 outl = user.len;
710 user.len = server->priv.len; 706 user.len = server->priv.len;
711 if (outl > user.len) outl = user.len; 707 if (outl > user.len) outl = user.len;
708 result = 0;
712 if (outl) { 709 if (outl) {
713 if (copy_to_user(user.data, 710 if (copy_to_user(user.data,
714 server->priv.data, 711 server->priv.data,
715 outl)) return -EFAULT; 712 outl))
713 result = -EFAULT;
716 } 714 }
715 up_read(&server->auth_rwsem);
716 if (result)
717 return result;
717#ifdef CONFIG_COMPAT 718#ifdef CONFIG_COMPAT
718 if (cmd == NCP_IOC_GETPRIVATEDATA_32) { 719 if (cmd == NCP_IOC_GETPRIVATEDATA_32) {
719 struct compat_ncp_privatedata_ioctl user32; 720 struct compat_ncp_privatedata_ioctl user32;
@@ -733,8 +734,6 @@ outrel:
733 case NCP_IOC_SETPRIVATEDATA_32: 734 case NCP_IOC_SETPRIVATEDATA_32:
734#endif 735#endif
735 case NCP_IOC_SETPRIVATEDATA: 736 case NCP_IOC_SETPRIVATEDATA:
736 if (uid != server->m.mounted_uid)
737 return -EACCES;
738 { 737 {
739 struct ncp_privatedata_ioctl user; 738 struct ncp_privatedata_ioctl user;
740 void* new; 739 void* new;
@@ -762,12 +761,12 @@ outrel:
762 } else { 761 } else {
763 new = NULL; 762 new = NULL;
764 } 763 }
765 /* enter critical section */ 764 down_write(&server->auth_rwsem);
766 old = server->priv.data; 765 old = server->priv.data;
767 oldlen = server->priv.len; 766 oldlen = server->priv.len;
768 server->priv.len = user.len; 767 server->priv.len = user.len;
769 server->priv.data = new; 768 server->priv.data = new;
770 /* leave critical section */ 769 up_write(&server->auth_rwsem);
771 kfree(old); 770 kfree(old);
772 return 0; 771 return 0;
773 } 772 }
@@ -775,17 +774,13 @@ outrel:
775#ifdef CONFIG_NCPFS_NLS 774#ifdef CONFIG_NCPFS_NLS
776 case NCP_IOC_SETCHARSETS: 775 case NCP_IOC_SETCHARSETS:
777 return ncp_set_charsets(server, argp); 776 return ncp_set_charsets(server, argp);
778 777
779 case NCP_IOC_GETCHARSETS: 778 case NCP_IOC_GETCHARSETS:
780 return ncp_get_charsets(server, argp); 779 return ncp_get_charsets(server, argp);
781 780
782#endif /* CONFIG_NCPFS_NLS */ 781#endif /* CONFIG_NCPFS_NLS */
783 782
784 case NCP_IOC_SETDENTRYTTL: 783 case NCP_IOC_SETDENTRYTTL:
785 if (file_permission(filp, MAY_WRITE) != 0 &&
786 uid != server->m.mounted_uid)
787 return -EACCES;
788
789 { 784 {
790 u_int32_t user; 785 u_int32_t user;
791 786
@@ -795,13 +790,13 @@ outrel:
795 if (user > 20000) 790 if (user > 20000)
796 return -EINVAL; 791 return -EINVAL;
797 user = (user * HZ) / 1000; 792 user = (user * HZ) / 1000;
798 server->dentry_ttl = user; 793 atomic_set(&server->dentry_ttl, user);
799 return 0; 794 return 0;
800 } 795 }
801 796
802 case NCP_IOC_GETDENTRYTTL: 797 case NCP_IOC_GETDENTRYTTL:
803 { 798 {
804 u_int32_t user = (server->dentry_ttl * 1000) / HZ; 799 u_int32_t user = (atomic_read(&server->dentry_ttl) * 1000) / HZ;
805 if (copy_to_user(argp, &user, sizeof(user))) 800 if (copy_to_user(argp, &user, sizeof(user)))
806 return -EFAULT; 801 return -EFAULT;
807 return 0; 802 return 0;
@@ -811,59 +806,103 @@ outrel:
811 return -EINVAL; 806 return -EINVAL;
812} 807}
813 808
814static int ncp_ioctl_need_write(unsigned int cmd) 809long ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
815{ 810{
811 struct inode *inode = filp->f_dentry->d_inode;
812 struct ncp_server *server = NCP_SERVER(inode);
813 uid_t uid = current_uid();
814 int need_drop_write = 0;
815 long ret;
816
816 switch (cmd) { 817 switch (cmd) {
817 case NCP_IOC_GET_FS_INFO:
818 case NCP_IOC_GET_FS_INFO_V2:
819 case NCP_IOC_NCPREQUEST:
820 case NCP_IOC_SETDENTRYTTL:
821 case NCP_IOC_SIGN_INIT:
822 case NCP_IOC_LOCKUNLOCK:
823 case NCP_IOC_SET_SIGN_WANTED:
824 return 1;
825 case NCP_IOC_GETOBJECTNAME:
826 case NCP_IOC_SETOBJECTNAME:
827 case NCP_IOC_GETPRIVATEDATA:
828 case NCP_IOC_SETPRIVATEDATA:
829 case NCP_IOC_SETCHARSETS: 818 case NCP_IOC_SETCHARSETS:
830 case NCP_IOC_GETCHARSETS:
831 case NCP_IOC_CONN_LOGGED_IN: 819 case NCP_IOC_CONN_LOGGED_IN:
832 case NCP_IOC_GETDENTRYTTL:
833 case NCP_IOC_GETMOUNTUID2:
834 case NCP_IOC_SIGN_WANTED:
835 case NCP_IOC_GETROOT:
836 case NCP_IOC_SETROOT: 820 case NCP_IOC_SETROOT:
837 return 0; 821 if (!capable(CAP_SYS_ADMIN)) {
838 default: 822 ret = -EACCES;
839 /* unknown IOCTL command, assume write */ 823 goto out;
840 return 1; 824 }
825 break;
841 } 826 }
842} 827 if (server->m.mounted_uid != uid) {
843 828 switch (cmd) {
844long ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
845{
846 long ret;
847
848 lock_kernel();
849 if (ncp_ioctl_need_write(cmd)) {
850 /* 829 /*
851 * inside the ioctl(), any failures which 830 * Only mount owner can issue these ioctls. Information
852 * are because of file_permission() are 831 * necessary to authenticate to other NDS servers are
853 * -EACCESS, so it seems consistent to keep 832 * stored here.
854 * that here.
855 */ 833 */
856 if (mnt_want_write(filp->f_path.mnt)) { 834 case NCP_IOC_GETOBJECTNAME:
835 case NCP_IOC_SETOBJECTNAME:
836 case NCP_IOC_GETPRIVATEDATA:
837 case NCP_IOC_SETPRIVATEDATA:
838#ifdef CONFIG_COMPAT
839 case NCP_IOC_GETOBJECTNAME_32:
840 case NCP_IOC_SETOBJECTNAME_32:
841 case NCP_IOC_GETPRIVATEDATA_32:
842 case NCP_IOC_SETPRIVATEDATA_32:
843#endif
857 ret = -EACCES; 844 ret = -EACCES;
858 goto out; 845 goto out;
846 /*
847 * These require write access on the inode if user id
848 * does not match. Note that they do not write to the
849 * file... But old code did mnt_want_write, so I keep
850 * it as is. Of course not for mountpoint owner, as
851 * that breaks read-only mounts altogether as ncpmount
852 * needs working NCP_IOC_NCPREQUEST and
853 * NCP_IOC_GET_FS_INFO. Some of these codes (setdentryttl,
854 * signinit, setsignwanted) should be probably restricted
855 * to owner only, or even more to CAP_SYS_ADMIN).
856 */
857 case NCP_IOC_GET_FS_INFO:
858 case NCP_IOC_GET_FS_INFO_V2:
859 case NCP_IOC_NCPREQUEST:
860 case NCP_IOC_SETDENTRYTTL:
861 case NCP_IOC_SIGN_INIT:
862 case NCP_IOC_LOCKUNLOCK:
863 case NCP_IOC_SET_SIGN_WANTED:
864#ifdef CONFIG_COMPAT
865 case NCP_IOC_GET_FS_INFO_V2_32:
866 case NCP_IOC_NCPREQUEST_32:
867#endif
868 ret = mnt_want_write_file(filp);
869 if (ret)
870 goto out;
871 need_drop_write = 1;
872 ret = inode_permission(inode, MAY_WRITE);
873 if (ret)
874 goto outDropWrite;
875 break;
876 /*
877 * Read access required.
878 */
879 case NCP_IOC_GETMOUNTUID16:
880 case NCP_IOC_GETMOUNTUID32:
881 case NCP_IOC_GETMOUNTUID64:
882 case NCP_IOC_GETROOT:
883 case NCP_IOC_SIGN_WANTED:
884 ret = inode_permission(inode, MAY_READ);
885 if (ret)
886 goto out;
887 break;
888 /*
889 * Anybody can read these.
890 */
891 case NCP_IOC_GETCHARSETS:
892 case NCP_IOC_GETDENTRYTTL:
893 default:
894 /* Three codes below are protected by CAP_SYS_ADMIN above. */
895 case NCP_IOC_SETCHARSETS:
896 case NCP_IOC_CONN_LOGGED_IN:
897 case NCP_IOC_SETROOT:
898 break;
859 } 899 }
860 } 900 }
861 ret = __ncp_ioctl(filp, cmd, arg); 901 ret = __ncp_ioctl(inode, cmd, arg);
862 if (ncp_ioctl_need_write(cmd)) 902outDropWrite:
903 if (need_drop_write)
863 mnt_drop_write(filp->f_path.mnt); 904 mnt_drop_write(filp->f_path.mnt);
864
865out: 905out:
866 unlock_kernel();
867 return ret; 906 return ret;
868} 907}
869 908
@@ -872,10 +911,8 @@ long ncp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
872{ 911{
873 long ret; 912 long ret;
874 913
875 lock_kernel();
876 arg = (unsigned long) compat_ptr(arg); 914 arg = (unsigned long) compat_ptr(arg);
877 ret = ncp_ioctl(file, cmd, arg); 915 ret = ncp_ioctl(file, cmd, arg);
878 unlock_kernel();
879 return ret; 916 return ret;
880} 917}
881#endif 918#endif
diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c
index 56f5b3a0e1ee..e5d71b27a5b0 100644
--- a/fs/ncpfs/mmap.c
+++ b/fs/ncpfs/mmap.c
@@ -16,12 +16,13 @@
16#include <linux/mman.h> 16#include <linux/mman.h>
17#include <linux/string.h> 17#include <linux/string.h>
18#include <linux/fcntl.h> 18#include <linux/fcntl.h>
19#include <linux/ncp_fs.h> 19#include <linux/memcontrol.h>
20 20
21#include "ncplib_kernel.h"
22#include <asm/uaccess.h> 21#include <asm/uaccess.h>
23#include <asm/system.h> 22#include <asm/system.h>
24 23
24#include "ncp_fs.h"
25
25/* 26/*
26 * Fill in the supplied page for mmap 27 * Fill in the supplied page for mmap
27 * XXX: how are we excluding truncate/invalidate here? Maybe need to lock 28 * XXX: how are we excluding truncate/invalidate here? Maybe need to lock
@@ -92,6 +93,7 @@ static int ncp_file_mmap_fault(struct vm_area_struct *area,
92 * -- wli 93 * -- wli
93 */ 94 */
94 count_vm_event(PGMAJFAULT); 95 count_vm_event(PGMAJFAULT);
96 mem_cgroup_count_vm_event(area->vm_mm, PGMAJFAULT);
95 return VM_FAULT_MAJOR; 97 return VM_FAULT_MAJOR;
96} 98}
97 99
diff --git a/fs/ncpfs/ncp_fs.h b/fs/ncpfs/ncp_fs.h
new file mode 100644
index 000000000000..31831afe1c3b
--- /dev/null
+++ b/fs/ncpfs/ncp_fs.h
@@ -0,0 +1,98 @@
1#include <linux/ncp_fs.h>
2#include "ncp_fs_i.h"
3#include "ncp_fs_sb.h"
4
5/* define because it is easy to change PRINTK to {*}PRINTK */
6#define PRINTK(format, args...) printk(KERN_DEBUG format , ## args)
7
8#undef NCPFS_PARANOIA
9#ifdef NCPFS_PARANOIA
10#define PPRINTK(format, args...) PRINTK(format , ## args)
11#else
12#define PPRINTK(format, args...)
13#endif
14
15#ifndef DEBUG_NCP
16#define DEBUG_NCP 0
17#endif
18#if DEBUG_NCP > 0
19#define DPRINTK(format, args...) PRINTK(format , ## args)
20#else
21#define DPRINTK(format, args...)
22#endif
23#if DEBUG_NCP > 1
24#define DDPRINTK(format, args...) PRINTK(format , ## args)
25#else
26#define DDPRINTK(format, args...)
27#endif
28
29#define NCP_MAX_RPC_TIMEOUT (6*HZ)
30
31
32struct ncp_entry_info {
33 struct nw_info_struct i;
34 ino_t ino;
35 int opened;
36 int access;
37 unsigned int volume;
38 __u8 file_handle[6];
39};
40
41static inline struct ncp_server *NCP_SBP(const struct super_block *sb)
42{
43 return sb->s_fs_info;
44}
45
46#define NCP_SERVER(inode) NCP_SBP((inode)->i_sb)
47static inline struct ncp_inode_info *NCP_FINFO(const struct inode *inode)
48{
49 return container_of(inode, struct ncp_inode_info, vfs_inode);
50}
51
52/* linux/fs/ncpfs/inode.c */
53int ncp_notify_change(struct dentry *, struct iattr *);
54struct inode *ncp_iget(struct super_block *, struct ncp_entry_info *);
55void ncp_update_inode(struct inode *, struct ncp_entry_info *);
56void ncp_update_inode2(struct inode *, struct ncp_entry_info *);
57
58/* linux/fs/ncpfs/dir.c */
59extern const struct inode_operations ncp_dir_inode_operations;
60extern const struct file_operations ncp_dir_operations;
61extern const struct dentry_operations ncp_dentry_operations;
62int ncp_conn_logged_in(struct super_block *);
63int ncp_date_dos2unix(__le16 time, __le16 date);
64void ncp_date_unix2dos(int unix_date, __le16 * time, __le16 * date);
65
66/* linux/fs/ncpfs/ioctl.c */
67long ncp_ioctl(struct file *, unsigned int, unsigned long);
68long ncp_compat_ioctl(struct file *, unsigned int, unsigned long);
69
70/* linux/fs/ncpfs/sock.c */
71int ncp_request2(struct ncp_server *server, int function,
72 void* reply, int max_reply_size);
73static inline int ncp_request(struct ncp_server *server, int function) {
74 return ncp_request2(server, function, server->packet, server->packet_size);
75}
76int ncp_connect(struct ncp_server *server);
77int ncp_disconnect(struct ncp_server *server);
78void ncp_lock_server(struct ncp_server *server);
79void ncp_unlock_server(struct ncp_server *server);
80
81/* linux/fs/ncpfs/symlink.c */
82#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
83extern const struct address_space_operations ncp_symlink_aops;
84int ncp_symlink(struct inode*, struct dentry*, const char*);
85#endif
86
87/* linux/fs/ncpfs/file.c */
88extern const struct inode_operations ncp_file_inode_operations;
89extern const struct file_operations ncp_file_operations;
90int ncp_make_open(struct inode *, int);
91
92/* linux/fs/ncpfs/mmap.c */
93int ncp_mmap(struct file *, struct vm_area_struct *);
94
95/* linux/fs/ncpfs/ncplib_kernel.c */
96int ncp_make_closed(struct inode *);
97
98#include "ncplib_kernel.h"
diff --git a/fs/ncpfs/ncp_fs_i.h b/fs/ncpfs/ncp_fs_i.h
new file mode 100644
index 000000000000..4b0bec477846
--- /dev/null
+++ b/fs/ncpfs/ncp_fs_i.h
@@ -0,0 +1,29 @@
1/*
2 * ncp_fs_i.h
3 *
4 * Copyright (C) 1995 Volker Lendecke
5 *
6 */
7
8#ifndef _LINUX_NCP_FS_I
9#define _LINUX_NCP_FS_I
10
11/*
12 * This is the ncpfs part of the inode structure. This must contain
13 * all the information we need to work with an inode after creation.
14 */
15struct ncp_inode_info {
16 __le32 dirEntNum;
17 __le32 DosDirNum;
18 __u8 volNumber;
19 __le32 nwattr;
20 struct mutex open_mutex;
21 atomic_t opened;
22 int access;
23 int flags;
24#define NCPI_KLUDGE_SYMLINK 0x0001
25 __u8 file_handle[6];
26 struct inode vfs_inode;
27};
28
29#endif /* _LINUX_NCP_FS_I */
diff --git a/fs/ncpfs/ncp_fs_sb.h b/fs/ncpfs/ncp_fs_sb.h
new file mode 100644
index 000000000000..4af803f13516
--- /dev/null
+++ b/fs/ncpfs/ncp_fs_sb.h
@@ -0,0 +1,176 @@
1/*
2 * ncp_fs_sb.h
3 *
4 * Copyright (C) 1995, 1996 by Volker Lendecke
5 *
6 */
7
8#ifndef _NCP_FS_SB
9#define _NCP_FS_SB
10
11#include <linux/types.h>
12#include <linux/ncp_mount.h>
13#include <linux/net.h>
14#include <linux/mutex.h>
15#include <linux/backing-dev.h>
16#include <linux/workqueue.h>
17
18#define NCP_DEFAULT_OPTIONS 0 /* 2 for packet signatures */
19
20struct sock;
21
22struct ncp_mount_data_kernel {
23 unsigned long flags; /* NCP_MOUNT_* flags */
24 unsigned int int_flags; /* internal flags */
25#define NCP_IMOUNT_LOGGEDIN_POSSIBLE 0x0001
26 __kernel_uid32_t mounted_uid; /* Who may umount() this filesystem? */
27 struct pid *wdog_pid; /* Who cares for our watchdog packets? */
28 unsigned int ncp_fd; /* The socket to the ncp port */
29 unsigned int time_out; /* How long should I wait after
30 sending a NCP request? */
31 unsigned int retry_count; /* And how often should I retry? */
32 unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
33 __kernel_uid32_t uid;
34 __kernel_gid32_t gid;
35 __kernel_mode_t file_mode;
36 __kernel_mode_t dir_mode;
37 int info_fd;
38};
39
40struct ncp_server {
41
42 struct ncp_mount_data_kernel m; /* Nearly all of the mount data is of
43 interest for us later, so we store
44 it completely. */
45
46 __u8 name_space[NCP_NUMBER_OF_VOLUMES + 2];
47
48 struct file *ncp_filp; /* File pointer to ncp socket */
49 struct socket *ncp_sock;/* ncp socket */
50 struct file *info_filp;
51 struct socket *info_sock;
52
53 u8 sequence;
54 u8 task;
55 u16 connection; /* Remote connection number */
56
57 u8 completion; /* Status message from server */
58 u8 conn_status; /* Bit 4 = 1 ==> Server going down, no
59 requests allowed anymore.
60 Bit 0 = 1 ==> Server is down. */
61
62 int buffer_size; /* Negotiated bufsize */
63
64 int reply_size; /* Size of last reply */
65
66 int packet_size;
67 unsigned char *packet; /* Here we prepare requests and
68 receive replies */
69 unsigned char *txbuf; /* Storage for current request */
70 unsigned char *rxbuf; /* Storage for reply to current request */
71
72 int lock; /* To prevent mismatch in protocols. */
73 struct mutex mutex;
74
75 int current_size; /* for packet preparation */
76 int has_subfunction;
77 int ncp_reply_size;
78
79 int root_setuped;
80 struct mutex root_setup_lock;
81
82 /* info for packet signing */
83 int sign_wanted; /* 1=Server needs signed packets */
84 int sign_active; /* 0=don't do signing, 1=do */
85 char sign_root[8]; /* generated from password and encr. key */
86 char sign_last[16];
87
88 /* Authentication info: NDS or BINDERY, username */
89 struct {
90 int auth_type;
91 size_t object_name_len;
92 void* object_name;
93 int object_type;
94 } auth;
95 /* Password info */
96 struct {
97 size_t len;
98 void* data;
99 } priv;
100 struct rw_semaphore auth_rwsem;
101
102 /* nls info: codepage for volume and charset for I/O */
103 struct nls_table *nls_vol;
104 struct nls_table *nls_io;
105
106 /* maximum age in jiffies */
107 atomic_t dentry_ttl;
108
109 /* miscellaneous */
110 unsigned int flags;
111
112 spinlock_t requests_lock; /* Lock accesses to tx.requests, tx.creq and rcv.creq when STREAM mode */
113
114 void (*data_ready)(struct sock* sk, int len);
115 void (*error_report)(struct sock* sk);
116 void (*write_space)(struct sock* sk); /* STREAM mode only */
117 struct {
118 struct work_struct tq; /* STREAM/DGRAM: data/error ready */
119 struct ncp_request_reply* creq; /* STREAM/DGRAM: awaiting reply from this request */
120 struct mutex creq_mutex; /* DGRAM only: lock accesses to rcv.creq */
121
122 unsigned int state; /* STREAM only: receiver state */
123 struct {
124 __u32 magic __packed;
125 __u32 len __packed;
126 __u16 type __packed;
127 __u16 p1 __packed;
128 __u16 p2 __packed;
129 __u16 p3 __packed;
130 __u16 type2 __packed;
131 } buf; /* STREAM only: temporary buffer */
132 unsigned char* ptr; /* STREAM only: pointer to data */
133 size_t len; /* STREAM only: length of data to receive */
134 } rcv;
135 struct {
136 struct list_head requests; /* STREAM only: queued requests */
137 struct work_struct tq; /* STREAM only: transmitter ready */
138 struct ncp_request_reply* creq; /* STREAM only: currently transmitted entry */
139 } tx;
140 struct timer_list timeout_tm; /* DGRAM only: timeout timer */
141 struct work_struct timeout_tq; /* DGRAM only: associated queue, we run timers from process context */
142 int timeout_last; /* DGRAM only: current timeout length */
143 int timeout_retries; /* DGRAM only: retries left */
144 struct {
145 size_t len;
146 __u8 data[128];
147 } unexpected_packet;
148 struct backing_dev_info bdi;
149};
150
151extern void ncp_tcp_rcv_proc(struct work_struct *work);
152extern void ncp_tcp_tx_proc(struct work_struct *work);
153extern void ncpdgram_rcv_proc(struct work_struct *work);
154extern void ncpdgram_timeout_proc(struct work_struct *work);
155extern void ncpdgram_timeout_call(unsigned long server);
156extern void ncp_tcp_data_ready(struct sock* sk, int len);
157extern void ncp_tcp_write_space(struct sock* sk);
158extern void ncp_tcp_error_report(struct sock* sk);
159
160#define NCP_FLAG_UTF8 1
161
162#define NCP_CLR_FLAG(server, flag) ((server)->flags &= ~(flag))
163#define NCP_SET_FLAG(server, flag) ((server)->flags |= (flag))
164#define NCP_IS_FLAG(server, flag) ((server)->flags & (flag))
165
166static inline int ncp_conn_valid(struct ncp_server *server)
167{
168 return ((server->conn_status & 0x11) == 0);
169}
170
171static inline void ncp_invalidate_conn(struct ncp_server *server)
172{
173 server->conn_status |= 0x01;
174}
175
176#endif
diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c
index 0ec6237a5970..981a95617fc9 100644
--- a/fs/ncpfs/ncplib_kernel.c
+++ b/fs/ncpfs/ncplib_kernel.c
@@ -11,7 +11,7 @@
11 11
12 12
13 13
14#include "ncplib_kernel.h" 14#include "ncp_fs.h"
15 15
16static inline void assert_server_locked(struct ncp_server *server) 16static inline void assert_server_locked(struct ncp_server *server)
17{ 17{
@@ -107,17 +107,17 @@ ncp_reply_data(struct ncp_server *server, int offset)
107 return &(server->packet[sizeof(struct ncp_reply_header) + offset]); 107 return &(server->packet[sizeof(struct ncp_reply_header) + offset]);
108} 108}
109 109
110static inline u8 BVAL(void *data) 110static inline u8 BVAL(const void *data)
111{ 111{
112 return *(u8 *)data; 112 return *(const u8 *)data;
113} 113}
114 114
115static u8 ncp_reply_byte(struct ncp_server *server, int offset) 115static u8 ncp_reply_byte(struct ncp_server *server, int offset)
116{ 116{
117 return *(u8 *)ncp_reply_data(server, offset); 117 return *(const u8 *)ncp_reply_data(server, offset);
118} 118}
119 119
120static inline u16 WVAL_LH(void *data) 120static inline u16 WVAL_LH(const void *data)
121{ 121{
122 return get_unaligned_le16(data); 122 return get_unaligned_le16(data);
123} 123}
@@ -134,7 +134,7 @@ ncp_reply_be16(struct ncp_server *server, int offset)
134 return get_unaligned_be16(ncp_reply_data(server, offset)); 134 return get_unaligned_be16(ncp_reply_data(server, offset));
135} 135}
136 136
137static inline u32 DVAL_LH(void *data) 137static inline u32 DVAL_LH(const void *data)
138{ 138{
139 return get_unaligned_le32(data); 139 return get_unaligned_le32(data);
140} 140}
@@ -349,9 +349,9 @@ int ncp_dirhandle_free(struct ncp_server* server, __u8 dirhandle) {
349 return result; 349 return result;
350} 350}
351 351
352void ncp_extract_file_info(void *structure, struct nw_info_struct *target) 352void ncp_extract_file_info(const void *structure, struct nw_info_struct *target)
353{ 353{
354 __u8 *name_len; 354 const __u8 *name_len;
355 const int info_struct_size = offsetof(struct nw_info_struct, nameLen); 355 const int info_struct_size = offsetof(struct nw_info_struct, nameLen);
356 356
357 memcpy(target, structure, info_struct_size); 357 memcpy(target, structure, info_struct_size);
@@ -364,7 +364,7 @@ void ncp_extract_file_info(void *structure, struct nw_info_struct *target)
364} 364}
365 365
366#ifdef CONFIG_NCPFS_NFS_NS 366#ifdef CONFIG_NCPFS_NFS_NS
367static inline void ncp_extract_nfs_info(unsigned char *structure, 367static inline void ncp_extract_nfs_info(const unsigned char *structure,
368 struct nw_nfs_info *target) 368 struct nw_nfs_info *target)
369{ 369{
370 target->mode = DVAL_LH(structure); 370 target->mode = DVAL_LH(structure);
@@ -417,7 +417,7 @@ int ncp_obtain_nfs_info(struct ncp_server *server,
417 * Returns information for a (one-component) name relative to 417 * Returns information for a (one-component) name relative to
418 * the specified directory. 418 * the specified directory.
419 */ 419 */
420int ncp_obtain_info(struct ncp_server *server, struct inode *dir, char *path, 420int ncp_obtain_info(struct ncp_server *server, struct inode *dir, const char *path,
421 struct nw_info_struct *target) 421 struct nw_info_struct *target)
422{ 422{
423 __u8 volnum = NCP_FINFO(dir)->volNumber; 423 __u8 volnum = NCP_FINFO(dir)->volNumber;
@@ -452,16 +452,16 @@ out:
452#ifdef CONFIG_NCPFS_NFS_NS 452#ifdef CONFIG_NCPFS_NFS_NS
453static int 453static int
454ncp_obtain_DOS_dir_base(struct ncp_server *server, 454ncp_obtain_DOS_dir_base(struct ncp_server *server,
455 __u8 volnum, __le32 dirent, 455 __u8 ns, __u8 volnum, __le32 dirent,
456 char *path, /* At most 1 component */ 456 const char *path, /* At most 1 component */
457 __le32 *DOS_dir_base) 457 __le32 *DOS_dir_base)
458{ 458{
459 int result; 459 int result;
460 460
461 ncp_init_request(server); 461 ncp_init_request(server);
462 ncp_add_byte(server, 6); /* subfunction */ 462 ncp_add_byte(server, 6); /* subfunction */
463 ncp_add_byte(server, server->name_space[volnum]); 463 ncp_add_byte(server, ns);
464 ncp_add_byte(server, server->name_space[volnum]); 464 ncp_add_byte(server, ns);
465 ncp_add_word(server, cpu_to_le16(0x8006)); /* get all */ 465 ncp_add_word(server, cpu_to_le16(0x8006)); /* get all */
466 ncp_add_dword(server, RIM_DIRECTORY); 466 ncp_add_dword(server, RIM_DIRECTORY);
467 ncp_add_handle_path(server, volnum, dirent, 1, path); 467 ncp_add_handle_path(server, volnum, dirent, 1, path);
@@ -523,10 +523,27 @@ ncp_get_known_namespace(struct ncp_server *server, __u8 volume)
523#endif /* defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS) */ 523#endif /* defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS) */
524} 524}
525 525
526int
527ncp_update_known_namespace(struct ncp_server *server, __u8 volume, int *ret_ns)
528{
529 int ns = ncp_get_known_namespace(server, volume);
530
531 if (ret_ns)
532 *ret_ns = ns;
533
534 DPRINTK("lookup_vol: namespace[%d] = %d\n",
535 volume, server->name_space[volume]);
536
537 if (server->name_space[volume] == ns)
538 return 0;
539 server->name_space[volume] = ns;
540 return 1;
541}
542
526static int 543static int
527ncp_ObtainSpecificDirBase(struct ncp_server *server, 544ncp_ObtainSpecificDirBase(struct ncp_server *server,
528 __u8 nsSrc, __u8 nsDst, __u8 vol_num, __le32 dir_base, 545 __u8 nsSrc, __u8 nsDst, __u8 vol_num, __le32 dir_base,
529 char *path, /* At most 1 component */ 546 const char *path, /* At most 1 component */
530 __le32 *dirEntNum, __le32 *DosDirNum) 547 __le32 *dirEntNum, __le32 *DosDirNum)
531{ 548{
532 int result; 549 int result;
@@ -560,14 +577,13 @@ ncp_mount_subdir(struct ncp_server *server,
560{ 577{
561 int dstNS; 578 int dstNS;
562 int result; 579 int result;
563 580
564 dstNS = ncp_get_known_namespace(server, volNumber); 581 ncp_update_known_namespace(server, volNumber, &dstNS);
565 if ((result = ncp_ObtainSpecificDirBase(server, srcNS, dstNS, volNumber, 582 if ((result = ncp_ObtainSpecificDirBase(server, srcNS, dstNS, volNumber,
566 dirEntNum, NULL, newDirEnt, newDosEnt)) != 0) 583 dirEntNum, NULL, newDirEnt, newDosEnt)) != 0)
567 { 584 {
568 return result; 585 return result;
569 } 586 }
570 server->name_space[volNumber] = dstNS;
571 *volume = volNumber; 587 *volume = volNumber;
572 server->m.mounted_vol[1] = 0; 588 server->m.mounted_vol[1] = 0;
573 server->m.mounted_vol[0] = 'X'; 589 server->m.mounted_vol[0] = 'X';
@@ -575,11 +591,10 @@ ncp_mount_subdir(struct ncp_server *server,
575} 591}
576 592
577int 593int
578ncp_get_volume_root(struct ncp_server *server, const char *volname, 594ncp_get_volume_root(struct ncp_server *server,
579 __u32* volume, __le32* dirent, __le32* dosdirent) 595 const char *volname, __u32* volume, __le32* dirent, __le32* dosdirent)
580{ 596{
581 int result; 597 int result;
582 __u8 volnum;
583 598
584 DPRINTK("ncp_get_volume_root: looking up vol %s\n", volname); 599 DPRINTK("ncp_get_volume_root: looking up vol %s\n", volname);
585 600
@@ -601,21 +616,14 @@ ncp_get_volume_root(struct ncp_server *server, const char *volname,
601 return result; 616 return result;
602 } 617 }
603 *dirent = *dosdirent = ncp_reply_dword(server, 4); 618 *dirent = *dosdirent = ncp_reply_dword(server, 4);
604 volnum = ncp_reply_byte(server, 8); 619 *volume = ncp_reply_byte(server, 8);
605 ncp_unlock_server(server); 620 ncp_unlock_server(server);
606 *volume = volnum;
607
608 server->name_space[volnum] = ncp_get_known_namespace(server, volnum);
609
610 DPRINTK("lookup_vol: namespace[%d] = %d\n",
611 volnum, server->name_space[volnum]);
612
613 return 0; 621 return 0;
614} 622}
615 623
616int 624int
617ncp_lookup_volume(struct ncp_server *server, const char *volname, 625ncp_lookup_volume(struct ncp_server *server,
618 struct nw_info_struct *target) 626 const char *volname, struct nw_info_struct *target)
619{ 627{
620 int result; 628 int result;
621 629
@@ -625,6 +633,7 @@ ncp_lookup_volume(struct ncp_server *server, const char *volname,
625 if (result) { 633 if (result) {
626 return result; 634 return result;
627 } 635 }
636 ncp_update_known_namespace(server, target->volNumber, NULL);
628 target->nameLen = strlen(volname); 637 target->nameLen = strlen(volname);
629 memcpy(target->entryName, volname, target->nameLen+1); 638 memcpy(target->entryName, volname, target->nameLen+1);
630 target->attributes = aDIR; 639 target->attributes = aDIR;
@@ -676,8 +685,8 @@ int ncp_modify_nfs_info(struct ncp_server *server, __u8 volnum, __le32 dirent,
676{ 685{
677 int result = 0; 686 int result = 0;
678 687
688 ncp_init_request(server);
679 if (server->name_space[volnum] == NW_NS_NFS) { 689 if (server->name_space[volnum] == NW_NS_NFS) {
680 ncp_init_request(server);
681 ncp_add_byte(server, 25); /* subfunction */ 690 ncp_add_byte(server, 25); /* subfunction */
682 ncp_add_byte(server, server->name_space[volnum]); 691 ncp_add_byte(server, server->name_space[volnum]);
683 ncp_add_byte(server, NW_NS_NFS); 692 ncp_add_byte(server, NW_NS_NFS);
@@ -690,8 +699,8 @@ int ncp_modify_nfs_info(struct ncp_server *server, __u8 volnum, __le32 dirent,
690 ncp_add_dword_lh(server, 1); /* nlinks */ 699 ncp_add_dword_lh(server, 1); /* nlinks */
691 ncp_add_dword_lh(server, rdev); 700 ncp_add_dword_lh(server, rdev);
692 result = ncp_request(server, 87); 701 result = ncp_request(server, 87);
693 ncp_unlock_server(server);
694 } 702 }
703 ncp_unlock_server(server);
695 return result; 704 return result;
696} 705}
697#endif 706#endif
@@ -700,7 +709,7 @@ int ncp_modify_nfs_info(struct ncp_server *server, __u8 volnum, __le32 dirent,
700static int 709static int
701ncp_DeleteNSEntry(struct ncp_server *server, 710ncp_DeleteNSEntry(struct ncp_server *server,
702 __u8 have_dir_base, __u8 volnum, __le32 dirent, 711 __u8 have_dir_base, __u8 volnum, __le32 dirent,
703 char* name, __u8 ns, __le16 attr) 712 const char* name, __u8 ns, __le16 attr)
704{ 713{
705 int result; 714 int result;
706 715
@@ -734,23 +743,25 @@ ncp_del_file_or_subdir2(struct ncp_server *server,
734 743
735int 744int
736ncp_del_file_or_subdir(struct ncp_server *server, 745ncp_del_file_or_subdir(struct ncp_server *server,
737 struct inode *dir, char *name) 746 struct inode *dir, const char *name)
738{ 747{
739 __u8 volnum = NCP_FINFO(dir)->volNumber; 748 __u8 volnum = NCP_FINFO(dir)->volNumber;
740 __le32 dirent = NCP_FINFO(dir)->dirEntNum; 749 __le32 dirent = NCP_FINFO(dir)->dirEntNum;
750 int name_space;
741 751
752 name_space = server->name_space[volnum];
742#ifdef CONFIG_NCPFS_NFS_NS 753#ifdef CONFIG_NCPFS_NFS_NS
743 if (server->name_space[volnum]==NW_NS_NFS) 754 if (name_space == NW_NS_NFS)
744 { 755 {
745 int result; 756 int result;
746 757
747 result=ncp_obtain_DOS_dir_base(server, volnum, dirent, name, &dirent); 758 result=ncp_obtain_DOS_dir_base(server, name_space, volnum, dirent, name, &dirent);
748 if (result) return result; 759 if (result) return result;
749 return ncp_DeleteNSEntry(server, 1, volnum, dirent, NULL, NW_NS_DOS, cpu_to_le16(0x8006)); 760 name = NULL;
761 name_space = NW_NS_DOS;
750 } 762 }
751 else
752#endif /* CONFIG_NCPFS_NFS_NS */ 763#endif /* CONFIG_NCPFS_NFS_NS */
753 return ncp_DeleteNSEntry(server, 1, volnum, dirent, name, server->name_space[volnum], cpu_to_le16(0x8006)); 764 return ncp_DeleteNSEntry(server, 1, volnum, dirent, name, name_space, cpu_to_le16(0x8006));
754} 765}
755 766
756static inline void ConvertToNWfromDWORD(__u16 v0, __u16 v1, __u8 ret[6]) 767static inline void ConvertToNWfromDWORD(__u16 v0, __u16 v1, __u8 ret[6])
@@ -765,7 +776,7 @@ static inline void ConvertToNWfromDWORD(__u16 v0, __u16 v1, __u8 ret[6])
765/* If both dir and name are NULL, then in target there's already a 776/* If both dir and name are NULL, then in target there's already a
766 looked-up entry that wants to be opened. */ 777 looked-up entry that wants to be opened. */
767int ncp_open_create_file_or_subdir(struct ncp_server *server, 778int ncp_open_create_file_or_subdir(struct ncp_server *server,
768 struct inode *dir, char *name, 779 struct inode *dir, const char *name,
769 int open_create_mode, 780 int open_create_mode,
770 __le32 create_attributes, 781 __le32 create_attributes,
771 __le16 desired_acc_rights, 782 __le16 desired_acc_rights,
@@ -890,8 +901,8 @@ int ncp_search_for_fileset(struct ncp_server *server,
890 901
891static int 902static int
892ncp_RenameNSEntry(struct ncp_server *server, 903ncp_RenameNSEntry(struct ncp_server *server,
893 struct inode *old_dir, char *old_name, __le16 old_type, 904 struct inode *old_dir, const char *old_name, __le16 old_type,
894 struct inode *new_dir, char *new_name) 905 struct inode *new_dir, const char *new_name)
895{ 906{
896 int result = -EINVAL; 907 int result = -EINVAL;
897 908
@@ -929,8 +940,8 @@ out:
929} 940}
930 941
931int ncp_ren_or_mov_file_or_subdir(struct ncp_server *server, 942int ncp_ren_or_mov_file_or_subdir(struct ncp_server *server,
932 struct inode *old_dir, char *old_name, 943 struct inode *old_dir, const char *old_name,
933 struct inode *new_dir, char *new_name) 944 struct inode *new_dir, const char *new_name)
934{ 945{
935 int result; 946 int result;
936 __le16 old_type = cpu_to_le16(0x06); 947 __le16 old_type = cpu_to_le16(0x06);
@@ -958,7 +969,7 @@ int
958ncp_read_kernel(struct ncp_server *server, const char *file_id, 969ncp_read_kernel(struct ncp_server *server, const char *file_id,
959 __u32 offset, __u16 to_read, char *target, int *bytes_read) 970 __u32 offset, __u16 to_read, char *target, int *bytes_read)
960{ 971{
961 char *source; 972 const char *source;
962 int result; 973 int result;
963 974
964 ncp_init_request(server); 975 ncp_init_request(server);
diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h
index 2441d1ab57dc..09881e6aa5ad 100644
--- a/fs/ncpfs/ncplib_kernel.h
+++ b/fs/ncpfs/ncplib_kernel.h
@@ -32,8 +32,6 @@
32#include <linux/ctype.h> 32#include <linux/ctype.h>
33#endif /* CONFIG_NCPFS_NLS */ 33#endif /* CONFIG_NCPFS_NLS */
34 34
35#include <linux/ncp_fs.h>
36
37#define NCP_MIN_SYMLINK_SIZE 8 35#define NCP_MIN_SYMLINK_SIZE 8
38#define NCP_MAX_SYMLINK_SIZE 512 36#define NCP_MAX_SYMLINK_SIZE 512
39 37
@@ -65,10 +63,11 @@ static inline void ncp_inode_close(struct inode *inode) {
65 atomic_dec(&NCP_FINFO(inode)->opened); 63 atomic_dec(&NCP_FINFO(inode)->opened);
66} 64}
67 65
68void ncp_extract_file_info(void* src, struct nw_info_struct* target); 66void ncp_extract_file_info(const void* src, struct nw_info_struct* target);
69int ncp_obtain_info(struct ncp_server *server, struct inode *, char *, 67int ncp_obtain_info(struct ncp_server *server, struct inode *, const char *,
70 struct nw_info_struct *target); 68 struct nw_info_struct *target);
71int ncp_obtain_nfs_info(struct ncp_server *server, struct nw_info_struct *target); 69int ncp_obtain_nfs_info(struct ncp_server *server, struct nw_info_struct *target);
70int ncp_update_known_namespace(struct ncp_server *server, __u8 volume, int *ret_ns);
72int ncp_get_volume_root(struct ncp_server *server, const char *volname, 71int ncp_get_volume_root(struct ncp_server *server, const char *volname,
73 __u32 *volume, __le32 *dirent, __le32 *dosdirent); 72 __u32 *volume, __le32 *dirent, __le32 *dosdirent);
74int ncp_lookup_volume(struct ncp_server *, const char *, struct nw_info_struct *); 73int ncp_lookup_volume(struct ncp_server *, const char *, struct nw_info_struct *);
@@ -80,8 +79,8 @@ int ncp_modify_nfs_info(struct ncp_server *, __u8 volnum, __le32 dirent,
80 __u32 mode, __u32 rdev); 79 __u32 mode, __u32 rdev);
81 80
82int ncp_del_file_or_subdir2(struct ncp_server *, struct dentry*); 81int ncp_del_file_or_subdir2(struct ncp_server *, struct dentry*);
83int ncp_del_file_or_subdir(struct ncp_server *, struct inode *, char *); 82int ncp_del_file_or_subdir(struct ncp_server *, struct inode *, const char *);
84int ncp_open_create_file_or_subdir(struct ncp_server *, struct inode *, char *, 83int ncp_open_create_file_or_subdir(struct ncp_server *, struct inode *, const char *,
85 int, __le32, __le16, struct ncp_entry_info *); 84 int, __le32, __le16, struct ncp_entry_info *);
86 85
87int ncp_initialize_search(struct ncp_server *, struct inode *, 86int ncp_initialize_search(struct ncp_server *, struct inode *,
@@ -93,7 +92,7 @@ int ncp_search_for_fileset(struct ncp_server *server,
93 char** rbuf, size_t* rsize); 92 char** rbuf, size_t* rsize);
94 93
95int ncp_ren_or_mov_file_or_subdir(struct ncp_server *server, 94int ncp_ren_or_mov_file_or_subdir(struct ncp_server *server,
96 struct inode *, char *, struct inode *, char *); 95 struct inode *, const char *, struct inode *, const char *);
97 96
98 97
99int 98int
@@ -134,7 +133,7 @@ int ncp__vol2io(struct ncp_server *, unsigned char *, unsigned int *,
134 const unsigned char *, unsigned int, int); 133 const unsigned char *, unsigned int, int);
135 134
136#define NCP_ESC ':' 135#define NCP_ESC ':'
137#define NCP_IO_TABLE(dentry) (NCP_SERVER((dentry)->d_inode)->nls_io) 136#define NCP_IO_TABLE(sb) (NCP_SBP(sb)->nls_io)
138#define ncp_tolower(t, c) nls_tolower(t, c) 137#define ncp_tolower(t, c) nls_tolower(t, c)
139#define ncp_toupper(t, c) nls_toupper(t, c) 138#define ncp_toupper(t, c) nls_toupper(t, c)
140#define ncp_strnicmp(t, s1, s2, len) \ 139#define ncp_strnicmp(t, s1, s2, len) \
@@ -149,15 +148,15 @@ int ncp__io2vol(unsigned char *, unsigned int *,
149int ncp__vol2io(unsigned char *, unsigned int *, 148int ncp__vol2io(unsigned char *, unsigned int *,
150 const unsigned char *, unsigned int, int); 149 const unsigned char *, unsigned int, int);
151 150
152#define NCP_IO_TABLE(dentry) NULL 151#define NCP_IO_TABLE(sb) NULL
153#define ncp_tolower(t, c) tolower(c) 152#define ncp_tolower(t, c) tolower(c)
154#define ncp_toupper(t, c) toupper(c) 153#define ncp_toupper(t, c) toupper(c)
155#define ncp_io2vol(S,m,i,n,k,U) ncp__io2vol(m,i,n,k,U) 154#define ncp_io2vol(S,m,i,n,k,U) ncp__io2vol(m,i,n,k,U)
156#define ncp_vol2io(S,m,i,n,k,U) ncp__vol2io(m,i,n,k,U) 155#define ncp_vol2io(S,m,i,n,k,U) ncp__vol2io(m,i,n,k,U)
157 156
158 157
159static inline int ncp_strnicmp(struct nls_table *t, const unsigned char *s1, 158static inline int ncp_strnicmp(const struct nls_table *t,
160 const unsigned char *s2, int len) 159 const unsigned char *s1, const unsigned char *s2, int len)
161{ 160{
162 while (len--) { 161 while (len--) {
163 if (tolower(*s1++) != tolower(*s2++)) 162 if (tolower(*s1++) != tolower(*s2++))
@@ -170,13 +169,13 @@ static inline int ncp_strnicmp(struct nls_table *t, const unsigned char *s1,
170#endif /* CONFIG_NCPFS_NLS */ 169#endif /* CONFIG_NCPFS_NLS */
171 170
172#define NCP_GET_AGE(dentry) (jiffies - (dentry)->d_time) 171#define NCP_GET_AGE(dentry) (jiffies - (dentry)->d_time)
173#define NCP_MAX_AGE(server) ((server)->dentry_ttl) 172#define NCP_MAX_AGE(server) atomic_read(&(server)->dentry_ttl)
174#define NCP_TEST_AGE(server,dentry) (NCP_GET_AGE(dentry) < NCP_MAX_AGE(server)) 173#define NCP_TEST_AGE(server,dentry) (NCP_GET_AGE(dentry) < NCP_MAX_AGE(server))
175 174
176static inline void 175static inline void
177ncp_age_dentry(struct ncp_server* server, struct dentry* dentry) 176ncp_age_dentry(struct ncp_server* server, struct dentry* dentry)
178{ 177{
179 dentry->d_time = jiffies - server->dentry_ttl; 178 dentry->d_time = jiffies - NCP_MAX_AGE(server);
180} 179}
181 180
182static inline void 181static inline void
@@ -192,7 +191,7 @@ ncp_renew_dentries(struct dentry *parent)
192 struct list_head *next; 191 struct list_head *next;
193 struct dentry *dentry; 192 struct dentry *dentry;
194 193
195 spin_lock(&dcache_lock); 194 spin_lock(&parent->d_lock);
196 next = parent->d_subdirs.next; 195 next = parent->d_subdirs.next;
197 while (next != &parent->d_subdirs) { 196 while (next != &parent->d_subdirs) {
198 dentry = list_entry(next, struct dentry, d_u.d_child); 197 dentry = list_entry(next, struct dentry, d_u.d_child);
@@ -204,7 +203,7 @@ ncp_renew_dentries(struct dentry *parent)
204 203
205 next = next->next; 204 next = next->next;
206 } 205 }
207 spin_unlock(&dcache_lock); 206 spin_unlock(&parent->d_lock);
208} 207}
209 208
210static inline void 209static inline void
@@ -214,7 +213,7 @@ ncp_invalidate_dircache_entries(struct dentry *parent)
214 struct list_head *next; 213 struct list_head *next;
215 struct dentry *dentry; 214 struct dentry *dentry;
216 215
217 spin_lock(&dcache_lock); 216 spin_lock(&parent->d_lock);
218 next = parent->d_subdirs.next; 217 next = parent->d_subdirs.next;
219 while (next != &parent->d_subdirs) { 218 while (next != &parent->d_subdirs) {
220 dentry = list_entry(next, struct dentry, d_u.d_child); 219 dentry = list_entry(next, struct dentry, d_u.d_child);
@@ -222,7 +221,7 @@ ncp_invalidate_dircache_entries(struct dentry *parent)
222 ncp_age_dentry(server, dentry); 221 ncp_age_dentry(server, dentry);
223 next = next->next; 222 next = next->next;
224 } 223 }
225 spin_unlock(&dcache_lock); 224 spin_unlock(&parent->d_lock);
226} 225}
227 226
228struct ncp_cache_head { 227struct ncp_cache_head {
diff --git a/fs/ncpfs/ncpsign_kernel.c b/fs/ncpfs/ncpsign_kernel.c
index 7c0b5c21e6cf..08907599dcd2 100644
--- a/fs/ncpfs/ncpsign_kernel.c
+++ b/fs/ncpfs/ncpsign_kernel.c
@@ -11,25 +11,26 @@
11#include <linux/string.h> 11#include <linux/string.h>
12#include <linux/ncp.h> 12#include <linux/ncp.h>
13#include <linux/bitops.h> 13#include <linux/bitops.h>
14#include "ncp_fs.h"
14#include "ncpsign_kernel.h" 15#include "ncpsign_kernel.h"
15 16
16/* i386: 32-bit, little endian, handles mis-alignment */ 17/* i386: 32-bit, little endian, handles mis-alignment */
17#ifdef __i386__ 18#ifdef __i386__
18#define GET_LE32(p) (*(int *)(p)) 19#define GET_LE32(p) (*(const int *)(p))
19#define PUT_LE32(p,v) { *(int *)(p)=v; } 20#define PUT_LE32(p,v) { *(int *)(p)=v; }
20#else 21#else
21/* from include/ncplib.h */ 22/* from include/ncplib.h */
22#define BVAL(buf,pos) (((__u8 *)(buf))[pos]) 23#define BVAL(buf,pos) (((const __u8 *)(buf))[pos])
23#define PVAL(buf,pos) ((unsigned)BVAL(buf,pos)) 24#define PVAL(buf,pos) ((unsigned)BVAL(buf,pos))
24#define BSET(buf,pos,val) (BVAL(buf,pos) = (val)) 25#define BSET(buf,pos,val) (((__u8 *)(buf))[pos] = (val))
25 26
26static inline __u16 27static inline __u16
27WVAL_LH(__u8 * buf, int pos) 28WVAL_LH(const __u8 * buf, int pos)
28{ 29{
29 return PVAL(buf, pos) | PVAL(buf, pos + 1) << 8; 30 return PVAL(buf, pos) | PVAL(buf, pos + 1) << 8;
30} 31}
31static inline __u32 32static inline __u32
32DVAL_LH(__u8 * buf, int pos) 33DVAL_LH(const __u8 * buf, int pos)
33{ 34{
34 return WVAL_LH(buf, pos) | WVAL_LH(buf, pos + 2) << 16; 35 return WVAL_LH(buf, pos) | WVAL_LH(buf, pos + 2) << 16;
35} 36}
diff --git a/fs/ncpfs/ncpsign_kernel.h b/fs/ncpfs/ncpsign_kernel.h
index 6451a68381cc..d9a1438bb1f6 100644
--- a/fs/ncpfs/ncpsign_kernel.h
+++ b/fs/ncpfs/ncpsign_kernel.h
@@ -8,8 +8,6 @@
8#ifndef _NCPSIGN_KERNEL_H 8#ifndef _NCPSIGN_KERNEL_H
9#define _NCPSIGN_KERNEL_H 9#define _NCPSIGN_KERNEL_H
10 10
11#include <linux/ncp_fs.h>
12
13#ifdef CONFIG_NCPFS_PACKET_SIGNING 11#ifdef CONFIG_NCPFS_PACKET_SIGNING
14void __sign_packet(struct ncp_server *server, const char *data, size_t size, __u32 totalsize, void *sign_buff); 12void __sign_packet(struct ncp_server *server, const char *data, size_t size, __u32 totalsize, void *sign_buff);
15int sign_verify_reply(struct ncp_server *server, const char *data, size_t size, __u32 totalsize, const void *sign_buff); 13int sign_verify_reply(struct ncp_server *server, const char *data, size_t size, __u32 totalsize, const void *sign_buff);
diff --git a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c
index c7ff6c700a6e..3a1587222c8a 100644
--- a/fs/ncpfs/sock.c
+++ b/fs/ncpfs/sock.c
@@ -28,7 +28,7 @@
28#include <linux/poll.h> 28#include <linux/poll.h>
29#include <linux/file.h> 29#include <linux/file.h>
30 30
31#include <linux/ncp_fs.h> 31#include "ncp_fs.h"
32 32
33#include "ncpsign_kernel.h" 33#include "ncpsign_kernel.h"
34 34
@@ -746,7 +746,6 @@ static int ncp_do_request(struct ncp_server *server, int size,
746 return -EIO; 746 return -EIO;
747 } 747 }
748 if (!ncp_conn_valid(server)) { 748 if (!ncp_conn_valid(server)) {
749 printk(KERN_ERR "ncpfs: Connection invalid!\n");
750 return -EIO; 749 return -EIO;
751 } 750 }
752 { 751 {
diff --git a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c
index c634fd17b337..661f861d80c6 100644
--- a/fs/ncpfs/symlink.c
+++ b/fs/ncpfs/symlink.c
@@ -25,13 +25,11 @@
25 25
26#include <linux/errno.h> 26#include <linux/errno.h>
27#include <linux/fs.h> 27#include <linux/fs.h>
28#include <linux/ncp_fs.h>
29#include <linux/time.h> 28#include <linux/time.h>
30#include <linux/slab.h> 29#include <linux/slab.h>
31#include <linux/mm.h> 30#include <linux/mm.h>
32#include <linux/stat.h> 31#include <linux/stat.h>
33#include "ncplib_kernel.h" 32#include "ncp_fs.h"
34
35 33
36/* these magic numbers must appear in the symlink file -- this makes it a bit 34/* these magic numbers must appear in the symlink file -- this makes it a bit
37 more resilient against the magic attributes being set on random files. */ 35 more resilient against the magic attributes being set on random files. */