summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-12-04 03:58:56 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-12-04 03:58:56 +0000
commit1d67e90f19a7acfd9a05dc59678e7d0c5090bd0d (patch)
tree357efc7b93f8f5102110d20d293f41360ec212fc /fs
parentaea27b2e18d69af87e673972246e66657b4fa274 (diff)
Merge with Linux 2.3.21.
Diffstat (limited to 'fs')
-rw-r--r--fs/Config.in3
-rw-r--r--fs/binfmt_elf.c12
-rw-r--r--fs/buffer.c44
-rw-r--r--fs/dcache.c78
-rw-r--r--fs/dquot.c3
-rw-r--r--fs/exec.c15
-rw-r--r--fs/fat/file.c4
-rw-r--r--fs/fcntl.c42
-rw-r--r--fs/inode.c431
-rw-r--r--fs/isofs/inode.c15
-rw-r--r--fs/ncpfs/Config.in20
-rw-r--r--fs/ncpfs/dir.c720
-rw-r--r--fs/ncpfs/file.c3
-rw-r--r--fs/ncpfs/inode.c169
-rw-r--r--fs/ncpfs/ioctl.c157
-rw-r--r--fs/ncpfs/ncplib_kernel.c21
-rw-r--r--fs/ncpfs/ncplib_kernel.h47
-rw-r--r--fs/ncpfs/ncpsign_kernel.h1
-rw-r--r--fs/ncpfs/sock.c2
-rw-r--r--fs/nfsd/nfsfh.c4
-rw-r--r--fs/open.c11
-rw-r--r--fs/partitions/msdos.c2
-rw-r--r--fs/proc/array.c16
-rw-r--r--fs/smbfs/cache.c79
-rw-r--r--fs/smbfs/file.c42
-rw-r--r--fs/sysv/inode.c25
-rw-r--r--fs/udf/inode.c2
27 files changed, 1001 insertions, 967 deletions
diff --git a/fs/Config.in b/fs/Config.in
index 9a6a53960..0c47f3165 100644
--- a/fs/Config.in
+++ b/fs/Config.in
@@ -59,6 +59,9 @@ fi
tristate 'ROM filesystem support' CONFIG_ROMFS_FS
tristate 'Second extended fs support' CONFIG_EXT2_FS
tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS
+if [ "$CONFIG_SYSV_FS" != "n" -a "$CONFIG_EXPERIMENTAL" ]; then
+ bool ' SYSV filesystem write support (DANGEROUS)' CONFIG_SYSV_FS_WRITE
+fi
tristate 'UFS filesystem support' CONFIG_UFS_FS
if [ "$CONFIG_UFS_FS" != "n" ]; then
bool ' UFS filesystem write support (experimental)' CONFIG_UFS_FS_WRITE
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index aa59a2f7f..089f83e82 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -423,13 +423,21 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
goto out;
if (!elf_check_arch(elf_ex.e_machine))
goto out;
-#ifdef __mips__
- /* IRIX binaries handled elsewhere. */
+#if defined(__mips__) && !defined(__mips64)
+ /* IRIX5 binaries handled elsewhere. */
if (elf_ex.e_flags & EF_MIPS_ARCH) {
retval = -ENOEXEC;
goto out;
}
#endif
+#if defined(__mips__) && defined(__mips64)
+ /* Linux/MIPS 32-bit binaries handled elsewhere. */
+ if (sizeof(elf_caddr_t) == 8 &&
+ elf_ex.e_ident[EI_CLASS] == ELFCLASS32) {
+ retval = -ENOEXEC;
+ goto out;
+ }
+#endif
if (!bprm->dentry->d_inode->i_op ||
!bprm->dentry->d_inode->i_op->default_file_ops ||
!bprm->dentry->d_inode->i_op->default_file_ops->mmap)
diff --git a/fs/buffer.c b/fs/buffer.c
index c4fefe5cc..d77dc86bc 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1205,6 +1205,18 @@ static int create_page_buffers(int rw, struct page *page, kdev_t dev, int b[], i
return 0;
}
+static void unmap_buffer(struct buffer_head * bh)
+{
+ if (buffer_mapped(bh))
+ {
+ mark_buffer_clean(bh);
+ wait_on_buffer(bh);
+ clear_bit(BH_Uptodate, &bh->b_state);
+ clear_bit(BH_Mapped, &bh->b_state);
+ clear_bit(BH_Req, &bh->b_state);
+ }
+}
+
/*
* We don't have to release all buffers here, but
* we have to be sure that no dirty buffer is left
@@ -1231,16 +1243,8 @@ int block_flushpage(struct inode *inode, struct page *page, unsigned long offset
/*
* is this block fully flushed?
*/
- if (offset <= curr_off) {
- if (buffer_mapped(bh)) {
- mark_buffer_clean(bh);
- wait_on_buffer(bh);
- clear_bit(BH_Uptodate, &bh->b_state);
- clear_bit(BH_Mapped, &bh->b_state);
- clear_bit(BH_Req, &bh->b_state);
- bh->b_blocknr = 0;
- }
- }
+ if (offset <= curr_off)
+ unmap_buffer(bh);
curr_off = next_off;
bh = next;
} while (bh != head);
@@ -1286,6 +1290,19 @@ static void create_empty_buffers(struct page *page, struct inode *inode, unsigne
get_page(page);
}
+static void unmap_underlying_metadata(struct buffer_head * bh)
+{
+ bh = get_hash_table(bh->b_dev, bh->b_blocknr, bh->b_size);
+ if (bh)
+ {
+ unmap_buffer(bh);
+ /* Here we could run brelse or bforget. We use
+ bforget because it will try to put the buffer
+ in the freelist. */
+ __bforget(bh);
+ }
+}
+
/*
* block_write_full_page() is SMP-safe - currently it's still
* being called with the kernel lock held, but the code is ready.
@@ -1331,6 +1348,7 @@ int block_write_full_page(struct file *file, struct page *page)
err = inode->i_op->get_block(inode, block, bh, 1);
if (err)
goto out;
+ unmap_underlying_metadata(bh);
}
set_bit(BH_Uptodate, &bh->b_state);
mark_buffer_dirty(bh,0);
@@ -1420,6 +1438,7 @@ int block_write_partial_page(struct file *file, struct page *page, unsigned long
err = inode->i_op->get_block(inode, block, bh, 1);
if (err)
goto out;
+ unmap_underlying_metadata(bh);
}
if (!buffer_uptodate(bh) && (start_offset || (end_bytes && (i == end_block)))) {
@@ -1512,8 +1531,8 @@ int block_write_cont_page(struct file *file, struct page *page, unsigned long of
char * target_buf, *target_data;
unsigned long data_offset = offset;
- offset = page->offset-inode->i_size;
- if (offset < 0)
+ offset = inode->i_size - page->offset;
+ if (page->offset>inode->i_size)
offset = 0;
else if (offset >= data_offset)
offset = data_offset;
@@ -1582,6 +1601,7 @@ int block_write_cont_page(struct file *file, struct page *page, unsigned long of
err = inode->i_op->get_block(inode, block, bh, 1);
if (err)
goto out;
+ unmap_underlying_metadata(bh);
}
if (!buffer_uptodate(bh) && (start_offset || (end_bytes && (i == end_block)))) {
diff --git a/fs/dcache.c b/fs/dcache.c
index cbdfcfaf5..ef45eba7d 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -42,7 +42,7 @@ kmem_cache_t *dentry_cache;
* This hash-function tries to avoid losing too many bits of hash
* information, yet avoid using a prime hash-size or similar.
*/
-#define D_HASHBITS 10
+#define D_HASHBITS 14
#define D_HASHSIZE (1UL << D_HASHBITS)
#define D_HASHMASK (D_HASHSIZE-1)
@@ -196,72 +196,6 @@ int d_invalidate(struct dentry * dentry)
}
/*
- * Select less valuable dentries to be pruned when we need
- * inodes or memory. The selected dentries are moved to the
- * old end of the list where prune_dcache() can find them.
- *
- * Negative dentries are included in the selection so that
- * they don't accumulate at the end of the list. The count
- * returned is the total number of dentries selected, which
- * may be much larger than the requested number of inodes.
- */
-int select_dcache(int inode_count, int page_count)
-{
- struct list_head *next, *tail = &dentry_unused;
- int found = 0;
- int depth = dentry_stat.nr_unused >> 1;
- unsigned long max_value = 4;
-
- if (page_count)
- max_value = -1;
-
- next = tail->prev;
- while (next != &dentry_unused && depth--) {
- struct list_head *tmp = next;
- struct dentry *dentry = list_entry(tmp, struct dentry, d_lru);
- struct inode *inode = dentry->d_inode;
- unsigned long value = 0;
-
- next = tmp->prev;
- if (dentry->d_count) {
- dentry_stat.nr_unused--;
- list_del(tmp);
- INIT_LIST_HEAD(tmp);
- continue;
- }
-
- /*
- * Select dentries based on the page cache count ...
- * should factor in number of uses as well. We take
- * all negative dentries so that they don't accumulate.
- * (We skip inodes that aren't immediately available.)
- */
- if (inode) {
- value = inode->i_nrpages;
- if (value >= max_value)
- continue;
- if (inode->i_state || inode->i_count > 1)
- continue;
- }
-
- /*
- * Move the selected dentries behind the tail.
- */
- if (tmp != tail->prev) {
- list_del(tmp);
- list_add(tmp, tail->prev);
- }
- tail = tmp;
- found++;
- if (inode && --inode_count <= 0)
- break;
- if (page_count && (page_count -= value) <= 0)
- break;
- }
- return found;
-}
-
-/*
* Throw away a dentry - free the inode, dput the parent.
* This requires that the LRU list has already been
* removed.
@@ -470,7 +404,7 @@ void shrink_dcache_parent(struct dentry * parent)
* ...
* 6 - base-level: try to shrink a bit.
*/
-void shrink_dcache_memory(int priority, unsigned int gfp_mask)
+int shrink_dcache_memory(int priority, unsigned int gfp_mask)
{
if (gfp_mask & __GFP_IO) {
int count = 0;
@@ -479,7 +413,15 @@ void shrink_dcache_memory(int priority, unsigned int gfp_mask)
count = dentry_stat.nr_unused / priority;
prune_dcache(count);
unlock_kernel();
+ /* FIXME: kmem_cache_shrink here should tell us
+ the number of pages freed, and it should
+ work in a __GFP_DMA/__GFP_BIGMEM behaviour
+ to free only the interesting pages in
+ function of the needs of the current allocation. */
+ kmem_cache_shrink(dentry_cache);
}
+
+ return 0;
}
#define NAME_ALLOC_LEN(len) ((len+16) & ~15)
diff --git a/fs/dquot.c b/fs/dquot.c
index d39a95b2c..2317af965 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -516,11 +516,10 @@ pressure:
/*
* Try pruning the dcache to free up some dquots ...
*/
- count = select_dcache(128, 0);
if (count) {
printk(KERN_DEBUG "get_empty_dquot: pruning %d\n", count);
prune_dcache(count);
- free_inode_memory(count);
+ prune_icache(count);
goto repeat;
}
diff --git a/fs/exec.c b/fs/exec.c
index 4d3295137..b3f31fd0a 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -169,7 +169,7 @@ out:
/*
* count() counts the number of arguments/envelopes
*/
-static int count(char ** argv)
+static int count(char ** argv, int max)
{
int i = 0;
@@ -184,7 +184,8 @@ static int count(char ** argv)
if (!p)
break;
argv++;
- i++;
+ if(++i > max)
+ return -E2BIG;
}
}
return i;
@@ -202,7 +203,7 @@ int copy_strings(int argc,char ** argv, struct linux_binprm *bprm)
int len;
unsigned long pos;
- if (get_user(str, argv+argc) || !str || !(len = strlen_user(str)))
+ if (get_user(str, argv+argc) || !str || !(len = strnlen_user(str, bprm->p)))
return -EFAULT;
if (bprm->p < len)
return -E2BIG;
@@ -211,7 +212,7 @@ int copy_strings(int argc,char ** argv, struct linux_binprm *bprm)
/* XXX: add architecture specific overflow check here. */
pos = bprm->p;
- while (len) {
+ while (len>0) {
char *pag;
int offset, bytes_to_copy;
@@ -274,7 +275,7 @@ int setup_arg_pages(struct linux_binprm *bprm)
mpnt->vm_ops = NULL;
mpnt->vm_offset = 0;
mpnt->vm_file = NULL;
- mpnt->vm_private_data = NULL;
+ mpnt->vm_private_data = (void *) 0;
insert_vm_struct(current->mm, mpnt);
current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
}
@@ -753,12 +754,12 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs
bprm.sh_bang = 0;
bprm.loader = 0;
bprm.exec = 0;
- if ((bprm.argc = count(argv)) < 0) {
+ if ((bprm.argc = count(argv, bprm.p / sizeof(void *))) < 0) {
dput(dentry);
return bprm.argc;
}
- if ((bprm.envc = count(envp)) < 0) {
+ if ((bprm.envc = count(envp, bprm.p / sizeof(void *))) < 0) {
dput(dentry);
return bprm.envc;
}
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 19b91b74f..5baa51af4 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -60,7 +60,7 @@ struct inode_operations fat_file_inode_operations = {
fat_get_block, /* get_block */
block_read_full_page, /* readpage */
NULL, /* writepage */
- NULL, /* flushpage */
+ block_flushpage, /* flushpage */
fat_truncate, /* truncate */
NULL, /* permission */
NULL, /* smap */
@@ -118,7 +118,7 @@ static int fat_write_partial_page(struct file *file, struct page *page, unsigned
unsigned long page_cache = 0;
long status;
- pgpos = inode->i_size & PAGE_CACHE_MASK;
+ pgpos = MSDOS_I(inode)->i_realsize & PAGE_CACHE_MASK;
while (pgpos < page->offset) {
hash = page_hash(inode, pgpos);
repeat_find: new_page = __find_lock_page(inode, pgpos, hash);
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 26c9bf4a0..255267da8 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -8,6 +8,8 @@
#include <linux/file.h>
#include <linux/smp_lock.h>
+#include <asm/poll.h>
+#include <asm/siginfo.h>
#include <asm/uaccess.h>
extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
@@ -255,8 +257,22 @@ out:
return err;
}
+/* Table to convert sigio signal codes into poll band bitmaps */
+
+static int band_table[NSIGPOLL+1] = {
+ ~0,
+ POLLIN | POLLRDNORM, /* POLL_IN */
+ POLLOUT | POLLWRNORM | POLLWRBAND, /* POLL_OUT */
+ POLLIN | POLLRDNORM | POLLMSG, /* POLL_MSG */
+ POLLERR, /* POLL_ERR */
+ POLLPRI | POLLRDBAND, /* POLL_PRI */
+ POLLHUP | POLLERR /* POLL_HUP */
+};
+
static void send_sigio_to_task(struct task_struct *p,
- struct fown_struct *fown, struct fasync_struct *fa)
+ struct fown_struct *fown,
+ struct fasync_struct *fa,
+ int reason)
{
if ((fown->euid != 0) &&
(fown->euid ^ p->suid) && (fown->euid ^ p->uid) &&
@@ -273,9 +289,11 @@ static void send_sigio_to_task(struct task_struct *p,
back to SIGIO in that case. --sct */
si.si_signo = fown->signum;
si.si_errno = 0;
- si.si_code = SI_SIGIO;
- si.si_pid = fown->pid;
- si.si_uid = fown->uid;
+ si.si_code = reason;
+ if (reason < 0 || reason > NSIGPOLL)
+ si.si_band = ~0;
+ else
+ si.si_band = band_table[reason];
si.si_fd = fa->fa_fd;
if (!send_sig_info(fown->signum, &si, p))
break;
@@ -285,14 +303,15 @@ static void send_sigio_to_task(struct task_struct *p,
}
}
-static void send_sigio(struct fown_struct *fown, struct fasync_struct *fa)
+static void send_sigio(struct fown_struct *fown, struct fasync_struct *fa,
+ int band)
{
struct task_struct * p;
int pid = fown->pid;
read_lock(&tasklist_lock);
if ( (pid > 0) && (p = find_task_by_pid(pid)) ) {
- send_sigio_to_task(p, fown, fa);
+ send_sigio_to_task(p, fown, fa, band);
goto out;
}
for_each_task(p) {
@@ -301,13 +320,13 @@ static void send_sigio(struct fown_struct *fown, struct fasync_struct *fa)
match = -p->pgrp;
if (pid != match)
continue;
- send_sigio_to_task(p, fown, fa);
+ send_sigio_to_task(p, fown, fa, band);
}
out:
read_unlock(&tasklist_lock);
}
-void kill_fasync(struct fasync_struct *fa, int sig)
+void kill_fasync(struct fasync_struct *fa, int sig, int band)
{
while (fa) {
struct fown_struct * fown;
@@ -317,8 +336,11 @@ void kill_fasync(struct fasync_struct *fa, int sig)
return;
}
fown = &fa->fa_file->f_owner;
- if (fown->pid)
- send_sigio(fown, fa);
+ /* Don't send SIGURG to processes which have not set a
+ queued signum: SIGURG has its own default signalling
+ mechanism. */
+ if (fown->pid && !(sig == SIGURG && fown->signum == 0))
+ send_sigio(fown, fa, band);
fa = fa->fa_next;
}
}
diff --git a/fs/inode.c b/fs/inode.c
index 66f76f927..55eddfde8 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -10,6 +10,7 @@
#include <linux/dcache.h>
#include <linux/init.h>
#include <linux/quotaops.h>
+#include <linux/slab.h>
/*
* New inode.c implementation.
@@ -21,6 +22,8 @@
* Famous last words.
*/
+/* inode dynamic allocation 1999, Andrea Arcangeli <andrea@suse.de> */
+
#define INODE_PARANOIA 1
/* #define INODE_DEBUG 1 */
@@ -28,7 +31,7 @@
* Inode lookup is no longer as critical as it used to be:
* most of the lookups are going to be through the dcache.
*/
-#define HASH_BITS 8
+#define HASH_BITS 14
#define HASH_SIZE (1UL << HASH_BITS)
#define HASH_MASK (HASH_SIZE-1)
@@ -36,9 +39,9 @@
* Each inode can be on two separate lists. One is
* the hash list of the inode, used for lookups. The
* other linked list is the "type" list:
- * "in_use" - valid inode, hashed if i_nlink > 0
- * "dirty" - valid inode, hashed if i_nlink > 0, dirty.
- * "unused" - ready to be re-used. Not hashed.
+ * "in_use" - valid inode, i_count > 0, i_nlink > 0
+ * "dirty" - as "in_use" but also dirty
+ * "unused" - valid inode, i_count = 0
*
* A "dirty" list is maintained for each super block,
* allowing for low-overhead inode sync() operations.
@@ -61,11 +64,36 @@ spinlock_t inode_lock = SPIN_LOCK_UNLOCKED;
*/
struct {
int nr_inodes;
- int nr_free_inodes;
+ int nr_unused;
int dummy[5];
} inodes_stat = {0, 0,};
-int max_inodes;
+static kmem_cache_t * inode_cachep;
+
+#define alloc_inode() \
+ ((struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL))
+#define destroy_inode(inode) kmem_cache_free(inode_cachep, (inode))
+
+/*
+ * These are initializations that only need to be done
+ * once, because the fields are idempotent across use
+ * of the inode, so let the slab aware of that.
+ */
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct inode * inode = (struct inode *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR)
+ {
+ memset(inode, 0, sizeof(*inode));
+ init_waitqueue_head(&inode->i_wait);
+ INIT_LIST_HEAD(&inode->i_hash);
+ INIT_LIST_HEAD(&inode->i_dentry);
+ sema_init(&inode->i_sem, 1);
+ spin_lock_init(&inode->i_shared_lock);
+ }
+}
/*
* Put the inode on the super block's dirty list.
@@ -118,20 +146,6 @@ static inline void wait_on_inode(struct inode *inode)
__wait_on_inode(inode);
}
-/*
- * These are initializations that only need to be done
- * once, because the fields are idempotent across use
- * of the inode..
- */
-static inline void init_once(struct inode * inode)
-{
- memset(inode, 0, sizeof(*inode));
- init_waitqueue_head(&inode->i_wait);
- INIT_LIST_HEAD(&inode->i_hash);
- INIT_LIST_HEAD(&inode->i_dentry);
- sema_init(&inode->i_sem, 1);
- spin_lock_init(&inode->i_shared_lock);
-}
static inline void write_inode(struct inode *inode)
{
@@ -147,7 +161,8 @@ static inline void sync_one(struct inode *inode)
spin_lock(&inode_lock);
} else {
list_del(&inode->i_list);
- list_add(&inode->i_list, &inode_in_use);
+ list_add(&inode->i_list,
+ inode->i_count ? &inode_in_use : &inode_unused);
/* Set I_LOCK, reset I_DIRTY */
inode->i_state ^= I_DIRTY | I_LOCK;
spin_unlock(&inode_lock);
@@ -233,6 +248,8 @@ void clear_inode(struct inode *inode)
{
if (inode->i_nrpages)
BUG();
+ if (!(inode->i_state & I_FREEING))
+ BUG();
wait_on_inode(inode);
if (IS_QUOTAINIT(inode))
DQUOT_DROP(inode);
@@ -243,35 +260,24 @@ void clear_inode(struct inode *inode)
}
/*
- * Dispose-list gets a local list, so it doesn't need to
- * worry about list corruption. It releases the inode lock
- * while clearing the inodes.
+ * Dispose-list gets a local list with local inodes in it, so it doesn't
+ * need to worry about list corruption and SMP locks.
*/
static void dispose_list(struct list_head * head)
{
- struct list_head *next;
- int count = 0;
+ struct list_head * inode_entry;
+ struct inode * inode;
- spin_unlock(&inode_lock);
- next = head->next;
- for (;;) {
- struct list_head * tmp = next;
- struct inode * inode;
+ while ((inode_entry = head->next) != head)
+ {
+ list_del(inode_entry);
- next = next->next;
- if (tmp == head)
- break;
- inode = list_entry(tmp, struct inode, i_list);
+ inode = list_entry(inode_entry, struct inode, i_list);
if (inode->i_nrpages)
truncate_inode_pages(inode, 0);
clear_inode(inode);
- count++;
+ destroy_inode(inode);
}
-
- /* Add them all to the unused list in one fell swoop */
- spin_lock(&inode_lock);
- list_splice(head, &inode_unused);
- inodes_stat.nr_free_inodes += count;
}
/*
@@ -280,7 +286,7 @@ static void dispose_list(struct list_head * head)
static int invalidate_list(struct list_head *head, struct super_block * sb, struct list_head * dispose)
{
struct list_head *next;
- int busy = 0;
+ int busy = 0, count = 0;
next = head->next;
for (;;) {
@@ -299,10 +305,13 @@ static int invalidate_list(struct list_head *head, struct super_block * sb, stru
list_del(&inode->i_list);
list_add(&inode->i_list, dispose);
inode->i_state |= I_FREEING;
+ count++;
continue;
}
busy = 1;
}
+ /* only unused inodes may be cached with i_count zero */
+ inodes_stat.nr_unused -= count;
return busy;
}
@@ -320,10 +329,12 @@ int invalidate_inodes(struct super_block * sb)
spin_lock(&inode_lock);
busy = invalidate_list(&inode_in_use, sb, &throw_away);
+ busy |= invalidate_list(&inode_unused, sb, &throw_away);
busy |= invalidate_list(&sb->s_dirty, sb, &throw_away);
- dispose_list(&throw_away);
spin_unlock(&inode_lock);
+ dispose_list(&throw_away);
+
return busy;
}
@@ -339,155 +350,84 @@ int invalidate_inodes(struct super_block * sb)
* dispose_list.
*/
#define CAN_UNUSE(inode) \
- (((inode)->i_count | (inode)->i_state | (inode)->i_nrpages) == 0)
+ (((inode)->i_state | (inode)->i_nrpages) == 0)
#define INODE(entry) (list_entry(entry, struct inode, i_list))
-static int free_inodes(void)
+void prune_icache(int goal)
{
- struct list_head list, *entry, *freeable = &list;
- int found = 0;
+ LIST_HEAD(list);
+ struct list_head *entry, *freeable = &list;
+ int count = 0;
+ struct inode * inode;
+
+ spin_lock(&inode_lock);
+ /* go simple and safe syncing everything before starting */
+ sync_all_inodes();
- INIT_LIST_HEAD(freeable);
- entry = inode_in_use.next;
- while (entry != &inode_in_use) {
+ entry = inode_unused.prev;
+ while (entry != &inode_unused)
+ {
struct list_head *tmp = entry;
- entry = entry->next;
- if (!CAN_UNUSE(INODE(tmp)))
+ entry = entry->prev;
+ inode = INODE(tmp);
+ if (!CAN_UNUSE(inode))
continue;
+ if (inode->i_count)
+ BUG();
list_del(tmp);
- list_del(&INODE(tmp)->i_hash);
- INIT_LIST_HEAD(&INODE(tmp)->i_hash);
+ list_del(&inode->i_hash);
+ INIT_LIST_HEAD(&inode->i_hash);
list_add(tmp, freeable);
- list_entry(tmp, struct inode, i_list)->i_state = I_FREEING;
- found = 1;
+ inode->i_state |= I_FREEING;
+ count++;
+ if (!--goal)
+ break;
}
+ inodes_stat.nr_unused -= count;
+ spin_unlock(&inode_lock);
- if (found)
- dispose_list(freeable);
-
- return found;
+ dispose_list(freeable);
}
-/*
- * Searches the inodes list for freeable inodes,
- * shrinking the dcache before (and possible after,
- * if we're low)
- */
-static void try_to_free_inodes(int goal)
+int shrink_icache_memory(int priority, int gfp_mask)
{
- /*
- * First stry to just get rid of unused inodes.
- *
- * If we can't reach our goal that way, we'll have
- * to try to shrink the dcache and sync existing
- * inodes..
- */
- free_inodes();
- goal -= inodes_stat.nr_free_inodes;
- if (goal > 0) {
- spin_unlock(&inode_lock);
- select_dcache(goal, 0);
- prune_dcache(goal);
- spin_lock(&inode_lock);
- sync_all_inodes();
- free_inodes();
+ if (gfp_mask & __GFP_IO)
+ {
+ int count = 0;
+
+ if (priority)
+ count = inodes_stat.nr_unused / priority;
+ prune_icache(count);
+ /* FIXME: kmem_cache_shrink here should tell us
+ the number of pages freed, and it should
+ work in a __GFP_DMA/__GFP_BIGMEM behaviour
+ to free only the interesting pages in
+ function of the needs of the current allocation. */
+ kmem_cache_shrink(inode_cachep);
}
-}
-/*
- * This is the externally visible routine for
- * inode memory management.
- */
-void free_inode_memory(int goal)
-{
- spin_lock(&inode_lock);
- free_inodes();
- spin_unlock(&inode_lock);
+ return 0;
}
-
-/*
- * This is called with the spinlock held, but releases
- * the lock when freeing or allocating inodes.
- * Look out! This returns with the inode lock held if
- * it got an inode..
- *
- * We do inode allocations two pages at a time to reduce
- * fragmentation.
- */
-#define INODE_PAGE_ORDER 1
-#define INODE_ALLOCATION_SIZE (PAGE_SIZE << INODE_PAGE_ORDER)
-#define INODES_PER_ALLOCATION (INODE_ALLOCATION_SIZE/sizeof(struct inode))
-
-static struct inode * grow_inodes(void)
+static inline void __iget(struct inode * inode)
{
- struct inode * inode;
-
- /*
- * Check whether to restock the unused list.
- */
- if (inodes_stat.nr_inodes > max_inodes) {
- struct list_head *tmp;
- try_to_free_inodes(inodes_stat.nr_inodes >> 2);
- tmp = inode_unused.next;
- if (tmp != &inode_unused) {
- inodes_stat.nr_free_inodes--;
- list_del(tmp);
- inode = list_entry(tmp, struct inode, i_list);
- return inode;
- }
- }
-
- spin_unlock(&inode_lock);
- inode = (struct inode *)__get_free_pages(GFP_KERNEL,INODE_PAGE_ORDER);
- if (inode) {
- int size;
- struct inode * tmp;
-
- size = INODE_ALLOCATION_SIZE - 2*sizeof(struct inode);
- tmp = inode;
- spin_lock(&inode_lock);
- do {
- tmp++;
- init_once(tmp);
- list_add(&tmp->i_list, &inode_unused);
- size -= sizeof(struct inode);
- } while (size >= 0);
- init_once(inode);
- /*
- * Update the inode statistics
- */
- inodes_stat.nr_inodes += INODES_PER_ALLOCATION;
- inodes_stat.nr_free_inodes += INODES_PER_ALLOCATION - 1;
- return inode;
- }
-
- /*
- * If the allocation failed, do an extensive pruning of
- * the dcache and then try again to free some inodes.
- */
- prune_dcache(inodes_stat.nr_inodes >> 2);
-
- spin_lock(&inode_lock);
- free_inodes();
+ if (!inode->i_count++)
{
- struct list_head *tmp = inode_unused.next;
- if (tmp != &inode_unused) {
- inodes_stat.nr_free_inodes--;
- list_del(tmp);
- inode = list_entry(tmp, struct inode, i_list);
- return inode;
+ if (!(inode->i_state & I_DIRTY))
+ {
+ list_del(&inode->i_list);
+ list_add(&inode->i_list, &inode_in_use);
}
+ inodes_stat.nr_unused--;
}
- spin_unlock(&inode_lock);
-
- printk("grow_inodes: allocation failed\n");
- return NULL;
}
/*
* Called with the inode lock held.
+ * NOTE: we are not increasing the inode-refcount, you must call __iget()
+ * by hand after calling find_inode now! This simplify iunique and won't
+ * add any additional branch in the common code.
*/
static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head)
{
@@ -505,7 +445,6 @@ static struct inode * find_inode(struct super_block * sb, unsigned long ino, str
continue;
if (inode->i_ino != ino)
continue;
- inode->i_count++;
break;
}
return inode;
@@ -518,7 +457,7 @@ static struct inode * find_inode(struct super_block * sb, unsigned long ino, str
* i_sb, i_ino, i_count, i_state and the lists have
* been initialized elsewhere..
*/
-void clean_inode(struct inode *inode)
+static void clean_inode(struct inode *inode)
{
memset(&inode->u, 0, sizeof(inode->u));
inode->i_sock = 0;
@@ -528,7 +467,6 @@ void clean_inode(struct inode *inode)
inode->i_size = 0;
inode->i_generation = 0;
memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
- sema_init(&inode->i_sem, 1);
inode->i_pipe = NULL;
}
@@ -542,15 +480,11 @@ struct inode * get_empty_inode(void)
{
static unsigned long last_ino = 0;
struct inode * inode;
- struct list_head * tmp;
- spin_lock(&inode_lock);
- tmp = inode_unused.next;
- if (tmp != &inode_unused) {
- list_del(tmp);
- inodes_stat.nr_free_inodes--;
- inode = list_entry(tmp, struct inode, i_list);
-add_new_inode:
+ inode = alloc_inode();
+ if (inode)
+ {
+ spin_lock(&inode_lock);
list_add(&inode->i_list, &inode_in_use);
inode->i_sb = NULL;
inode->i_dev = 0;
@@ -560,22 +494,12 @@ add_new_inode:
inode->i_state = 0;
spin_unlock(&inode_lock);
clean_inode(inode);
- return inode;
}
-
- /*
- * Warning: if this succeeded, we will now
- * return with the inode lock.
- */
- inode = grow_inodes();
- if (inode)
- goto add_new_inode;
-
return inode;
}
/*
- * This is called with the inode lock held.. Be careful.
+ * This is called without the inode lock held.. Be careful.
*
* We no longer cache the sb_flags in i_flags - see fs.h
* -- rmk@arm.uk.linux.org
@@ -583,56 +507,47 @@ add_new_inode:
static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, struct list_head *head)
{
struct inode * inode;
- struct list_head * tmp = inode_unused.next;
-
- if (tmp != &inode_unused) {
- list_del(tmp);
- inodes_stat.nr_free_inodes--;
- inode = list_entry(tmp, struct inode, i_list);
-add_new_inode:
- list_add(&inode->i_list, &inode_in_use);
- list_add(&inode->i_hash, head);
- inode->i_sb = sb;
- inode->i_dev = sb->s_dev;
- inode->i_ino = ino;
- inode->i_flags = 0;
- inode->i_count = 1;
- inode->i_state = I_LOCK;
- spin_unlock(&inode_lock);
- clean_inode(inode);
- sb->s_op->read_inode(inode);
-
- /*
- * This is special! We do not need the spinlock
- * when clearing I_LOCK, because we're guaranteed
- * that nobody else tries to do anything about the
- * state of the inode when it is locked, as we
- * just created it (so there can be no old holders
- * that haven't tested I_LOCK).
- */
- inode->i_state &= ~I_LOCK;
- wake_up(&inode->i_wait);
-
- return inode;
- }
-
- /*
- * We need to expand. Note that "grow_inodes()" will
- * release the spinlock, but will return with the lock
- * held again if the allocation succeeded.
- */
- inode = grow_inodes();
+ inode = alloc_inode();
if (inode) {
+ struct inode * old;
+
+ spin_lock(&inode_lock);
/* We released the lock, so.. */
- struct inode * old = find_inode(sb, ino, head);
+ old = find_inode(sb, ino, head);
if (!old)
- goto add_new_inode;
- list_add(&inode->i_list, &inode_unused);
- inodes_stat.nr_free_inodes++;
+ {
+ list_add(&inode->i_list, &inode_in_use);
+ list_add(&inode->i_hash, head);
+ inode->i_sb = sb;
+ inode->i_dev = sb->s_dev;
+ inode->i_ino = ino;
+ inode->i_flags = 0;
+ inode->i_count = 1;
+ inode->i_state = I_LOCK;
+ spin_unlock(&inode_lock);
+
+ clean_inode(inode);
+ sb->s_op->read_inode(inode);
+
+ /*
+ * This is special! We do not need the spinlock
+ * when clearing I_LOCK, because we're guaranteed
+ * that nobody else tries to do anything about the
+ * state of the inode when it is locked, as we
+ * just created it (so there can be no old holders
+ * that haven't tested I_LOCK).
+ */
+ inode->i_state &= ~I_LOCK;
+ wake_up(&inode->i_wait);
+
+ return inode;
+ }
+ __iget(inode);
spin_unlock(&inode_lock);
- wait_on_inode(old);
- return old;
+ destroy_inode(inode);
+ inode = old;
+ wait_on_inode(inode);
}
return inode;
}
@@ -660,7 +575,6 @@ retry:
spin_unlock(&inode_lock);
return res;
}
- inode->i_count--; /* compensate find_inode() */
} else {
counter = max_reserved + 1;
}
@@ -671,10 +585,10 @@ retry:
struct inode *igrab(struct inode *inode)
{
spin_lock(&inode_lock);
- if (inode->i_state & I_FREEING)
- inode = NULL;
+ if (!(inode->i_state & I_FREEING))
+ __iget(inode);
else
- inode->i_count++;
+ inode = NULL;
spin_unlock(&inode_lock);
if (inode)
wait_on_inode(inode);
@@ -689,14 +603,16 @@ struct inode *iget(struct super_block *sb, unsigned long ino)
spin_lock(&inode_lock);
inode = find_inode(sb, ino, head);
if (inode) {
+ __iget(inode);
spin_unlock(&inode_lock);
wait_on_inode(inode);
return inode;
}
+ spin_unlock(&inode_lock);
+
/*
- * get_new_inode() will do the right thing, releasing
- * the inode lock and re-trying the search in case it
- * had to block at any point.
+ * get_new_inode() will do the right thing, re-trying the search
+ * in case it had to block at any point.
*/
return get_new_inode(sb, ino, head);
}
@@ -721,6 +637,7 @@ void iput(struct inode *inode)
{
if (inode) {
struct super_operations *op = NULL;
+ int destroy = 0;
if (inode->i_sb && inode->i_sb->s_op)
op = inode->i_sb->s_op;
@@ -750,13 +667,17 @@ void iput(struct inode *inode)
inode->i_state|=I_FREEING;
spin_unlock(&inode_lock);
clear_inode(inode);
+ destroy = 1;
spin_lock(&inode_lock);
- list_add(&inode->i_list, &inode_unused);
- inodes_stat.nr_free_inodes++;
}
- else if (!(inode->i_state & I_DIRTY)) {
- list_del(&inode->i_list);
- list_add(&inode->i_list, &inode_in_use);
+ else
+ {
+ if (!(inode->i_state & I_DIRTY)) {
+ list_del(&inode->i_list);
+ list_add(&inode->i_list,
+ &inode_unused);
+ }
+ inodes_stat.nr_unused++;
}
#ifdef INODE_PARANOIA
if (inode->i_flock)
@@ -778,6 +699,8 @@ kdevname(inode->i_dev), inode->i_ino, atomic_read(&inode->i_sem.count));
kdevname(inode->i_dev), inode->i_ino);
}
spin_unlock(&inode_lock);
+ if (destroy)
+ destroy_inode(inode);
}
}
@@ -795,14 +718,11 @@ int bmap(struct inode * inode, int block)
}
/*
- * Initialize the hash tables and default
- * value for max inodes
+ * Initialize the hash tables.
*/
-#define MAX_INODE (16384)
-
void __init inode_init(void)
{
- int i, max;
+ int i;
struct list_head *head = inode_hashtable;
i = HASH_SIZE;
@@ -812,11 +732,12 @@ void __init inode_init(void)
i--;
} while (i);
- /* Initial guess at reasonable inode number */
- max = num_physpages >> 1;
- if (max > MAX_INODE)
- max = MAX_INODE;
- max_inodes = max;
+ /* inode slab cache */
+ inode_cachep = kmem_cache_create("inode_cache", sizeof(struct inode),
+ 0, SLAB_HWCACHE_ALIGN, init_once,
+ NULL);
+ if (!inode_cachep)
+ panic("cannot create inode slab cache");
}
void update_atime (struct inode *inode)
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index f055c52e0..8001c5186 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -446,6 +446,14 @@ static unsigned int isofs_get_last_session(kdev_t dev,s32 session )
inode_fake.i_rdev=dev;
init_waitqueue_head(&inode_fake.i_wait);
ms_info.addr_format=CDROM_LBA;
+ /* If a minor device was explicitly opened, set session to the
+ * minor number. For instance, if /dev/hdc1 is mounted, session
+ * 1 on the CD-ROM is selected. CD_PART_MAX gives access to
+ * a max of 64 sessions on IDE. SCSI drives must still use
+ * the session option to mount.
+ */
+ if ((MINOR(dev) % CD_PART_MAX) && (MAJOR(dev) != SCSI_CDROM_MAJOR))
+ session = MINOR(dev) % CD_PART_MAX;
set_fs(KERNEL_DS);
if(session >= 0 && session <= 99) {
struct cdrom_tocentry Te;
@@ -1042,6 +1050,7 @@ static int isofs_read_level3_size(struct inode * inode)
struct buffer_head * bh = NULL;
int block = 0;
int i = 0;
+ int more_entries = 0;
void *cpnt;
struct iso_directory_record * raw_inode;
@@ -1062,7 +1071,6 @@ static int isofs_read_level3_size(struct inode * inode)
goto out_noread;
}
pnt = ((unsigned char *) bh->b_data + offset);
- raw_inode = ((struct iso_directory_record *) pnt);
/*
* Note: this is invariant even if the record
* spans buffers and must be copied ...
@@ -1074,6 +1082,7 @@ static int isofs_read_level3_size(struct inode * inode)
ino = (ino & ~(ISOFS_BLOCK_SIZE - 1)) + ISOFS_BLOCK_SIZE;
continue;
}
+ raw_inode = ((struct iso_directory_record *) pnt);
/* Check whether the raw inode spans the buffer ... */
if (offset + reclen > bufsize){
@@ -1095,13 +1104,15 @@ static int isofs_read_level3_size(struct inode * inode)
inode->i_size += isonum_733 (raw_inode->size);
if(i == 1) inode->u.isofs_i.i_next_section_ino = ino;
+ more_entries = raw_inode->flags[-high_sierra] & 0x80;
+
ino += reclen;
if (cpnt)
kfree (cpnt);
i++;
if(i > 100)
goto out_toomany;
- } while(raw_inode->flags[-high_sierra] & 0x80);
+ } while(more_entries);
out:
brelse(bh);
return 0;
diff --git a/fs/ncpfs/Config.in b/fs/ncpfs/Config.in
index 11a1b1d36..5bbc29dc8 100644
--- a/fs/ncpfs/Config.in
+++ b/fs/ncpfs/Config.in
@@ -1,15 +1,15 @@
#
# NCP Filesystem configuration
#
-bool ' Packet signatures' CONFIG_NCPFS_PACKET_SIGNING
-bool ' Proprietary file locking' CONFIG_NCPFS_IOCTL_LOCKING
-bool ' Clear remove/delete inhibit when needed' CONFIG_NCPFS_STRONG
-bool ' Use NFS namespace if available' CONFIG_NCPFS_NFS_NS
-bool ' Use LONG (OS/2) namespace if available' CONFIG_NCPFS_OS2_NS
+bool ' Packet signatures' CONFIG_NCPFS_PACKET_SIGNING
+bool ' Proprietary file locking' CONFIG_NCPFS_IOCTL_LOCKING
+bool ' Clear remove/delete inhibit when needed' CONFIG_NCPFS_STRONG
+bool ' Use NFS namespace if available' CONFIG_NCPFS_NFS_NS
+bool ' Use LONG (OS/2) namespace if available' CONFIG_NCPFS_OS2_NS
if [ "$CONFIG_NCPFS_OS2_NS" = "y" ]; then
- bool ' Lowercase DOS filenames' CONFIG_NCPFS_SMALLDOS
+ bool ' Lowercase DOS filenames' CONFIG_NCPFS_SMALLDOS
fi
-bool ' Allow mounting of volume subdirectories' CONFIG_NCPFS_MOUNT_SUBDIR
-# bool ' NDS interserver authentication support' CONFIG_NCPFS_NDS_DOMAINS
-bool ' Use Native Language Support' CONFIG_NCPFS_NLS
-bool ' Enable symbolic links and execute flags' CONFIG_NCPFS_EXTRAS
+bool ' Allow mounting of volume subdirectories' CONFIG_NCPFS_MOUNT_SUBDIR
+# bool ' NDS interserver authentication support' CONFIG_NCPFS_NDS_DOMAINS
+bool ' Use Native Language Support' CONFIG_NCPFS_NLS
+bool ' Enable symbolic links and execute flags' CONFIG_NCPFS_EXTRAS
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index ee2886228..ea541e796 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -5,6 +5,7 @@
* Modified for big endian by J.F. Chadima and David S. Miller
* Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
* Modified 1998 Wolfram Pienkoss for NLS
+ * Modified 1999 Wolfram Pienkoss for directory caching
*
*/
@@ -25,24 +26,8 @@
#include "ncplib_kernel.h"
-struct ncp_dirent {
- struct nw_info_struct i;
- struct nw_search_sequence s; /* given back for i */
- unsigned long f_pos;
-};
-
-static kdev_t c_dev = 0;
-static unsigned long c_ino = 0;
-static int c_size;
-static int c_seen_eof;
-static int c_last_returned_index;
-static struct ncp_dirent *c_entry = NULL;
-static DECLARE_MUTEX(c_sem);
-
-static int ncp_read_volume_list(struct ncp_server *, int, int,
- struct ncp_dirent *);
-static int ncp_do_readdir(struct ncp_server *, struct dentry *, int, int,
- struct ncp_dirent *);
+static int ncp_read_volume_list(struct file *, void *, filldir_t);
+static int ncp_do_readdir(struct file *, void *, filldir_t);
static ssize_t ncp_dir_read(struct file *, char *, size_t, loff_t *);
static int ncp_readdir(struct file *, void *, filldir_t);
@@ -198,22 +183,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
}
}
-/*
- * Generate a unique inode number.
- */
-ino_t ncp_invent_inos(unsigned long n)
-{
- static ino_t ino = 2;
-
- if (ino + 2*n < ino)
- {
- /* wrap around */
- ino = 2;
- }
- ino += n;
- return ino;
-}
-
static inline int
ncp_single_volume(struct ncp_server *server)
{
@@ -226,16 +195,6 @@ static inline int ncp_is_server_root(struct inode *inode)
inode == inode->i_sb->s_root->d_inode);
}
-static inline void ncp_lock_dircache(void)
-{
- down(&c_sem);
-}
-
-static inline void ncp_unlock_dircache(void)
-{
- up(&c_sem);
-}
-
/*
* This is the callback when the dcache has a lookup hit.
@@ -344,67 +303,68 @@ ncp_lookup_validate(struct dentry * dentry, int flags)
{
struct ncp_server *server;
struct inode *dir = dentry->d_parent->d_inode;
- int down_case = 0;
- int val = 0,res;
+ int res, val = 0;
int len = dentry->d_name.len;
- struct ncpfs_inode_info finfo;
+ struct ncp_entry_info finfo;
__u8 __name[dentry->d_name.len + 1];
if (!dentry->d_inode || !dir)
- return 0;
+ goto finished;
server = NCP_SERVER(dir);
if (!ncp_conn_valid(server))
goto finished;
- strncpy(__name, dentry->d_name.name, len);
- __name[len] = '\0';
+ /*
+ * Inspired by smbfs:
+ * The default validation is based on dentry age:
+ * We set the max age at mount time. (But each
+ * successful server lookup renews the timestamp.)
+ */
+ val = NCP_TEST_AGE(server, dentry);
+ if (val)
+ goto finished;
#ifdef NCPFS_PARANOIA
-printk(KERN_DEBUG "ncp_lookup_validate: %s, len %d\n", __name, len);
+ printk(KERN_DEBUG "ncp_lookup_validate: %s/%s not valid, age=%ld\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name,
+ NCP_GET_AGE(dentry));
#endif
- /* If the file is in the dir cache, we do not have to ask the
- server. */
-
+ memcpy(__name, dentry->d_name.name, len);
+ __name[len] = '\0';
#ifdef NCPFS_PARANOIA
+printk(KERN_DEBUG "ncp_lookup_validate: %s, len %d\n", __name, len);
printk(KERN_DEBUG "ncp_lookup_validate: server lookup for %s/%s\n",
dentry->d_parent->d_name.name, __name);
#endif
- if (ncp_is_server_root(dir))
- {
- io2vol(server, __name, 1);
- down_case = 1;
- res = ncp_lookup_volume(server, __name,
- &(finfo.nw_info.i));
- } else
- {
- down_case = !ncp_preserve_case(dir);
- io2vol(server, __name, down_case);
- res = ncp_obtain_info(server, dir, __name,
- &(finfo.nw_info.i));
- }
+ if (ncp_is_server_root(dir)) {
+ io2vol(server, __name, 1);
+ res = ncp_lookup_volume(server, __name, &(finfo.i));
+ } else {
+ io2vol(server, __name, !ncp_preserve_case(dir));
+ res = ncp_obtain_info(server, dir, __name, &(finfo.i));
+ }
#ifdef NCPFS_PARANOIA
printk(KERN_DEBUG "ncp_lookup_validate: looked for %s/%s, res=%d\n",
dentry->d_parent->d_name.name, __name, res);
#endif
- /*
- * If we didn't find it, or if it has a different dirEntNum to
- * what we remember, it's not valid any more.
- */
- if (!res) {
- if (finfo.nw_info.i.dirEntNum == NCP_FINFO(dentry->d_inode)->dirEntNum)
- val=1;
+ /*
+ * If we didn't find it, or if it has a different dirEntNum to
+ * what we remember, it's not valid any more.
+ */
+ if (!res) {
+ if (finfo.i.dirEntNum == NCP_FINFO(dentry->d_inode)->dirEntNum)
+ val=1;
#ifdef NCPFS_PARANOIA
- else
- printk(KERN_DEBUG "ncp_lookup_validate: found, but dirEntNum changed\n");
+ else
+ printk(KERN_DEBUG "ncp_lookup_validate: found, but dirEntNum changed\n");
#endif
- vol2io(server, finfo.nw_info.i.entryName,
- !ncp_preserve_entry_case(dir,
- finfo.nw_info.i.NSCreator));
- ncp_update_inode2(dentry->d_inode, &finfo.nw_info);
- }
- if (!val) ncp_invalid_dir_cache(dir);
+ vol2io(server, finfo.i.entryName,
+ !ncp_preserve_entry_case(dir, finfo.i.NSCreator));
+ ncp_update_inode2(dentry->d_inode, &finfo);
+ ncp_new_dentry(dentry);
+ }
finished:
#ifdef NCPFS_PARANOIA
@@ -420,279 +380,341 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
struct dentry *dentry = filp->f_dentry;
struct inode *inode = dentry->d_inode;
struct ncp_server *server = NCP_SERVER(inode);
- struct ncp_dirent *entry = NULL;
- int result, i, index = 0;
+ int entries, result;
DDPRINTK(KERN_DEBUG "ncp_readdir: reading %s/%s, pos=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
(int) filp->f_pos);
- DDPRINTK(KERN_DEBUG "ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",
- inode->i_ino, c_ino);
result = -EIO;
if (!ncp_conn_valid(server))
- goto out;
-
- ncp_lock_dircache();
- result = -ENOMEM;
- if (c_entry == NULL) {
- i = sizeof(struct ncp_dirent) * NCP_READDIR_CACHE_SIZE;
- c_entry = (struct ncp_dirent *) vmalloc(i);
- if (c_entry == NULL) {
- printk(KERN_WARNING "ncp_readdir: no MEMORY for cache\n");
- goto finished;
- }
- }
+ goto finished;
result = 0;
if (filp->f_pos == 0) {
- ncp_invalid_dir_cache(inode);
- if (filldir(dirent, ".", 1, 0, inode->i_ino) < 0) {
+ if (filldir(dirent, ".", 1, 0, inode->i_ino))
goto finished;
- }
filp->f_pos = 1;
}
if (filp->f_pos == 1) {
if (filldir(dirent, "..", 2, 1,
- dentry->d_parent->d_inode->i_ino) < 0) {
+ dentry->d_parent->d_inode->i_ino))
goto finished;
- }
filp->f_pos = 2;
}
- if ((inode->i_dev == c_dev) && (inode->i_ino == c_ino)) {
- for (i = 0; i < c_size; i++) {
- if (filp->f_pos == c_entry[i].f_pos) {
- entry = &c_entry[i];
- c_last_returned_index = i;
- index = i;
- break;
- }
- }
- if ((entry == NULL) && c_seen_eof) {
- goto finished;
- }
+ if (ncp_is_server_root(inode)) {
+ entries = ncp_read_volume_list(filp, dirent, filldir);
+ DPRINTK(KERN_DEBUG "ncp_read_volume_list returned %d\n", entries);
+ } else {
+ entries = ncp_do_readdir(filp, dirent, filldir);
+ DPRINTK(KERN_DEBUG "ncp_readdir: returned %d\n", entries);
}
- if (entry == NULL) {
- int entries;
- DDPRINTK(KERN_DEBUG "ncp_readdir: Not found in cache.\n");
- if (ncp_is_server_root(inode)) {
- entries = ncp_read_volume_list(server, filp->f_pos,
- NCP_READDIR_CACHE_SIZE, c_entry);
- DPRINTK(KERN_DEBUG "ncp_read_volume_list returned %d\n", entries);
+ if (entries < 0)
+ result = entries;
- } else {
- entries = ncp_do_readdir(server, dentry, filp->f_pos,
- NCP_READDIR_CACHE_SIZE, c_entry);
- DPRINTK(KERN_DEBUG "ncp_readdir: returned %d\n", entries);
- }
+finished:
+ return result;
+}
- if (entries < 0) {
- c_dev = 0;
- c_ino = 0;
- result = entries;
- goto finished;
+static int
+ncp_do_simple_filldir(struct file *filp, char* name, int len,
+ void* dirent, filldir_t filldir)
+{
+ struct dentry *dentry = filp->f_dentry;
+ struct qstr qname;
+ ino_t ino = 0;
+ int result;
+
+ qname.name = name;
+ qname.len = len;
+
+ ino = find_inode_number(dentry, &qname);
+
+ if (!ino)
+ ino = iunique(dentry->d_inode->i_sb, 2);
+
+ result = filldir(dirent, name, len, filp->f_pos, ino);
+ if (!result)
+ filp->f_pos += 1;
+
+ return result;
+}
+
+static int
+ncp_do_filldir(struct file *filp, struct ncp_entry_info *entry, void *dirent,
+ filldir_t filldir)
+{
+ struct dentry *dentry = filp->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ struct qstr qname;
+ ino_t ino = 0;
+ int result;
+
+ /* For getwd() we have to return the correct inode in d_ino if the
+ * inode is currently in use. Otherwise the inode number does not
+ * matter. (You can argue a lot about this..)
+ */
+ qname.name = entry->i.entryName;
+ qname.len = entry->i.nameLen;
+
+ {
+ struct dentry *newdent;
+ struct inode *newino;
+
+ qname.hash = full_name_hash(qname.name, qname.len);
+ if (dentry->d_op && dentry->d_op->d_hash)
+ if (dentry->d_op->d_hash(dentry, &qname) != 0)
+ goto end_advance;
+
+ newdent = d_lookup(dentry, &qname);
+
+ if (!newdent) {
+ newdent = d_alloc(dentry, &qname);
+ if (!newdent)
+ goto end_advance;
}
- if (entries > 0) {
- c_seen_eof = (entries < NCP_READDIR_CACHE_SIZE);
- c_dev = inode->i_dev;
- c_ino = inode->i_ino;
- c_size = entries;
- entry = c_entry;
- c_last_returned_index = 0;
- index = 0;
-
- for (i = 0; i < c_size; i++)
- {
- vol2io(server, c_entry[i].i.entryName,
- !ncp_preserve_entry_case(inode,
- c_entry[i].i.NSCreator));
+
+ if (!newdent->d_inode) {
+ entry->opened = 0;
+ entry->ino = iunique(inode->i_sb, 2);
+ newino = ncp_iget(inode->i_sb, entry);
+ if (newino) {
+ newdent->d_op = &ncp_dentry_operations;
+ d_add(newdent, newino);
+ ncp_new_dentry(newdent);
}
+ } else {
+ ncp_update_inode2(newdent->d_inode, entry);
+ ncp_new_dentry(newdent);
}
- }
- if (entry == NULL) {
- /* Nothing found, even from a ncp call */
- goto finished;
- }
- while (index < c_size) {
- ino_t ino;
- struct qstr qname;
+ if (newdent->d_inode)
+ ino = newdent->d_inode->i_ino;
- DDPRINTK(KERN_DEBUG "ncp_readdir: entry->path= %s\n", entry->i.entryName);
- DDPRINTK(KERN_DEBUG "ncp_readdir: entry->f_pos = %ld\n", entry->f_pos);
+ dput(newdent);
- /* For getwd() we have to return the correct
- * inode in d_ino if the inode is currently in
- * use. Otherwise the inode number does not
- * matter. (You can argue a lot about this..)
- */
- qname.name = entry->i.entryName;
- qname.len = entry->i.nameLen;
+end_advance:
+ }
+ if (!ino)
ino = find_inode_number(dentry, &qname);
- if (!ino)
- ino = ncp_invent_inos(1);
- if (filldir(dirent, entry->i.entryName, entry->i.nameLen,
- entry->f_pos, ino) < 0) {
- break;
- }
- if ((inode->i_dev != c_dev)
- || (inode->i_ino != c_ino)
- || (entry->f_pos != filp->f_pos)) {
- /* Someone has destroyed the cache while we slept
- in filldir */
- break;
- }
+ if (!ino)
+ ino = iunique(inode->i_sb, 2);
+
+ result = filldir(dirent, entry->i.entryName, entry->i.nameLen,
+ filp->f_pos, ino);
+ if (!result)
filp->f_pos += 1;
- index += 1;
- entry += 1;
- }
- finished:
- ncp_unlock_dircache();
-out:
+
return result;
}
static int
-ncp_read_volume_list(struct ncp_server *server, int fpos,
- int cache_size, struct ncp_dirent *entry)
+ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir)
{
- int i, total_count = 2;
+ struct dentry *dentry = filp->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ struct ncp_server *server = NCP_SERVER(inode);
struct ncp_volume_info info;
+ struct ncp_entry_info entry;
+ unsigned long total_count = 2, fpos = filp->f_pos;
+ int i;
- DPRINTK(KERN_DEBUG "ncp_read_volume_list: pos=%d\n", fpos);
-#if 1
- if (fpos < 2) {
- printk(KERN_ERR "OOPS, we expect fpos >= 2");
- fpos = 2;
- }
-#endif
+ DPRINTK(KERN_DEBUG "ncp_read_volume_list: pos=%ld\n", fpos);
for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
if (ncp_get_volume_info_with_number(server, i, &info) != 0)
- goto out;
+ break;
if (!strlen(info.volume_name))
continue;
if (total_count < fpos) {
DPRINTK(KERN_DEBUG "ncp_read_volume_list: skipped vol: %s\n",
info.volume_name);
- } else if (total_count >= fpos + cache_size) {
- goto out;
} else {
DPRINTK(KERN_DEBUG "ncp_read_volume_list: found vol: %s\n",
info.volume_name);
if (ncp_lookup_volume(server, info.volume_name,
- &(entry->i)) != 0) {
+ &entry.i)) {
DPRINTK(KERN_DEBUG "ncpfs: could not lookup vol %s\n",
info.volume_name);
continue;
}
- entry->f_pos = total_count;
- entry += 1;
+ vol2io(server, entry.i.entryName,
+ !ncp_preserve_entry_case(inode, entry.i.NSCreator));
+ if (ncp_do_filldir(filp, &entry, dirent, filldir))
+ break;
}
total_count += 1;
}
-out:
+
return (total_count - fpos);
}
-static int ncp_do_readdir(struct ncp_server *server, struct dentry *dentry,
- int fpos, int cache_size, struct ncp_dirent *entry)
+static int ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
+ struct dentry *dentry = filp->f_dentry;
struct inode *dir = dentry->d_inode;
- static struct inode *last_dir;
- static int total_count;
- static struct nw_search_sequence seq;
+ struct ncp_server *server = NCP_SERVER(dir);
+ struct ncp_seq_cache *cache = NULL;
+ struct ncp_cache_control ctl;
+ struct ncp_entry_info entry;
+ struct page *page, **hash;
+ unsigned long total_count = 0, fpos = filp->f_pos;
int err;
-#if 1
- if (fpos < 2) {
- printk(KERN_ERR "OOPS, we expect fpos >= 2");
- fpos = 2;
- }
-#endif
- DPRINTK(KERN_DEBUG "ncp_do_readdir: %s/%s, fpos=%d\n",
+ DPRINTK(KERN_DEBUG "ncp_do_readdir: %s/%s, fpos=%ld\n",
dentry->d_parent->d_name.name, dentry->d_name.name, fpos);
- if (fpos == 2) {
- last_dir = NULL;
- total_count = 2;
+#ifdef NCPFS_DEBUG_VERBOSE
+printk("ncp_do_readdir: finding cache for %s/%s\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+
+ /* cache using inspired by smbfs and nfs */
+ hash = page_hash(dir, 0);
+
+ page = __find_lock_page(dir, 0, hash);
+
+ if (!page) {
+ unsigned long page_cache;
+
+ page_cache = page_cache_alloc();
+ if (page_cache) {
+ page = page_cache_entry(page_cache);
+ if (add_to_page_cache_unique(page, dir, 0, hash)) {
+ page_cache_release(page);
+ page = NULL;
+ page_cache_free(page_cache);
+ }
+ }
}
- if ((fpos != total_count) || (dir != last_dir))
+
+ if (!page)
+ goto start_search;
+
+ cache = (struct ncp_seq_cache *) page_address(page);
+ ctl = cache->ctl;
+
+ if (!Page_Uptodate(page))
+ ctl.currentpos = NCP_FPOS_EMPTY;
+
+ if ((fpos == 2) || (fpos < ctl.firstcache))
+ ctl.currentpos = NCP_FPOS_EMPTY;
+
+ if (ctl.currentpos == NCP_FPOS_EMPTY)
+ goto start_search;
+
{
- total_count = 2;
- last_dir = dir;
+ int fetchpos = ctl.cachehead;
+ int readpos = ctl.firstcache;
+ while (readpos < fpos) {
+ fetchpos += cache->cache[fetchpos] + 1;
+ readpos++;
+ }
+ while (fpos < ctl.currentpos) {
+ err = ncp_do_simple_filldir(filp,
+ (char*)(cache->cache+fetchpos+1),
+ cache->cache[fetchpos],
+ dirent, filldir);
+ if (err)
+ goto out;
+ fetchpos += cache->cache[fetchpos] + 1;
+ fpos++;
+ total_count++;
+ }
+ }
+
+start_search:
+
+ DDPRINTK(KERN_DEBUG "ncp_do_readdir: %s: f_pos=%ld,total_count=%ld\n",
+ dentry->d_name.name, fpos, total_count);
+
+ if (ctl.currentpos == NCP_FPOS_EMPTY) {
#ifdef NCPFS_PARANOIA
printk(KERN_DEBUG "ncp_do_readdir: init %s, volnum=%d, dirent=%u\n",
dentry->d_name.name, NCP_FINFO(dir)->volNumber, NCP_FINFO(dir)->dirEntNum);
#endif
- err = ncp_initialize_search(server, dir, &seq);
- if (err)
- {
+ err = ncp_initialize_search(server, dir, &ctl.seq);
+ if (err) {
DPRINTK(KERN_DEBUG "ncp_do_readdir: init failed, err=%d\n", err);
goto out;
}
- }
+ ctl.eof = 0;
+ ctl.cachehead = ctl.cachetail = 0;
+ ctl.firstcache = ctl.currentpos = 2;
+ } else
+ DDPRINTK(KERN_DEBUG "ncp_do_readdir: reused seq for %s, fpos=%li\n",
+ dentry->d_name.name, total_count);
- while (total_count < fpos + cache_size) {
- err = ncp_search_for_file_or_subdir(server, &seq, &(entry->i));
+ for (;;) {
+ err = ncp_search_for_file_or_subdir(server, &ctl.seq,
+ &entry.i);
if (err) {
DPRINTK(KERN_DEBUG "ncp_do_readdir: search failed, err=%d\n", err);
- goto out;
+ ctl.eof = 1;
+ break;
}
- if (total_count < fpos) {
+
+ ctl.currentpos++;
+
+ vol2io(server, entry.i.entryName,
+ !ncp_preserve_entry_case(dir, entry.i.NSCreator));
+
+ if (page) {
+ int tlen = ctl.cachetail + entry.i.nameLen + 1;
+
+ if (tlen > NCP_DIRCACHE_SIZE) {
+ int ofs = ctl.cachehead;
+
+ while (tlen - ofs > NCP_DIRCACHE_SIZE) {
+ ofs += cache->cache[ofs] + 1;
+ ctl.firstcache++;
+ }
+ ctl.cachetail -= ofs;
+ memmove(cache->cache+0,
+ cache->cache+ofs,
+ ctl.cachetail);
+ }
+ cache->cache[ctl.cachetail++] = entry.i.nameLen;
+ memcpy(cache->cache+ctl.cachetail,
+ entry.i.entryName, entry.i.nameLen);
+ ctl.cachetail += entry.i.nameLen;
+ }
+ if (ctl.currentpos < fpos) {
DPRINTK(KERN_DEBUG "ncp_do_readdir: skipped file: %s/%s\n",
- dentry->d_name.name, entry->i.entryName);
+ dentry->d_name.name, entry.i.entryName);
} else {
- DDPRINTK(KERN_DEBUG "ncp_do_r: file: %s, f_pos=%d,total_count=%d",
- entry->i.entryName, fpos, total_count);
- entry->s = seq;
- entry->f_pos = total_count;
- entry += 1;
+ DDPRINTK(KERN_DEBUG "ncp_do_r: file: %s, f_pos=%ld,total_count=%ld",
+ entry.i.entryName, fpos, total_count);
+ if (ncp_do_filldir(filp, &entry, dirent, filldir))
+ break;
}
- total_count += 1;
+ total_count++;
+ fpos++;
}
out:
- return (total_count - fpos);
-}
-
-void ncp_init_dir_cache(void)
-{
- c_dev = 0;
- c_ino = 0;
- c_entry = NULL;
-}
-
-void ncp_invalid_dir_cache(struct inode *ino)
-{
- if ((ino->i_dev == c_dev) && (ino->i_ino == c_ino)) {
- c_dev = 0;
- c_ino = 0;
- c_seen_eof = 0;
- }
-}
-
-void ncp_free_dir_cache(void)
-{
- DPRINTK(KERN_DEBUG "ncp_free_dir_cache: enter\n");
-
- if (c_entry == NULL) {
- return;
+ if (page) {
+ cache->ctl = ctl;
+ SetPageUptodate(page);
+ UnlockPage(page);
+ page_cache_release(page);
}
- vfree(c_entry);
- c_entry = NULL;
- DPRINTK(KERN_DEBUG "ncp_free_dir_cache: exit\n");
+ DDPRINTK(KERN_DEBUG "ncp_do_readdir: %s: return=%ld\n",
+ dentry->d_name.name, total_count);
+ return total_count;
}
-int ncp_conn_logged_in(struct ncp_server *server)
+int ncp_conn_logged_in(struct super_block *sb)
{
+ struct ncp_server* server = NCP_SBP(sb);
+ struct nw_info_struct i;
int result;
if (ncp_single_volume(server)) {
@@ -700,26 +722,25 @@ int ncp_conn_logged_in(struct ncp_server *server)
result = -ENOENT;
io2vol(server, server->m.mounted_vol, 1);
- if (ncp_lookup_volume(server, server->m.mounted_vol,
- &(server->root.finfo.i)) != 0) {
+ if (ncp_lookup_volume(server, server->m.mounted_vol, &i)) {
#ifdef NCPFS_PARANOIA
printk(KERN_DEBUG "ncp_conn_logged_in: %s not found\n", server->m.mounted_vol);
#endif
goto out;
}
- vol2io(server, server->root.finfo.i.entryName, 1);
- dent = server->root_dentry;
+ vol2io(server, i.entryName, 1);
+ dent = sb->s_root;
if (dent) {
struct inode* ino = dent->d_inode;
if (ino) {
- NCP_FINFO(ino)->volNumber = server->root.finfo.i.volNumber;
- NCP_FINFO(ino)->dirEntNum = server->root.finfo.i.dirEntNum;
- NCP_FINFO(ino)->DosDirNum = server->root.finfo.i.DosDirNum;
+ NCP_FINFO(ino)->volNumber = i.volNumber;
+ NCP_FINFO(ino)->dirEntNum = i.dirEntNum;
+ NCP_FINFO(ino)->DosDirNum = i.DosDirNum;
} else {
- DPRINTK(KERN_DEBUG "ncpfs: sb->root_dentry->d_inode == NULL!\n");
+ DPRINTK(KERN_DEBUG "ncpfs: sb->s_root->d_inode == NULL!\n");
}
} else {
- DPRINTK(KERN_DEBUG "ncpfs: sb->root_dentry == NULL!\n");
+ DPRINTK(KERN_DEBUG "ncpfs: sb->s_root == NULL!\n");
}
}
result = 0;
@@ -732,10 +753,8 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry)
{
struct ncp_server *server;
struct inode *inode = NULL;
- int found_in_cache, down_case = 0;
- int error;
- int len = dentry->d_name.len;
- struct ncpfs_inode_info finfo;
+ int error, res, len = dentry->d_name.len;
+ struct ncp_entry_info finfo;
__u8 __name[dentry->d_name.len + 1];
server = NCP_SERVER(dir);
@@ -744,88 +763,46 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry)
if (!ncp_conn_valid(server))
goto finished;
- strncpy(__name, dentry->d_name.name, len);
+ memcpy(__name, dentry->d_name.name, len);
__name[len] = '\0';
#ifdef NCPFS_PARANOIA
printk(KERN_DEBUG "ncp_lookup: %s, len %d\n", __name, len);
-#endif
-
- /* If the file is in the dir cache, we do not have to ask the
- server. */
-
- found_in_cache = 0;
- ncp_lock_dircache();
-
- if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino))
- {
- int first = c_last_returned_index;
- int i;
-
- i = first;
- do {
-#ifdef NCPFS_PARANOIA
-printk(KERN_DEBUG "ncp_lookup: trying index: %d, name: %s\n", i, c_entry[i].i.entryName);
-#endif
- if (strcmp(c_entry[i].i.entryName, __name) == 0) {
-#ifdef NCPFS_PARANOIA
-printk(KERN_DEBUG "ncp_lookup: found in cache!\n");
-#endif
- finfo.nw_info.i = c_entry[i].i;
- found_in_cache = 1;
- break;
- }
- i = (i + 1) % c_size;
- } while (i != first);
- }
- ncp_unlock_dircache();
-
- if (found_in_cache == 0)
- {
- int res;
-
-#ifdef NCPFS_PARANOIA
printk(KERN_DEBUG "ncp_lookup: server lookup for %s/%s\n",
dentry->d_parent->d_name.name, __name);
#endif
- if (ncp_is_server_root(dir))
- {
- io2vol(server, __name, 1);
- down_case = 1;
- res = ncp_lookup_volume(server, __name,
- &(finfo.nw_info.i));
- } else
- {
- down_case = !ncp_preserve_case(dir);
- io2vol(server, __name, down_case);
- res = ncp_obtain_info(server, dir, __name,
- &(finfo.nw_info.i));
- }
+ if (ncp_is_server_root(dir)) {
+ io2vol(server, __name, 1);
+ res = ncp_lookup_volume(server, __name, &(finfo.i));
+ } else {
+ io2vol(server, __name, !ncp_preserve_case(dir));
+ res = ncp_obtain_info(server, dir, __name, &(finfo.i));
+ }
#ifdef NCPFS_PARANOIA
printk(KERN_DEBUG "ncp_lookup: looked for %s/%s, res=%d\n",
dentry->d_parent->d_name.name, __name, res);
#endif
- /*
- * If we didn't find an entry, make a negative dentry.
- */
- if (res != 0) {
- goto add_entry;
- } else vol2io(server, finfo.nw_info.i.entryName,
- !ncp_preserve_entry_case(dir,
- finfo.nw_info.i.NSCreator));
- }
+ /*
+ * If we didn't find an entry, make a negative dentry.
+ */
+ if (res)
+ goto add_entry;
+
+ vol2io(server, finfo.i.entryName,
+ !ncp_preserve_entry_case(dir, finfo.i.NSCreator));
/*
* Create an inode for the entry.
*/
- finfo.nw_info.opened = 0;
- finfo.ino = ncp_invent_inos(1);
+ finfo.opened = 0;
+ finfo.ino = iunique(dir->i_sb, 2);
error = -EACCES;
inode = ncp_iget(dir->i_sb, &finfo);
- if (inode)
- {
- add_entry:
+
+ if (inode) {
+add_entry:
dentry->d_op = &ncp_dentry_operations;
d_add(dentry, inode);
+ ncp_new_dentry(dentry);
error = 0;
}
@@ -840,14 +817,12 @@ printk(KERN_DEBUG "ncp_lookup: result=%d\n", error);
* This code is common to create, mkdir, and mknod.
*/
static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
- struct ncpfs_inode_info *finfo)
+ struct ncp_entry_info *finfo)
{
struct inode *inode;
int error = -EINVAL;
- ncp_invalid_dir_cache(dir);
-
- finfo->ino = ncp_invent_inos(1);
+ finfo->ino = iunique(dir->i_sb, 2);
inode = ncp_iget(dir->i_sb, finfo);
if (!inode)
goto out_close;
@@ -861,7 +836,7 @@ out_close:
printk(KERN_DEBUG "ncp_instantiate: %s/%s failed, closing file\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
#endif
- ncp_close_file(NCP_SERVER(dir), finfo->nw_info.file_handle);
+ ncp_close_file(NCP_SERVER(dir), finfo->file_handle);
goto out;
}
@@ -869,7 +844,8 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode,
int attributes)
{
int error, result;
- struct ncpfs_inode_info finfo;
+ struct ncp_entry_info finfo;
+ struct ncp_server *server = NCP_SERVER(dir);
__u8 _name[dentry->d_name.len + 1];
#ifdef NCPFS_PARANOIA
@@ -877,20 +853,22 @@ printk(KERN_DEBUG "ncp_create_new: creating %s/%s, mode=%x\n",
dentry->d_parent->d_name.name, dentry->d_name.name, mode);
#endif
error = -EIO;
- if (!ncp_conn_valid(NCP_SERVER(dir)))
+ if (!ncp_conn_valid(server))
goto out;
- strncpy(_name, dentry->d_name.name, dentry->d_name.len);
+ ncp_age_dentry(server, dentry);
+
+ memcpy(_name, dentry->d_name.name, dentry->d_name.len);
_name[dentry->d_name.len] = '\0';
- io2vol(NCP_SERVER(dir), _name, !ncp_preserve_case(dir));
+ io2vol(server, _name, !ncp_preserve_case(dir));
error = -EACCES;
- result = ncp_open_create_file_or_subdir(NCP_SERVER(dir), dir, _name,
+ result = ncp_open_create_file_or_subdir(server, dir, _name,
OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
- attributes, AR_READ | AR_WRITE, &finfo.nw_info);
+ attributes, AR_READ | AR_WRITE, &finfo);
if (!result) {
- finfo.nw_info.access = O_RDWR;
+ finfo.access = O_RDWR;
error = ncp_instantiate(dir, dentry, &finfo);
} else {
if (result == 0x87) error = -ENAMETOOLONG;
@@ -910,23 +888,26 @@ static int ncp_create(struct inode *dir, struct dentry *dentry, int mode)
static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
int error;
- struct ncpfs_inode_info finfo;
+ struct ncp_entry_info finfo;
+ struct ncp_server *server = NCP_SERVER(dir);
__u8 _name[dentry->d_name.len + 1];
DPRINTK(KERN_DEBUG "ncp_mkdir: making %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
error = -EIO;
- if (!ncp_conn_valid(NCP_SERVER(dir)))
+ if (!ncp_conn_valid(server))
goto out;
- strncpy(_name, dentry->d_name.name, dentry->d_name.len);
+ ncp_age_dentry(server, dentry);
+
+ memcpy(_name, dentry->d_name.name, dentry->d_name.len);
_name[dentry->d_name.len] = '\0';
- io2vol(NCP_SERVER(dir), _name, !ncp_preserve_case(dir));
+ io2vol(server, _name, !ncp_preserve_case(dir));
error = -EACCES;
- if (ncp_open_create_file_or_subdir(NCP_SERVER(dir), dir, _name,
+ if (ncp_open_create_file_or_subdir(server, dir, _name,
OC_MODE_CREATE, aDIR, 0xffff,
- &finfo.nw_info) == 0)
+ &finfo) == 0)
{
error = ncp_instantiate(dir, dentry, &finfo);
}
@@ -937,27 +918,27 @@ out:
static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
{
int error, result;
+ struct ncp_server *server = NCP_SERVER(dir);
__u8 _name[dentry->d_name.len + 1];
DPRINTK(KERN_DEBUG "ncp_rmdir: removing %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
error = -EIO;
- if (!ncp_conn_valid(NCP_SERVER(dir)))
+ if (!ncp_conn_valid(server))
goto out;
error = -EBUSY;
if (!list_empty(&dentry->d_hash))
goto out;
- strncpy(_name, dentry->d_name.name, dentry->d_name.len);
+ memcpy(_name, dentry->d_name.name, dentry->d_name.len);
_name[dentry->d_name.len] = '\0';
- io2vol(NCP_SERVER(dir), _name, !ncp_preserve_case(dir));
- result = ncp_del_file_or_subdir(NCP_SERVER(dir), dir, _name);
+ io2vol(server, _name, !ncp_preserve_case(dir));
+ result = ncp_del_file_or_subdir(server, dir, _name);
switch (result) {
case 0x00:
- ncp_invalid_dir_cache(dir);
error = 0;
break;
case 0x85: /* unauthorized to delete file */
@@ -988,13 +969,14 @@ out:
static int ncp_unlink(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
+ struct ncp_server *server = NCP_SERVER(dir);
int error;
DPRINTK(KERN_DEBUG "ncp_unlink: unlinking %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
error = -EIO;
- if (!ncp_conn_valid(NCP_SERVER(dir)))
+ if (!ncp_conn_valid(server))
goto out;
/*
@@ -1007,11 +989,11 @@ printk(KERN_DEBUG "ncp_unlink: closing file\n");
ncp_make_closed(inode);
}
- error = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
+ error = ncp_del_file_or_subdir2(server, dentry);
#ifdef CONFIG_NCPFS_STRONG
/* 9C is Invalid path.. It should be 8F, 90 - read only, but
it is not :-( */
- if (error == 0x9C && NCP_SERVER(dir)->m.flags & NCP_MOUNT_STRONG) { /* R/O */
+ if (error == 0x9C && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */
error = ncp_force_unlink(dir, dentry);
}
#endif
@@ -1019,7 +1001,6 @@ printk(KERN_DEBUG "ncp_unlink: closing file\n");
case 0x00:
DPRINTK(KERN_DEBUG "ncp: removed %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
- ncp_invalid_dir_cache(dir);
d_delete(dentry);
break;
case 0x85:
@@ -1064,11 +1045,14 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
if (!ncp_conn_valid(NCP_SERVER(old_dir)))
goto out;
- strncpy(_old_name, old_dentry->d_name.name, old_len);
+ ncp_age_dentry(NCP_SERVER(old_dir), old_dentry);
+ ncp_age_dentry(NCP_SERVER(new_dir), new_dentry);
+
+ memcpy(_old_name, old_dentry->d_name.name, old_len);
_old_name[old_len] = '\0';
io2vol(NCP_SERVER(old_dir), _old_name, !ncp_preserve_case(old_dir));
- strncpy(_new_name, new_dentry->d_name.name, new_len);
+ memcpy(_new_name, new_dentry->d_name.name, new_len);
_new_name[new_len] = '\0';
io2vol(NCP_SERVER(new_dir), _new_name, !ncp_preserve_case(new_dir));
@@ -1085,8 +1069,6 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
case 0x00:
DPRINTK(KERN_DEBUG "ncp renamed %s -> %s.\n",
old_dentry->d_name.name,new_dentry->d_name.name);
- ncp_invalid_dir_cache(old_dir);
- ncp_invalid_dir_cache(new_dir);
/* d_move(old_dentry, new_dentry); */
break;
case 0x9E:
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index 3e16cf408..e39578d75 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -38,7 +38,7 @@ int ncp_make_open(struct inode *inode, int right)
{
int error, result;
int access;
- struct nw_file_info finfo;
+ struct ncp_entry_info finfo;
error = -EINVAL;
if (!inode) {
@@ -259,7 +259,6 @@ ncp_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
if (pos > inode->i_size) {
inode->i_size = pos;
- ncp_invalid_dir_cache(dentry->d_parent->d_inode);
}
DPRINTK(KERN_DEBUG "ncp_file_write: exit %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 88d56f7b2..e2d8a8a0f 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -31,7 +31,6 @@
#include "ncplib_kernel.h"
-static void ncp_read_inode(struct inode *);
static void ncp_put_inode(struct inode *);
static void ncp_delete_inode(struct inode *);
static void ncp_put_super(struct super_block *);
@@ -39,7 +38,7 @@ static int ncp_statfs(struct super_block *, struct statfs *, int);
static struct super_operations ncp_sops =
{
- ncp_read_inode, /* read inode */
+ NULL, /* read inode */
NULL, /* write inode */
ncp_put_inode, /* put inode */
ncp_delete_inode, /* delete inode */
@@ -56,21 +55,15 @@ extern struct inode_operations ncp_symlink_inode_operations;
extern int ncp_symlink(struct inode*, struct dentry*, const char*);
#endif
-static struct nw_file_info *read_nwinfo = NULL;
-static DECLARE_MUTEX(read_sem);
-
/*
* Fill in the ncpfs-specific information in the inode.
*/
-void ncp_update_inode(struct inode *inode, struct nw_file_info *nwinfo)
+void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
{
NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
NCP_FINFO(inode)->volNumber = nwinfo->i.volNumber;
-#ifdef CONFIG_NCPFS_SMALLDOS
- NCP_FINFO(inode)->origNS = nwinfo->i.NSCreator;
-#endif
#ifdef CONFIG_NCPFS_STRONG
NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
#endif
@@ -85,7 +78,7 @@ nwinfo->i.entryName, NCP_FINFO(inode)->volNumber, NCP_FINFO(inode)->dirEntNum);
#endif
}
-void ncp_update_inode2(struct inode* inode, struct nw_file_info *nwinfo)
+void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
{
struct nw_info_struct *nwi = &nwinfo->i;
struct ncp_server *server = NCP_SERVER(inode);
@@ -96,7 +89,7 @@ void ncp_update_inode2(struct inode* inode, struct nw_file_info *nwinfo)
#endif
if (nwi->attributes & aDIR) {
inode->i_mode = server->m.dir_mode;
- inode->i_size = 512;
+ inode->i_size = NCP_BLOCK_SIZE;
} else {
inode->i_mode = server->m.file_mode;
inode->i_size = le32_to_cpu(nwi->dataStreamSize);
@@ -105,8 +98,8 @@ void ncp_update_inode2(struct inode* inode, struct nw_file_info *nwinfo)
switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
case aHIDDEN:
if (server->m.flags & NCP_MOUNT_SYMLINKS) {
- if ((inode->i_size >= NCP_MIN_SYMLINK_SIZE)
- && (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) {
+ if ( /* (inode->i_size >= NCP_MIN_SYMLINK_SIZE)
+ && */ (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) {
inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
break;
}
@@ -149,9 +142,9 @@ void ncp_update_inode2(struct inode* inode, struct nw_file_info *nwinfo)
}
/*
- * Fill in the inode based on the nw_file_info structure.
+ * Fill in the inode based on the ncp_entry_info structure.
*/
-static void ncp_set_attr(struct inode *inode, struct nw_file_info *nwinfo)
+static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
{
struct nw_info_struct *nwi = &nwinfo->i;
struct ncp_server *server = NCP_SERVER(inode);
@@ -160,7 +153,7 @@ static void ncp_set_attr(struct inode *inode, struct nw_file_info *nwinfo)
inode->i_mode = server->m.dir_mode;
/* for directories dataStreamSize seems to be some
Object ID ??? */
- inode->i_size = 512;
+ inode->i_size = NCP_BLOCK_SIZE;
} else {
inode->i_mode = server->m.file_mode;
inode->i_size = le32_to_cpu(nwi->dataStreamSize);
@@ -200,7 +193,7 @@ static void ncp_set_attr(struct inode *inode, struct nw_file_info *nwinfo)
inode->i_nlink = 1;
inode->i_uid = server->m.uid;
inode->i_gid = server->m.gid;
- inode->i_blksize = 512;
+ inode->i_blksize = NCP_BLOCK_SIZE;
inode->i_rdev = 0;
inode->i_blocks = 0;
@@ -219,36 +212,10 @@ static void ncp_set_attr(struct inode *inode, struct nw_file_info *nwinfo)
}
/*
- * This is called from iget() with the read semaphore held.
- * The global ncpfs_file_info structure has been set up by ncp_iget.
- */
-static void ncp_read_inode(struct inode *inode)
-{
- if (read_nwinfo == NULL) {
- printk(KERN_ERR "ncp_read_inode: invalid call\n");
- return;
- }
-
- ncp_set_attr(inode, read_nwinfo);
-
- if (S_ISREG(inode->i_mode)) {
- inode->i_op = &ncp_file_inode_operations;
- } else if (S_ISDIR(inode->i_mode)) {
- inode->i_op = &ncp_dir_inode_operations;
-#ifdef CONFIG_NCPFS_EXTRAS
- } else if (S_ISLNK(inode->i_mode)) {
- inode->i_op = &ncp_symlink_inode_operations;
-#endif
- } else {
- inode->i_op = NULL;
- }
-}
-
-/*
- * Set up the ncpfs_inode_info pointer and get a new inode.
+ * Get a new inode.
*/
struct inode *
-ncp_iget(struct super_block *sb, struct ncpfs_inode_info *info)
+ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
{
struct inode *inode;
@@ -257,12 +224,23 @@ ncp_iget(struct super_block *sb, struct ncpfs_inode_info *info)
return NULL;
}
- down(&read_sem);
- read_nwinfo = &info->nw_info;
- inode = iget(sb, info->ino);
- read_nwinfo = NULL;
- up(&read_sem);
- if (!inode)
+ inode = get_empty_inode();
+ if (inode) {
+ inode->i_sb = sb;
+ inode->i_dev = sb->s_dev;
+ inode->i_ino = info->ino;
+ ncp_set_attr(inode, info);
+ if (S_ISREG(inode->i_mode)) {
+ inode->i_op = &ncp_file_inode_operations;
+ } else if (S_ISDIR(inode->i_mode)) {
+ inode->i_op = &ncp_dir_inode_operations;
+#ifdef CONFIG_NCPFS_EXTRAS
+ } else if (S_ISLNK(inode->i_mode)) {
+ inode->i_op = &ncp_symlink_inode_operations;
+#endif
+ }
+ insert_inode_hash(inode);
+ } else
printk(KERN_ERR "ncp_iget: iget failed!\n");
return inode;
}
@@ -278,7 +256,6 @@ ncp_delete_inode(struct inode *inode)
{
if (S_ISDIR(inode->i_mode)) {
DDPRINTK(KERN_DEBUG "ncp_delete_inode: put directory %ld\n", inode->i_ino);
- ncp_invalid_dir_cache(inode);
}
if (NCP_FINFO(inode)->opened && ncp_make_closed(inode) != 0) {
@@ -288,34 +265,6 @@ ncp_delete_inode(struct inode *inode)
clear_inode(inode);
}
-static void ncp_init_root(struct ncp_server *server,
- struct ncpfs_inode_info *info)
-{
- struct ncp_inode_info *root = &(server->root);
- struct nw_info_struct *i = &(root->finfo.i);
-
- DPRINTK(KERN_DEBUG "ncp_init_root: i = %x\n", (int) i);
-
- i->attributes = aDIR;
- i->dataStreamSize= 1024;
- i->dirEntNum = 0;
- i->DosDirNum = 0;
-#ifdef CONFIG_NCPFS_SMALLDOS
- i->NSCreator = NW_NS_DOS;
-#endif
- i->volNumber = NCP_NUMBER_OF_VOLUMES + 1; /* illegal volnum */
- /* set dates of mountpoint to Jan 1, 1986; 00:00 */
- i->creationTime = i->modifyTime = cpu_to_le16(0x0000);
- i->creationDate = i->modifyDate = i->lastAccessDate = cpu_to_le16(0x0C21);
- i->nameLen = 0;
- i->entryName[0] = '\0';
-
- root->finfo.opened= 0;
- info->ino = 2; /* tradition */
- info->nw_info = root->finfo;
- return;
-}
-
struct super_block *
ncp_read_super(struct super_block *sb, void *raw_data, int silent)
{
@@ -328,7 +277,7 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
#ifdef CONFIG_NCPFS_PACKET_SIGNING
int options;
#endif
- struct ncpfs_inode_info finfo;
+ struct ncp_entry_info finfo;
MOD_INC_USE_COUNT;
if (data == NULL)
@@ -349,13 +298,8 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
sb->s_dev = dev;
sb->s_op = &ncp_sops;
- /* We must malloc our own super-block info */
- server = (struct ncp_server *) ncp_kmalloc(sizeof(struct ncp_server),
- GFP_KERNEL);
- if (server == NULL)
- goto out_no_server;
+ server = NCP_SBP(sb);
memset(server, 0, sizeof(*server));
- NCP_SBP(sb) = server;
server->ncp_filp = ncp_filp;
/* server->lock = 0; */
@@ -390,12 +334,12 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
#ifdef CONFIG_NCPFS_NLS
/* load the default NLS charsets */
- server->nls_charsets.codepage[0] = 0;
- server->nls_charsets.iocharset[0] = 0;
server->nls_vol = load_nls_default();
server->nls_io = load_nls_default();
#endif /* CONFIG_NCPFS_NLS */
+ server->dentry_ttl = 0; /* no caching */
+
server->packet_size = NCP_PACKET_SIZE;
server->packet = ncp_kmalloc(NCP_PACKET_SIZE, GFP_KERNEL);
if (server->packet == NULL)
@@ -433,16 +377,36 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent)
goto out_no_bufsize;
DPRINTK(KERN_DEBUG "ncpfs: bufsize = %d\n", server->buffer_size);
- ncp_init_root(server, &finfo);
- server->name_space[finfo.nw_info.i.volNumber] = NW_NS_DOS;
+ memset(&finfo, 0, sizeof(finfo));
+ finfo.i.attributes = aDIR;
+ finfo.i.dataStreamSize = NCP_BLOCK_SIZE;
+ finfo.i.dirEntNum = 0;
+ finfo.i.DosDirNum = 0;
+#ifdef CONFIG_NCPFS_SMALLDOS
+ finfo.i.NSCreator = NW_NS_DOS;
+#endif
+ finfo.i.volNumber = NCP_NUMBER_OF_VOLUMES + 1; /* illegal volnum */
+ /* set dates of mountpoint to Jan 1, 1986; 00:00 */
+ finfo.i.creationTime = finfo.i.modifyTime
+ = cpu_to_le16(0x0000);
+ finfo.i.creationDate = finfo.i.modifyDate
+ = finfo.i.lastAccessDate
+ = cpu_to_le16(0x0C21);
+ finfo.i.nameLen = 0;
+ finfo.i.entryName[0] = '\0';
+
+ finfo.opened = 0;
+ finfo.ino = 2; /* tradition */
+
+ server->name_space[finfo.i.volNumber] = NW_NS_DOS;
root_inode = ncp_iget(sb, &finfo);
if (!root_inode)
goto out_no_root;
DPRINTK(KERN_DEBUG "ncp_read_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
- server->root_dentry = sb->s_root = d_alloc_root(root_inode);
+ sb->s_root = d_alloc_root(root_inode);
if (!sb->s_root)
goto out_no_root;
- server->root_dentry->d_op = &ncp_dentry_operations;
+ sb->s_root->d_op = &ncp_dentry_operations;
unlock_super(sb);
return sb;
@@ -469,11 +433,6 @@ out_free_server:
unload_nls(server->nls_io);
unload_nls(server->nls_vol);
#endif
- ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server));
- goto out_unlock;
-out_no_server:
- printk(KERN_ERR "ncp_read_super: could not alloc ncp_server\n");
-out_unlock:
/* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
*
* The previously used put_filp(ncp_filp); was bogous, since
@@ -531,8 +490,6 @@ static void ncp_put_super(struct super_block *sb)
ncp_kfree_s(server->auth.object_name, server->auth.object_name_len);
ncp_kfree_s(server->packet, server->packet_size);
- ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server));
-
MOD_DEC_USE_COUNT;
}
@@ -547,7 +504,7 @@ static int ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
here is to err conservatively. */
tmp.f_type = NCP_SUPER_MAGIC;
- tmp.f_bsize = 512;
+ tmp.f_bsize = NCP_BLOCK_SIZE;
tmp.f_blocks = 0;
tmp.f_bfree = 0;
tmp.f_bavail = 0;
@@ -571,6 +528,9 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
if ((!server) || !ncp_conn_valid(server))
goto out;
+ /* ageing the dentry to force validation */
+ ncp_age_dentry(server, dentry);
+
result = inode_change_ok(inode, attr);
if (result < 0)
goto out;
@@ -703,7 +663,6 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
closing the file */
result = ncp_make_closed(inode);
}
- ncp_invalid_dir_cache(dentry->d_parent->d_inode);
out:
return result;
}
@@ -732,22 +691,16 @@ int init_module(void)
{
DPRINTK(KERN_DEBUG "ncpfs: init_module called\n");
- init_MUTEX(&read_sem);
- read_nwinfo = NULL;
-
#ifdef DEBUG_NCP_MALLOC
ncp_malloced = 0;
ncp_current_malloced = 0;
#endif
- ncp_init_dir_cache();
-
return init_ncp_fs();
}
void cleanup_module(void)
{
DPRINTK(KERN_DEBUG "ncpfs: cleanup_module called\n");
- ncp_free_dir_cache();
unregister_filesystem(&ncp_fs_type);
#ifdef DEBUG_NCP_MALLOC
printk(KERN_DEBUG "ncp_malloced: %d\n", ncp_malloced);
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index a7f767e38..ca2b534eb 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -16,7 +16,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
-#include <linux/ncp.h>
#include <linux/ncp_fs.h>
#include "ncplib_kernel.h"
@@ -110,7 +109,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
}
if (server->root_setuped) return -EBUSY;
server->root_setuped = 1;
- return ncp_conn_logged_in(server);
+ return ncp_conn_logged_in(inode->i_sb);
case NCP_IOC_GET_FS_INFO:
@@ -162,9 +161,19 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
return -EACCES;
}
if (server->m.mounted_vol[0]) {
- sr.volNumber = server->root.finfo.i.volNumber;
- sr.dirEntNum = server->root.finfo.i.dirEntNum;
- sr.namespace = server->name_space[sr.volNumber];
+ struct dentry* dentry = inode->i_sb->s_root;
+
+ if (dentry) {
+ struct inode* inode = dentry->d_inode;
+
+ if (inode) {
+ sr.volNumber = NCP_FINFO(inode)->volNumber;
+ sr.dirEntNum = NCP_FINFO(inode)->dirEntNum;
+ sr.namespace = server->name_space[sr.volNumber];
+ } else
+ DPRINTK(KERN_DEBUG "ncpfs: s_root->d_inode==NULL\n");
+ } else
+ DPRINTK(KERN_DEBUG "ncpfs: s_root==NULL\n");
} else {
sr.volNumber = -1;
sr.namespace = 0;
@@ -178,6 +187,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
case NCP_IOC_SETROOT:
{
struct ncp_setroot_ioctl sr;
+ struct nw_info_struct i;
struct dentry* dentry;
if ( (permission(inode, MAY_WRITE) != 0)
@@ -191,31 +201,30 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
sizeof(sr))) return -EFAULT;
if (sr.volNumber < 0) {
server->m.mounted_vol[0] = 0;
- server->root.finfo.i.volNumber = NCP_NUMBER_OF_VOLUMES + 1;
- server->root.finfo.i.dirEntNum = 0;
- server->root.finfo.i.DosDirNum = 0;
+ i.volNumber = NCP_NUMBER_OF_VOLUMES + 1;
+ i.dirEntNum = 0;
+ i.DosDirNum = 0;
} else if (sr.volNumber >= NCP_NUMBER_OF_VOLUMES) {
return -EINVAL;
- } else {
- if (ncp_mount_subdir(server, sr.volNumber, sr.namespace, sr.dirEntNum)) {
+ } else
+ if (ncp_mount_subdir(server, &i, sr.volNumber,
+ sr.namespace, sr.dirEntNum))
return -ENOENT;
- }
- }
- dentry = server->root_dentry;
+
+ dentry = inode->i_sb->s_root;
server->root_setuped = 1;
if (dentry) {
struct inode* inode = dentry->d_inode;
if (inode) {
- NCP_FINFO(inode)->volNumber = server->root.finfo.i.volNumber;
- NCP_FINFO(inode)->dirEntNum = server->root.finfo.i.dirEntNum;
- NCP_FINFO(inode)->DosDirNum = server->root.finfo.i.DosDirNum;
- } else {
- DPRINTK(KERN_DEBUG "ncpfs: root_dentry->d_inode==NULL\n");
- }
- } else {
- DPRINTK(KERN_DEBUG "ncpfs: root_dentry==NULL\n");
- }
+ NCP_FINFO(inode)->volNumber = i.volNumber;
+ NCP_FINFO(inode)->dirEntNum = i.dirEntNum;
+ NCP_FINFO(inode)->DosDirNum = i.DosDirNum;
+ } else
+ DPRINTK(KERN_DEBUG "ncpfs: s_root->d_inode==NULL\n");
+ } else
+ DPRINTK(KERN_DEBUG "ncpfs: s_root==NULL\n");
+
return 0;
}
#endif /* CONFIG_NCPFS_MOUNT_SUBDIR */
@@ -503,12 +512,12 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
* Thanks Petr Vandrovec for idea and many hints.
*/
case NCP_IOC_SETCHARSETS:
- if ( (permission(inode, MAY_WRITE) != 0)
- && (current->uid != server->m.mounted_uid))
- {
+ if ((permission(inode, MAY_WRITE) != 0) &&
+ (current->uid != server->m.mounted_uid))
return -EACCES;
- }
- if (server->root_setuped) return -EBUSY;
+ if (server->root_setuped)
+ return -EBUSY;
+
{
struct ncp_nls_ioctl user;
struct nls_table *codepage;
@@ -516,28 +525,28 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
struct nls_table *oldset_io;
struct nls_table *oldset_cp;
- if (copy_from_user(&user,
- (struct ncp_nls_ioctl*)arg,
- sizeof(user))) return -EFAULT;
+ if (copy_from_user(&user, (struct ncp_nls_ioctl*)arg,
+ sizeof(user)))
+ return -EFAULT;
codepage = NULL;
- if (!user.codepage[0]) {
+ user.codepage[NCP_IOCSNAME_LEN] = 0;
+ if (!user.codepage[0])
codepage = load_nls_default();
- }
else {
codepage = load_nls(user.codepage);
- if (! codepage) {
+ if (!codepage) {
return -EBADRQC;
}
}
iocharset = NULL;
- if (user.iocharset[0] == 0) {
+ user.iocharset[NCP_IOCSNAME_LEN] = 0;
+ if (user.iocharset[0] == 0)
iocharset = load_nls_default();
- }
else {
iocharset = load_nls(user.iocharset);
- if (! iocharset) {
+ if (!iocharset) {
unload_nls(codepage);
return -EBADRQC;
}
@@ -547,18 +556,80 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
server->nls_vol = codepage;
oldset_io = server->nls_io;
server->nls_io = iocharset;
- server->nls_charsets = user;
- if (oldset_cp) unload_nls(oldset_cp);
- if (oldset_io) unload_nls(oldset_io);
+
+ if (oldset_cp)
+ unload_nls(oldset_cp);
+ if (oldset_io)
+ unload_nls(oldset_io);
+
return 0;
}
case NCP_IOC_GETCHARSETS: /* not tested */
- if (copy_to_user((struct ncp_nls_ioctl*)arg,
- &(server->nls_charsets),
- sizeof(server->nls_charsets))) return -EFAULT;
- return 0;
+ {
+ struct ncp_nls_ioctl user;
+
+ memset(&user, 0, sizeof(user));
+ if (server->nls_vol)
+ if (server->nls_vol->charset) {
+ strncpy(user.codepage,
+ server->nls_vol->charset,
+ NCP_IOCSNAME_LEN);
+ user.codepage[NCP_IOCSNAME_LEN] = 0;
+ if (!strcmp(user.codepage, "default"))
+ /* unfortunately, we cannot set
+ 'default' charset... maybe
+ we should change load_nls()?
+ It is easy, do not initialize
+ 'tables' in fs/nls/nls_base.c
+ with NULL, but with
+ 'default_table'... */
+ memset(user.codepage, 0,
+ sizeof(user.codepage));
+ }
+
+ if (server->nls_io)
+ if (server->nls_io->charset) {
+ strncpy(user.iocharset,
+ server->nls_io->charset,
+ NCP_IOCSNAME_LEN);
+ user.iocharset[NCP_IOCSNAME_LEN] = 0;
+ if (!strcmp(user.iocharset, "default"))
+ memset(user.iocharset, 0,
+ sizeof(user.iocharset));
+ }
+
+ if (copy_to_user((struct ncp_nls_ioctl*)arg, &user,
+ sizeof(user)))
+ return -EFAULT;
+
+ return 0;
+ }
#endif /* CONFIG_NCPFS_NLS */
+ case NCP_IOC_SETDENTRYTTL:
+ if ((permission(inode, MAY_WRITE) != 0) &&
+ (current->uid != server->m.mounted_uid))
+ return -EACCES;
+ {
+ u_int32_t user;
+
+ if (copy_from_user(&user, (u_int32_t*)arg, sizeof(user)))
+ return -EFAULT;
+ /* 20 secs at most... */
+ if (user > 20000)
+ return -EINVAL;
+ user = (user * HZ) / 1000;
+ server->dentry_ttl = user;
+ return 0;
+ }
+
+ case NCP_IOC_GETDENTRYTTL:
+ {
+ u_int32_t user = (server->dentry_ttl * 1000) / HZ;
+ if (copy_to_user((u_int32_t*)arg, &user, sizeof(user)))
+ return -EFAULT;
+ return 0;
+ }
default:
return -EINVAL;
diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c
index 8fc691356..2881c74fa 100644
--- a/fs/ncpfs/ncplib_kernel.c
+++ b/fs/ncpfs/ncplib_kernel.c
@@ -148,7 +148,7 @@ ncp_negotiate_size_and_options(struct ncp_server *server,
int result;
/* there is minimum */
- if (size < 512) size = 512;
+ if (size < NCP_BLOCK_SIZE) size = NCP_BLOCK_SIZE;
ncp_init_request(server);
ncp_add_word(server, htons(size));
@@ -162,7 +162,7 @@ ncp_negotiate_size_and_options(struct ncp_server *server,
/* NCP over UDP returns 0 (!!!) */
result = ntohs(ncp_reply_word(server, 0));
- if (result >= 512) size=min(result, size);
+ if (result >= NCP_BLOCK_SIZE) size=min(result, size);
*ret_size = size;
*ret_options = ncp_reply_byte(server, 4);
@@ -264,7 +264,7 @@ static void ncp_extract_file_info(void *structure, struct nw_info_struct *target
memcpy(target, structure, info_struct_size);
name_len = structure + info_struct_size;
target->nameLen = *name_len;
- strncpy(target->entryName, name_len + 1, *name_len);
+ memcpy(target->entryName, name_len + 1, *name_len);
target->entryName[*name_len] = '\0';
return;
}
@@ -406,9 +406,8 @@ ncp_ObtainSpecificDirBase(struct ncp_server *server,
}
int
-ncp_mount_subdir(struct ncp_server *server,
- __u8 volNumber,
- __u8 srcNS, __u32 dirEntNum)
+ncp_mount_subdir(struct ncp_server *server, struct nw_info_struct *i,
+ __u8 volNumber, __u8 srcNS, __u32 dirEntNum)
{
int dstNS;
int result;
@@ -422,9 +421,9 @@ ncp_mount_subdir(struct ncp_server *server,
return result;
}
server->name_space[volNumber] = dstNS;
- server->root.finfo.i.volNumber = volNumber;
- server->root.finfo.i.dirEntNum = newDirEnt;
- server->root.finfo.i.DosDirNum = newDosEnt;
+ i->volNumber = volNumber;
+ i->dirEntNum = newDirEnt;
+ i->DosDirNum = newDosEnt;
server->m.mounted_vol[1] = 0;
server->m.mounted_vol[0] = 'X';
return 0;
@@ -467,7 +466,7 @@ ncp_lookup_volume(struct ncp_server *server, char *volname,
volnum, server->name_space[volnum]);
target->nameLen = strlen(volname);
- strcpy(target->entryName, volname);
+ memcpy(target->entryName, volname, target->nameLen+1);
target->attributes = aDIR;
/* set dates to Jan 1, 1986 00:00 */
target->creationTime = target->modifyTime = cpu_to_le16(0x0000);
@@ -583,7 +582,7 @@ int ncp_open_create_file_or_subdir(struct ncp_server *server,
int open_create_mode,
__u32 create_attributes,
int desired_acc_rights,
- struct nw_file_info *target)
+ struct ncp_entry_info *target)
{
__u16 search_attribs = ntohs(0x0600);
__u8 volnum = target->i.volNumber;
diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h
index 057b068b8..f4cc6425b 100644
--- a/fs/ncpfs/ncplib_kernel.h
+++ b/fs/ncpfs/ncplib_kernel.h
@@ -5,6 +5,7 @@
* Modified for big endian by J.F. Chadima and David S. Miller
* Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
* Modified 1998 Wolfram Pienkoss for NLS
+ * Modified 1999 Wolfram Pienkoss for directory caching
*
*/
@@ -19,6 +20,8 @@
#include <linux/malloc.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
+#include <linux/pagemap.h>
+
#include <asm/uaccess.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
@@ -28,13 +31,13 @@
#include <linux/nls.h>
#endif
-#include <linux/ncp.h>
#include <linux/ncp_fs.h>
-#include <linux/ncp_fs_sb.h>
#define NCP_MIN_SYMLINK_SIZE 8
#define NCP_MAX_SYMLINK_SIZE 512
+#define NCP_BLOCK_SIZE 512
+
int ncp_negotiate_buffersize(struct ncp_server *, int, int *);
int ncp_negotiate_size_and_options(struct ncp_server *server, int size,
int options, int *ret_size, int *ret_options);
@@ -62,7 +65,7 @@ int ncp_modify_file_or_subdir_dos_info_path(struct ncp_server *, struct inode *,
int ncp_del_file_or_subdir2(struct ncp_server *, struct dentry*);
int ncp_del_file_or_subdir(struct ncp_server *, struct inode *, char *);
int ncp_open_create_file_or_subdir(struct ncp_server *, struct inode *, char *,
- int, __u32, int, struct nw_file_info *);
+ int, __u32, int, struct ncp_entry_info *);
int ncp_initialize_search(struct ncp_server *, struct inode *,
struct nw_search_sequence *target);
@@ -88,8 +91,8 @@ ncp_ClearPhysicalRecord(struct ncp_server *server,
#ifdef CONFIG_NCPFS_MOUNT_SUBDIR
int
-ncp_mount_subdir(struct ncp_server* server, __u8 volNumber,
- __u8 srcNS, __u32 srcDirEntNum);
+ncp_mount_subdir(struct ncp_server *, struct nw_info_struct *,
+ __u8, __u8, __u32);
#endif /* CONFIG_NCPFS_MOUNT_SUBDIR */
#ifdef CONFIG_NCPFS_NLS
@@ -169,5 +172,37 @@ vol2io(struct ncp_server *server, char *name, int case_trans)
#endif /* CONFIG_NCPFS_NLS */
-#endif /* _NCPLIB_H */
+#define NCP_GET_AGE(dentry) (jiffies - (dentry)->d_time)
+#define NCP_MAX_AGE (server->dentry_ttl)
+#define NCP_TEST_AGE(server,dentry) (NCP_GET_AGE(dentry) < NCP_MAX_AGE)
+static inline void
+ncp_age_dentry(struct ncp_server* server, struct dentry* dentry)
+{
+ dentry->d_time = jiffies - server->dentry_ttl;
+}
+
+static inline void
+ncp_new_dentry(struct dentry* dentry)
+{
+ dentry->d_time = jiffies;
+}
+
+#define NCP_FPOS_EMPTY 0 /* init value for fpos variables. */
+
+struct ncp_cache_control {
+ struct nw_search_sequence seq;
+ int firstcache;
+ int currentpos;
+ int cachehead;
+ int cachetail;
+ int eof;
+};
+
+#define NCP_DIRCACHE_SIZE (PAGE_CACHE_SIZE-sizeof(struct ncp_cache_control))
+struct ncp_seq_cache {
+ struct ncp_cache_control ctl;
+ unsigned char cache[NCP_DIRCACHE_SIZE];
+};
+
+#endif /* _NCPLIB_H */
diff --git a/fs/ncpfs/ncpsign_kernel.h b/fs/ncpfs/ncpsign_kernel.h
index 85974f346..141338fb5 100644
--- a/fs/ncpfs/ncpsign_kernel.h
+++ b/fs/ncpfs/ncpsign_kernel.h
@@ -9,7 +9,6 @@
#define _NCPSIGN_KERNEL_H
#include <linux/ncp_fs.h>
-#include <linux/ncp_fs_sb.h>
void sign_packet(struct ncp_server *server, int *size);
diff --git a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c
index 81ac20840..2d43ec9ad 100644
--- a/fs/ncpfs/sock.c
+++ b/fs/ncpfs/sock.c
@@ -27,9 +27,7 @@
#include <linux/poll.h>
#include <linux/file.h>
-#include <linux/ncp.h>
#include <linux/ncp_fs.h>
-#include <linux/ncp_fs_sb.h>
#ifdef CONFIG_NCPFS_PACKET_SIGNING
#include "ncpsign_kernel.h"
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 0c318e212..a1241da96 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -824,7 +824,7 @@ printk("lookup_by_inode: ino %ld not found in %s\n", ino, parent->d_name.name);
printk("lookup_by_inode: found %s\n", dirent.name);
#endif
- dentry = lookup_dentry(dirent.name, dget(parent), 0);
+ dentry = lookup_dentry(dirent.name, parent, 0);
if (!IS_ERR(dentry)) {
if (dentry->d_inode && dentry->d_inode->i_ino == ino)
goto out;
@@ -1007,7 +1007,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
/*
* ... then search for the inode in the parent directory.
*/
- dentry = lookup_by_inode(parent, u32_to_ino_t(fh->fh_ino));
+ dentry = lookup_by_inode(dget(parent), u32_to_ino_t(fh->fh_ino));
dput(parent);
if (dentry)
goto out;
diff --git a/fs/open.c b/fs/open.c
index 5a86dc48a..3caaa53ce 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -526,10 +526,13 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
* non-root user, remove the setuid bit.
* 19981026 David C Niemi <niemi@tux.org>
*
+ * Changed this to apply to all users, including root, to avoid
+ * some races. This is the behavior we had in 2.0. The check for
+ * non-root was definitely wrong for 2.2 anyway, as it should
+ * have been using CAP_FSETID rather than fsuid -- 19990830 SD.
*/
if ((inode->i_mode & S_ISUID) == S_ISUID &&
- !S_ISDIR(inode->i_mode)
- && current->fsuid)
+ !S_ISDIR(inode->i_mode))
{
newattrs.ia_mode &= ~S_ISUID;
newattrs.ia_valid |= ATTR_MODE;
@@ -539,9 +542,11 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
* by a non-root user, remove the setgid bit UNLESS there is no group
* execute bit (this would be a file marked for mandatory locking).
* 19981026 David C Niemi <niemi@tux.org>
+ *
+ * Removed the fsuid check (see the comment above) -- 19990830 SD.
*/
if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))
- && !S_ISDIR(inode->i_mode) && current->fsuid)
+ && !S_ISDIR(inode->i_mode))
{
newattrs.ia_mode &= ~S_ISGID;
newattrs.ia_valid |= ATTR_MODE;
diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c
index a4ba9253b..c05d6cf30 100644
--- a/fs/partitions/msdos.c
+++ b/fs/partitions/msdos.c
@@ -26,6 +26,7 @@
#include <linux/major.h>
#include <linux/string.h>
#include <linux/blk.h>
+#include <linux/ide.h> /* IDE xlate */
#include <asm/system.h>
@@ -356,7 +357,6 @@ check_table:
/*
* Look for various forms of IDE disk geometry translation
*/
- extern int ide_xlate_1024(kdev_t, int, int, const char *);
unsigned int sig = le16_to_cpu(*(unsigned short *)(data + 2));
int heads = 0;
/*
diff --git a/fs/proc/array.c b/fs/proc/array.c
index e2775ae0d..801ecee88 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -575,10 +575,20 @@ static unsigned long get_wchan(struct task_struct *p)
unsigned long pc;
pc = thread_saved_pc(&p->thread);
- if (pc >= (unsigned long) interruptible_sleep_on && pc < (unsigned long) add_timer) {
- schedule_frame = ((unsigned long *)(long)p->thread.reg30)[16];
- return (unsigned long)((unsigned long *)schedule_frame)[11];
+ if (pc == (unsigned long) interruptible_sleep_on
+ || pc == (unsigned long) sleep_on) {
+ schedule_frame = ((unsigned long *)p->thread.reg30)[9];
+ return ((unsigned long *)schedule_frame)[15];
}
+ if (pc == (unsigned long) interruptible_sleep_on_timeout
+ || pc == (unsigned long) sleep_on_timeout) {
+ schedule_frame = ((unsigned long *)p->thread.reg30)[9];
+ return ((unsigned long *)schedule_frame)[16];
+ }
+ if (pc >= first_sched && pc < last_sched) {
+ printk(KERN_DEBUG "Bug in %s\n", __FUNCTION__);
+ }
+
return pc;
}
#elif defined(__mc68000__)
diff --git a/fs/smbfs/cache.c b/fs/smbfs/cache.c
index 36f1650ac..14d61aba0 100644
--- a/fs/smbfs/cache.c
+++ b/fs/smbfs/cache.c
@@ -14,12 +14,67 @@
#include <linux/mm.h>
#include <linux/dirent.h>
#include <linux/smb_fs.h>
+#include <linux/pagemap.h>
#include <asm/page.h>
#define SMBFS_PARANOIA 1
/* #define SMBFS_DEBUG_VERBOSE 1 */
+#ifdef SMBFS_DEBUG_VERBOSE
+/*
+ * Print a cache_dirent->name, max 80 chars
+ * You can't just printk non-null terminated strings ...
+ */
+printk_name(const char *name, int len)
+{
+ char buf[81];
+
+ if(len > 80)
+ len = 80;
+ strncpy(buf, name, len);
+ buf[len] = 0;
+ printk(buf);
+}
+#endif
+
+/*
+ * Get a page for this inode, if new is set then we want to allocate
+ * the page if it isn't in memory. As I understand it the rest of the
+ * smb-cache code assumes we return a locked page.
+ */
+unsigned long
+get_cached_page(struct inode * inode, unsigned long offset, int new)
+{
+ struct page * page;
+ struct page ** hash;
+ unsigned long new_page;
+
+ again:
+ hash = page_hash(inode, offset);
+ page = __find_lock_page(inode, offset, hash);
+ if(!page && new) {
+ /* not in cache, alloc a new page */
+ new_page = page_cache_alloc();
+ if (!new_page)
+ return 0;
+ clear_page(new_page); /* smb code assumes pages are zeroed */
+ page = page_cache_entry(new_page);
+ if (add_to_page_cache_unique(page, inode, offset, hash)) {
+ /* Hmm, a page has materialized in the
+ cache. Fine. Go back and get that page
+ instead ... throwing away this one first. */
+ put_cached_page((unsigned long) page);
+ goto again;
+ }
+ }
+ if(!page)
+ return 0;
+ if(!PageLocked(page))
+ printk(KERN_ERR "smbfs/cache.c: page isn't locked! This could be fun ...\n");
+ return page_address(page);
+}
+
static inline struct inode *
get_cache_inode(struct cache_head *cachep)
{
@@ -38,8 +93,8 @@ smb_get_dircache(struct dentry * dentry)
struct cache_head * cachep;
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_get_dircache: finding cache for %s/%s\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
+ printk("smb_get_dircache: finding cache for %s/%s\n",
+ dentry->d_parent->d_name.name, dentry->d_name.name);
#endif
cachep = (struct cache_head *) get_cached_page(inode, 0, 1);
if (!cachep)
@@ -140,8 +195,10 @@ smb_add_to_cache(struct cache_head * cachep, struct cache_dirent *entry,
unsigned int needed = len + sizeof(struct cache_entry);
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_add_to_cache: cache inode %p, status %d, adding %s at %ld\n",
-inode, cachep->status, entry->name, fpos);
+printk("smb_add_to_cache: cache inode %p, status %d, adding ",
+ inode, cachep->status);
+printk_name(entry->name, entry->len);
+printk(" at %ld\n", fpos);
#endif
/*
* Don't do anything if we've had an error ...
@@ -169,8 +226,10 @@ inode, cachep->status, entry->name, fpos);
block->cb_data.table[nent].ino = entry->ino;
cachep->entries++;
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_add_to_cache: added entry %s, len=%d, pos=%ld, entries=%d\n",
-entry->name, len, fpos, cachep->entries);
+printk("smb_add_to_cache: added entry ");
+printk_name(entry->name, entry->len);
+printk(", len=%d, pos=%ld, entries=%d\n",
+len, fpos, cachep->entries);
#endif
return;
}
@@ -231,7 +290,7 @@ printk("smb_find_in_cache: cache %p, looking for pos=%ld\n", cachep, pos);
nent = pos - next_pos;
next_pos += index->num_entries;
if (pos >= next_pos)
- continue;
+ continue;
/*
* The entry is in this block. Note: we return
* then name as a reference with _no_ null byte.
@@ -242,8 +301,9 @@ printk("smb_find_in_cache: cache %p, looking for pos=%ld\n", cachep, pos);
offset = block->cb_data.table[nent].offset;
entry->name = &block->cb_data.names[offset];
#ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_find_in_cache: found %s, len=%d, pos=%ld\n",
-entry->name, entry->len, pos);
+printk("smb_find_in_cache: found ");
+printk_name(entry->name, entry->len);
+printk(", len=%d, pos=%ld\n", entry->len, pos);
#endif
break;
}
@@ -312,4 +372,3 @@ smb_invalid_dir_cache(struct inode * dir)
dir->u.smbfs_i.cache_valid &= ~SMB_F_CACHEVALID;
dir->u.smbfs_i.oldmtime = 0;
}
-
diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c
index 682b511f6..1aa6b711e 100644
--- a/fs/smbfs/file.c
+++ b/fs/smbfs/file.c
@@ -32,13 +32,6 @@ min(int a, int b)
return a < b ? a : b;
}
-static inline void
-smb_unlock_page(struct page *page)
-{
- clear_bit(PG_locked, &page->flags);
- wake_up(&page->wait);
-}
-
static int
smb_fsync(struct file *file, struct dentry * dentry)
{
@@ -61,7 +54,9 @@ smb_readpage_sync(struct dentry *dentry, struct page *page)
int count = PAGE_SIZE;
int result;
- clear_bit(PG_error, &page->flags);
+ /* We can't replace this with ClearPageError. why? is it a problem?
+ fs/buffer.c:brw_page does the same. */
+ /* clear_bit(PG_error, &page->flags); */
#ifdef SMBFS_DEBUG_VERBOSE
printk("smb_readpage_sync: file %s/%s, count=%d@%ld, rsize=%d\n",
@@ -94,11 +89,11 @@ dentry->d_parent->d_name.name, dentry->d_name.name, result);
} while (count);
memset(buffer, 0, count);
- set_bit(PG_uptodate, &page->flags);
+ SetPageUptodate(page);
result = 0;
io_error:
- smb_unlock_page(page);
+ UnlockPage(page);
return result;
}
@@ -110,13 +105,13 @@ smb_readpage(struct file *file, struct page *page)
pr_debug("SMB: smb_readpage %08lx\n", page_address(page));
#ifdef SMBFS_PARANOIA
- if (test_bit(PG_locked, &page->flags))
- printk("smb_readpage: page already locked!\n");
+ if (!PageLocked(page))
+ printk("smb_readpage: page not already locked!\n");
#endif
- set_bit(PG_locked, &page->flags);
- atomic_inc(&page->count);
+
+ get_page(page);
error = smb_readpage_sync(dentry, page);
- free_page(page_address(page));
+ put_page(page);
return error;
}
@@ -169,6 +164,8 @@ printk("smb_writepage_sync: short write, wsize=%d, result=%d\n", wsize, result);
/*
* Write a page to the server. This will be used for NFS swapping only
* (for now), and we currently do this synchronously only.
+ *
+ * We are called with the page locked and the caller unlocks.
*/
static int
smb_writepage(struct file *file, struct page *page)
@@ -177,14 +174,13 @@ smb_writepage(struct file *file, struct page *page)
int result;
#ifdef SMBFS_PARANOIA
- if (test_bit(PG_locked, &page->flags))
- printk("smb_writepage: page already locked!\n");
+ if (!PageLocked(page))
+ printk("smb_writepage: page not already locked!\n");
#endif
- set_bit(PG_locked, &page->flags);
- atomic_inc(&page->count);
+ get_page(page);
result = smb_writepage_sync(dentry, page, 0, PAGE_SIZE);
- smb_unlock_page(page);
- free_page(page_address(page));
+ SetPageUptodate(page);
+ put_page(page);
return result;
}
@@ -266,9 +262,9 @@ out:
* If the writer ends up delaying the write, the writer needs to
* increment the page use counts until he is done with the page.
*/
-static long smb_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
+static int smb_write_one_page(struct file *file, struct page *page, unsigned long offset, unsigned long bytes, const char * buf)
{
- long status;
+ int status;
bytes -= copy_from_user((u8*)page_address(page) + offset, buf, bytes);
status = -EFAULT;
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 4e70122c3..1db8ca9c8 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -517,6 +517,9 @@ static struct super_block *sysv_read_super(struct super_block *sb,
unlock_super(sb);
return NULL;
}
+#ifndef CONFIG_SYSV_FS_WRITE
+ sb->s_flags |= MS_RDONLY;
+#endif
unlock_super(sb);
sb->s_dirt = 1;
/* brelse(bh); resp. brelse(bh1); brelse(bh2);
@@ -912,15 +915,15 @@ abort:
return err;
abort_negative:
- printk("sysv_getblk: block < 0\n");
+ printk("sysv_get_block: block < 0\n");
goto abort;
abort_too_big:
- printk("sysv_getblk: block > big\n");
+ printk("sysv_get_block: block > big\n");
goto abort;
}
-struct buffer_head *sysv_getblk(struct inode *inode, unsigned int block, int create)
+static struct buffer_head *sysv_getblk(struct inode *inode, unsigned int block, int create)
{
struct buffer_head dummy;
int error;
@@ -930,9 +933,9 @@ struct buffer_head *sysv_getblk(struct inode *inode, unsigned int block, int cre
error = sysv_get_block(inode, block, &dummy, create);
if (!error && buffer_mapped(&dummy)) {
struct buffer_head *bh;
- bh = getblk(dummy.b_dev, dummy.b_blocknr, BLOCK_SIZE);
+ bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->sv_block_size);
if (buffer_new(&dummy)) {
- memset(bh->b_data, 0, BLOCK_SIZE);
+ memset(bh->b_data, 0, inode->i_sb->sv_block_size);
mark_buffer_uptodate(bh, 1);
mark_buffer_dirty(bh, 1);
}
@@ -1168,18 +1171,16 @@ int sysv_sync_inode(struct inode * inode)
/* Every kernel module contains stuff like this. */
-static struct file_system_type sysv_fs_type[3] = {
- {"xenix", FS_REQUIRES_DEV, sysv_read_super, NULL},
- {"sysv", FS_REQUIRES_DEV, sysv_read_super, NULL},
- {"coherent", FS_REQUIRES_DEV, sysv_read_super, NULL}
+static struct file_system_type sysv_fs_type[] = {
+ {"sysv", FS_REQUIRES_DEV, sysv_read_super, NULL}
};
int __init init_sysv_fs(void)
{
int i;
- int ouch;
+ int ouch = 0;
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < sizeof(sysv_fs_type)/sizeof(sysv_fs_type[0]); i++) {
if ((ouch = register_filesystem(&sysv_fs_type[i])) != 0)
break;
}
@@ -1198,7 +1199,7 @@ void cleanup_module(void)
{
int i;
- for (i = 0; i < 3; i++)
+ for (i = 0; i < sizeof(sysv_fs_type)/sizeof(sysv_fs_type[0]); i++)
/* No error message if this breaks... that's OK... */
unregister_filesystem(&sysv_fs_type[i]);
}
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 5e0aa576e..3cb450036 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -917,7 +917,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
inode->i_size = le64_to_cpu(fe->informationLength);
#if BITS_PER_LONG < 64
- if (le64_to_cpu(fe->informationLength) & 0xFFFFFFFF00000000)
+ if (le64_to_cpu(fe->informationLength) & 0xFFFFFFFF00000000ULL)
inode->i_size = (Uint32)-1;
#endif