diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-12-04 03:58:56 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-12-04 03:58:56 +0000 |
commit | 1d67e90f19a7acfd9a05dc59678e7d0c5090bd0d (patch) | |
tree | 357efc7b93f8f5102110d20d293f41360ec212fc /fs | |
parent | aea27b2e18d69af87e673972246e66657b4fa274 (diff) |
Merge with Linux 2.3.21.
Diffstat (limited to 'fs')
-rw-r--r-- | fs/Config.in | 3 | ||||
-rw-r--r-- | fs/binfmt_elf.c | 12 | ||||
-rw-r--r-- | fs/buffer.c | 44 | ||||
-rw-r--r-- | fs/dcache.c | 78 | ||||
-rw-r--r-- | fs/dquot.c | 3 | ||||
-rw-r--r-- | fs/exec.c | 15 | ||||
-rw-r--r-- | fs/fat/file.c | 4 | ||||
-rw-r--r-- | fs/fcntl.c | 42 | ||||
-rw-r--r-- | fs/inode.c | 431 | ||||
-rw-r--r-- | fs/isofs/inode.c | 15 | ||||
-rw-r--r-- | fs/ncpfs/Config.in | 20 | ||||
-rw-r--r-- | fs/ncpfs/dir.c | 720 | ||||
-rw-r--r-- | fs/ncpfs/file.c | 3 | ||||
-rw-r--r-- | fs/ncpfs/inode.c | 169 | ||||
-rw-r--r-- | fs/ncpfs/ioctl.c | 157 | ||||
-rw-r--r-- | fs/ncpfs/ncplib_kernel.c | 21 | ||||
-rw-r--r-- | fs/ncpfs/ncplib_kernel.h | 47 | ||||
-rw-r--r-- | fs/ncpfs/ncpsign_kernel.h | 1 | ||||
-rw-r--r-- | fs/ncpfs/sock.c | 2 | ||||
-rw-r--r-- | fs/nfsd/nfsfh.c | 4 | ||||
-rw-r--r-- | fs/open.c | 11 | ||||
-rw-r--r-- | fs/partitions/msdos.c | 2 | ||||
-rw-r--r-- | fs/proc/array.c | 16 | ||||
-rw-r--r-- | fs/smbfs/cache.c | 79 | ||||
-rw-r--r-- | fs/smbfs/file.c | 42 | ||||
-rw-r--r-- | fs/sysv/inode.c | 25 | ||||
-rw-r--r-- | fs/udf/inode.c | 2 |
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; } @@ -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; @@ -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 |