diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-03-23 02:25:38 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-03-23 02:25:38 +0000 |
commit | 16b5d462f73eb29d1f67fa01cc1ea66afdc72569 (patch) | |
tree | 5407bd573f4840e473ea27cbe61e5c7a07131fcd /fs | |
parent | ce8a076e11e7e5ee36007f9a3eee5bb3744cb8f6 (diff) |
Merge with Linux 2.3.99-pre2.
Diffstat (limited to 'fs')
-rw-r--r-- | fs/autofs/inode.c | 1 | ||||
-rw-r--r-- | fs/binfmt_aout.c | 28 | ||||
-rw-r--r-- | fs/binfmt_elf.c | 28 | ||||
-rw-r--r-- | fs/binfmt_em86.c | 4 | ||||
-rw-r--r-- | fs/binfmt_misc.c | 2 | ||||
-rw-r--r-- | fs/binfmt_script.c | 2 | ||||
-rw-r--r-- | fs/buffer.c | 12 | ||||
-rw-r--r-- | fs/dquot.c | 230 | ||||
-rw-r--r-- | fs/exec.c | 14 | ||||
-rw-r--r-- | fs/ext2/dir.c | 4 | ||||
-rw-r--r-- | fs/namei.c | 87 | ||||
-rw-r--r-- | fs/nfsd/nfs3xdr.c | 39 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 4 | ||||
-rw-r--r-- | fs/nfsd/nfsfh.c | 6 | ||||
-rw-r--r-- | fs/nfsd/nfsproc.c | 34 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 270 | ||||
-rw-r--r-- | fs/open.c | 6 | ||||
-rw-r--r-- | fs/partitions/acorn.c | 4 | ||||
-rw-r--r-- | fs/partitions/msdos.c | 12 | ||||
-rw-r--r-- | fs/smbfs/inode.c | 2 | ||||
-rw-r--r-- | fs/super.c | 107 | ||||
-rw-r--r-- | fs/ufs/dir.c | 4 |
22 files changed, 446 insertions, 454 deletions
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c index 1aa665d1c..2c2e7d32d 100644 --- a/fs/autofs/inode.c +++ b/fs/autofs/inode.c @@ -253,7 +253,6 @@ fail_iput: fail_free: kfree(sbi); fail_unlock: -fail_dec: return NULL; } diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index 5aa2f1b35..9339775ce 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -30,7 +30,7 @@ #include <asm/pgalloc.h> static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs); -static int load_aout_library(int fd); +static int load_aout_library(struct file*); static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file); extern void dump_thread(struct pt_regs *, struct user *); @@ -414,9 +414,8 @@ beyond_if: return 0; } -static int load_aout_library(int fd) +static int load_aout_library(struct file *file) { - struct file * file; struct inode * inode; unsigned long bss, start_addr, len; unsigned long error; @@ -424,12 +423,6 @@ static int load_aout_library(int fd) loff_t offset = 0; struct exec ex; - retval = -EACCES; - file = fget(fd); - if (!file) - goto out; - if (!file->f_op) - goto out_putf; inode = file->f_dentry->d_inode; retval = -ENOEXEC; @@ -438,17 +431,17 @@ static int load_aout_library(int fd) error = file->f_op->read(file, (char *) &ex, sizeof(ex), &offset); set_fs(USER_DS); if (error != sizeof(ex)) - goto out_putf; + goto out; /* We come in here for the regular a.out style of shared libraries */ if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || N_TRSIZE(ex) || N_DRSIZE(ex) || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) || inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { - goto out_putf; + goto out; } if (N_FLAGS(ex)) - goto out_putf; + goto out; /* For QMAGIC, the starting address is 0x20 into the page. We mask this off to get the starting address for the page */ @@ -474,16 +467,18 @@ static int load_aout_library(int fd) (unsigned long) start_addr + ex.a_text + ex.a_data); retval = 0; - goto out_putf; + goto out; } /* Now use mmap to map the library into memory. */ + down(¤t->mm->mmap_sem); error = do_mmap(file, start_addr, ex.a_text + ex.a_data, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, N_TXTOFF(ex)); + up(¤t->mm->mmap_sem); retval = error; if (error != start_addr) - goto out_putf; + goto out; len = PAGE_ALIGN(ex.a_text + ex.a_data); bss = ex.a_text + ex.a_data + ex.a_bss; @@ -491,12 +486,9 @@ static int load_aout_library(int fd) error = do_brk(start_addr + len, bss - len); retval = error; if (error != start_addr + len) - goto out_putf; + goto out; } retval = 0; - -out_putf: - fput(file); out: return retval; } diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 877d9e6d7..28f82594f 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -40,7 +40,7 @@ #include <linux/elf.h> static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs); -static int load_elf_library(int fd); +static int load_elf_library(struct file*); extern int dump_fpu (struct pt_regs *, elf_fpregset_t *); extern void dump_thread(struct pt_regs *, struct user *); @@ -503,16 +503,14 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) current->personality = PER_SVR4; lock_kernel(); - interpreter_dentry = open_namei(elf_interpreter, - 0, 0); + interpreter_dentry = open_namei(elf_interpreter); unlock_kernel(); current->personality = old_pers; } else #endif { lock_kernel(); - interpreter_dentry = open_namei(elf_interpreter, - 0, 0); + interpreter_dentry = open_namei(elf_interpreter); unlock_kernel(); } set_fs(old_fs); @@ -797,9 +795,8 @@ out_free_ph: /* This is really simpleminded and specialized - we are loading an a.out library that is given an ELF header. */ -static int load_elf_library(int fd) +static int load_elf_library(struct file *file) { - struct file * file; struct dentry * dentry; struct inode * inode; struct elf_phdr *elf_phdata; @@ -809,9 +806,6 @@ static int load_elf_library(int fd) loff_t offset = 0; error = -EACCES; - file = fget(fd); - if (!file || !file->f_op) - goto out; dentry = file->f_dentry; inode = dentry->d_inode; @@ -823,27 +817,27 @@ static int load_elf_library(int fd) retval = file->f_op->read(file, (char *) &elf_ex, sizeof(elf_ex), &offset); set_fs(USER_DS); if (retval != sizeof(elf_ex)) - goto out_putf; + goto out; if (memcmp(elf_ex.e_ident, ELFMAG, SELFMAG) != 0) - goto out_putf; + goto out; /* First of all, some simple consistency checks */ if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || !elf_check_arch(elf_ex.e_machine) || (!inode->i_fop || !inode->i_fop->mmap)) - goto out_putf; + goto out; /* Now read in all of the header information */ j = sizeof(struct elf_phdr) * elf_ex.e_phnum; if (j > ELF_EXEC_PAGESIZE) - goto out_putf; + goto out; error = -ENOMEM; elf_phdata = (struct elf_phdr *) kmalloc(j, GFP_KERNEL); if (!elf_phdata) - goto out_putf; + goto out; /* N.B. check for error return?? */ retval = read_exec(dentry, elf_ex.e_phoff, (char *) elf_phdata, @@ -858,6 +852,7 @@ static int load_elf_library(int fd) while (elf_phdata->p_type != PT_LOAD) elf_phdata++; /* Now use mmap to map the library into memory. */ + down(¤t->mm->mmap_sem); error = do_mmap(file, ELF_PAGESTART(elf_phdata->p_vaddr), (elf_phdata->p_filesz + @@ -866,6 +861,7 @@ static int load_elf_library(int fd) MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, (elf_phdata->p_offset - ELF_PAGEOFFSET(elf_phdata->p_vaddr))); + up(¤t->mm->mmap_sem); if (error != ELF_PAGESTART(elf_phdata->p_vaddr)) goto out_free_ph; @@ -883,8 +879,6 @@ static int load_elf_library(int fd) out_free_ph: kfree(elf_phdata); -out_putf: - fput(file); out: return error; } diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c index 189d130ca..1a1533a10 100644 --- a/fs/binfmt_em86.c +++ b/fs/binfmt_em86.c @@ -12,6 +12,8 @@ #include <linux/string.h> #include <linux/stat.h> #include <linux/malloc.h> +#include <linux/locks.h> +#include <linux/smp_lock.h> #include <linux/binfmts.h> #include <linux/elf.h> #include <linux/init.h> @@ -81,7 +83,7 @@ static int load_em86(struct linux_binprm *bprm,struct pt_regs *regs) * space, and we don't need to copy it. */ lock_kernel(); - dentry = open_namei(interp, 0, 0); + dentry = open_namei(interp); unlock_kernel(); if (IS_ERR(dentry)) return PTR_ERR(dentry); diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index c530a6ff2..9d98d7d70 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -213,7 +213,7 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) bprm->argc++; bprm->filename = iname; /* for binfmt_script */ - dentry = open_namei(iname, 0, 0); + dentry = open_namei(iname); retval = PTR_ERR(dentry); if (IS_ERR(dentry)) goto _ret; diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c index 84dbf11b0..450f918a4 100644 --- a/fs/binfmt_script.c +++ b/fs/binfmt_script.c @@ -82,7 +82,7 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs) * OK, now restart the process with the interpreter's dentry. */ lock_kernel(); - dentry = open_namei(interp, 0, 0); + dentry = open_namei(interp); unlock_kernel(); if (IS_ERR(dentry)) return PTR_ERR(dentry); diff --git a/fs/buffer.c b/fs/buffer.c index dabf1d39c..617188db0 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -147,13 +147,13 @@ void __wait_on_buffer(struct buffer_head * bh) atomic_inc(&bh->b_count); add_wait_queue(&bh->b_wait, &wait); -repeat: - run_task_queue(&tq_disk); - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (buffer_locked(bh)) { + do { + run_task_queue(&tq_disk); + set_task_state(tsk, TASK_UNINTERRUPTIBLE); + if (!buffer_locked(bh)) + break; schedule(); - goto repeat; - } + } while (buffer_locked(bh)); tsk->state = TASK_RUNNING; remove_wait_queue(&bh->b_wait, &wait); atomic_dec(&bh->b_count); diff --git a/fs/dquot.c b/fs/dquot.c index 61dcef366..c602697f5 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -66,6 +66,11 @@ static char *quotatypes[] = INITQFNAMES; static kmem_cache_t *dquot_cachep; +static inline struct quota_mount_options *sb_dqopt(struct super_block *sb) +{ + return &sb->s_dquot; +} + /* * Dquot List Management: * The quota code uses three lists for dquot management: the inuse_list, @@ -98,29 +103,20 @@ static DECLARE_WAIT_QUEUE_HEAD(update_wait); static void dqput(struct dquot *); static struct dquot *dqduplicate(struct dquot *); -static inline char is_enabled(struct vfsmount *vfsmnt, short type) +static inline char is_enabled(struct quota_mount_options *dqopt, short type) { switch (type) { case USRQUOTA: - return((vfsmnt->mnt_dquot.flags & DQUOT_USR_ENABLED) != 0); + return((dqopt->flags & DQUOT_USR_ENABLED) != 0); case GRPQUOTA: - return((vfsmnt->mnt_dquot.flags & DQUOT_GRP_ENABLED) != 0); + return((dqopt->flags & DQUOT_GRP_ENABLED) != 0); } return(0); } static inline char sb_has_quota_enabled(struct super_block *sb, short type) { - struct vfsmount *vfsmnt; - - return((vfsmnt = lookup_vfsmnt(sb->s_dev)) != (struct vfsmount *)NULL && is_enabled(vfsmnt, type)); -} - -static inline char dev_has_quota_enabled(kdev_t dev, short type) -{ - struct vfsmount *vfsmnt; - - return((vfsmnt = lookup_vfsmnt(dev)) != (struct vfsmount *)NULL && is_enabled(vfsmnt, type)); + return is_enabled(sb_dqopt(sb), type); } static inline int const hashfn(kdev_t dev, unsigned int id, short type) @@ -253,15 +249,15 @@ static void write_dquot(struct dquot *dquot) mm_segment_t fs; loff_t offset; ssize_t ret; - struct semaphore *sem = &dquot->dq_mnt->mnt_dquot.dqio_sem; + struct semaphore *sem = &dquot->dq_sb->s_dquot.dqio_sem; lock_dquot(dquot); - if (!dquot->dq_mnt) { /* Invalidated quota? */ + if (!dquot->dq_sb) { /* Invalidated quota? */ unlock_dquot(dquot); return; } down(sem); - filp = dquot->dq_mnt->mnt_dquot.files[type]; + filp = dquot->dq_sb->s_dquot.files[type]; offset = dqoff(dquot->dq_id); fs = get_fs(); set_fs(KERNEL_DS); @@ -293,20 +289,20 @@ static void read_dquot(struct dquot *dquot) mm_segment_t fs; loff_t offset; - filp = dquot->dq_mnt->mnt_dquot.files[type]; + filp = dquot->dq_sb->s_dquot.files[type]; if (filp == (struct file *)NULL) return; lock_dquot(dquot); - if (!dquot->dq_mnt) /* Invalidated quota? */ + if (!dquot->dq_sb) /* Invalidated quota? */ goto out_lock; /* Now we are sure filp is valid - the dquot isn't invalidated */ - down(&dquot->dq_mnt->mnt_dquot.dqio_sem); + down(&dquot->dq_sb->s_dquot.dqio_sem); offset = dqoff(dquot->dq_id); fs = get_fs(); set_fs(KERNEL_DS); filp->f_op->read(filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk), &offset); - up(&dquot->dq_mnt->mnt_dquot.dqio_sem); + up(&dquot->dq_sb->s_dquot.dqio_sem); set_fs(fs); if (dquot->dq_bhardlimit == 0 && dquot->dq_bsoftlimit == 0 && @@ -326,7 +322,7 @@ void clear_dquot(struct dquot *dquot) { /* unhash it first */ unhash_dquot(dquot); - dquot->dq_mnt = NULL; + dquot->dq_sb = NULL; dquot->dq_flags = 0; dquot->dq_referenced = 0; memset(&dquot->dq_dqb, 0, sizeof(struct dqblk)); @@ -346,7 +342,7 @@ restart: continue; if (dquot->dq_type != type) continue; - if (!dquot->dq_mnt) /* Already invalidated entry? */ + if (!dquot->dq_sb) /* Already invalidated entry? */ continue; if (dquot->dq_flags & DQ_LOCKED) { __wait_on_dquot(dquot); @@ -360,7 +356,7 @@ restart: continue; if (dquot->dq_type != type) continue; - if (!dquot->dq_mnt) + if (!dquot->dq_sb) continue; } /* @@ -368,7 +364,7 @@ restart: * the quota needn't to be written to disk. So we write it * ourselves before discarding the data just for sure... */ - if (dquot->dq_flags & DQ_MOD && dquot->dq_mnt) + if (dquot->dq_flags & DQ_MOD && dquot->dq_sb) { write_dquot(dquot); need_restart = 1; /* We slept on IO */ @@ -397,7 +393,7 @@ restart: continue; if (type != -1 && dquot->dq_type != type) continue; - if (!dquot->dq_mnt) /* Invalidated? */ + if (!dquot->dq_sb) /* Invalidated? */ continue; if (!(dquot->dq_flags & (DQ_LOCKED | DQ_MOD))) continue; @@ -435,11 +431,11 @@ static void dqput(struct dquot *dquot) } /* - * If the dq_mnt pointer isn't initialized this entry needs no + * If the dq_sb pointer isn't initialized this entry needs no * checking and doesn't need to be written. It's just an empty * dquot that is put back on to the freelist. */ - if (dquot->dq_mnt) + if (dquot->dq_sb) dqstats.drops++; we_slept: if (dquot->dq_count > 1) { @@ -451,7 +447,7 @@ we_slept: printk(KERN_ERR "VFS: Locked quota to be put on the free list.\n"); dquot->dq_flags &= ~DQ_LOCKED; } - if (dquot->dq_mnt && dquot->dq_flags & DQ_MOD) { + if (dquot->dq_sb && dquot->dq_flags & DQ_MOD) { write_dquot(dquot); goto we_slept; } @@ -571,17 +567,17 @@ pressure: goto repeat; } -struct dquot *dqget(kdev_t dev, unsigned int id, short type) +static struct dquot *dqget(struct super_block *sb, unsigned int id, short type) { - unsigned int hashent = hashfn(dev, id, type); + unsigned int hashent = hashfn(sb->s_dev, id, type); struct dquot *dquot, *empty = NULL; - struct vfsmount *vfsmnt; + struct quota_mount_options *dqopt = sb_dqopt(sb); - if ((vfsmnt = lookup_vfsmnt(dev)) == (struct vfsmount *)NULL || !is_enabled(vfsmnt, type)) + if (!is_enabled(dqopt, type)) return(NODQUOT); we_slept: - if ((dquot = find_dquot(hashent, dev, id, type)) == NULL) { + if ((dquot = find_dquot(hashent, sb->s_dev, id, type)) == NULL) { if (empty == NULL) { dquot_updating[hashent]++; empty = get_empty_dquot(); @@ -592,8 +588,8 @@ we_slept: dquot = empty; dquot->dq_id = id; dquot->dq_type = type; - dquot->dq_dev = dev; - dquot->dq_mnt = vfsmnt; + dquot->dq_dev = sb->s_dev; + dquot->dq_sb = sb; /* hash it first so it can be found */ hash_dquot(dquot); read_dquot(dquot); @@ -610,7 +606,7 @@ we_slept: while (dquot_updating[hashent]) sleep_on(&update_wait); - if (!dquot->dq_mnt) { /* Has somebody invalidated entry under us? */ + if (!dquot->dq_sb) { /* Has somebody invalidated entry under us? */ /* * Do it as if the quota was invalidated before we started */ @@ -625,11 +621,11 @@ we_slept: static struct dquot *dqduplicate(struct dquot *dquot) { - if (dquot == NODQUOT || !dquot->dq_mnt) + if (dquot == NODQUOT || !dquot->dq_sb) return NODQUOT; dquot->dq_count++; wait_on_dquot(dquot); - if (!dquot->dq_mnt) { + if (!dquot->dq_sb) { dquot->dq_count--; return NODQUOT; } @@ -642,13 +638,12 @@ static struct dquot *dqduplicate(struct dquot *dquot) static inline int is_quotafile(struct inode *inode) { int cnt; - struct vfsmount *vfsmnt; + struct quota_mount_options *dqopt = sb_dqopt(inode->i_sb); struct file **files; - vfsmnt = lookup_vfsmnt(inode->i_dev); - if (!vfsmnt) + if (!dqopt) return 0; - files = vfsmnt->mnt_dquot.files; + files = dqopt->files; for (cnt = 0; cnt < MAXQUOTAS; cnt++) if (files[cnt] && files[cnt]->f_dentry->d_inode == inode) return 1; @@ -671,13 +666,12 @@ static int dqinit_needed(struct inode *inode, short type) return 0; } -static void add_dquot_ref(kdev_t dev, short type) +static void add_dquot_ref(struct super_block *sb, short type) { - struct super_block *sb = get_super(dev); struct list_head *p; struct inode *inode; - if (!sb || !sb->dq_op) + if (!sb->dq_op) return; /* nothing to do */ restart: @@ -804,7 +798,7 @@ static void print_warning(struct dquot *dquot, int flag, const char *fmtstr) if (!need_print_warning(dquot, flag)) return; - root = dquot->dq_mnt->mnt_sb->s_root; + root = dquot->dq_sb->s_root; dget(root); buffer = (char *) __get_free_page(GFP_KERNEL); path = buffer ? d_path(root, buffer, PAGE_SIZE) : "?"; @@ -817,7 +811,7 @@ static void print_warning(struct dquot *dquot, int flag, const char *fmtstr) static inline char ignore_hardlimit(struct dquot *dquot) { - return capable(CAP_SYS_RESOURCE) && !dquot->dq_mnt->mnt_dquot.rsquash[dquot->dq_type]; + return capable(CAP_SYS_RESOURCE) && !dquot->dq_sb->s_dquot.rsquash[dquot->dq_type]; } static int check_idq(struct dquot *dquot, u_long inodes) @@ -844,7 +838,7 @@ static int check_idq(struct dquot *dquot, u_long inodes) (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit && dquot->dq_itime == 0) { print_warning(dquot, 0, "%s: warning, %s file quota exceeded\n"); - dquot->dq_itime = CURRENT_TIME + dquot->dq_mnt->mnt_dquot.inode_expire[dquot->dq_type]; + dquot->dq_itime = CURRENT_TIME + dquot->dq_sb->s_dquot.inode_expire[dquot->dq_type]; } return QUOTA_OK; @@ -877,7 +871,7 @@ static int check_bdq(struct dquot *dquot, u_long blocks, char prealloc) dquot->dq_btime == 0) { if (!prealloc) { print_warning(dquot, 0, "%s: warning, %s disk quota exceeded\n"); - dquot->dq_btime = CURRENT_TIME + dquot->dq_mnt->mnt_dquot.block_expire[dquot->dq_type]; + dquot->dq_btime = CURRENT_TIME + dquot->dq_sb->s_dquot.block_expire[dquot->dq_type]; } else /* @@ -894,7 +888,7 @@ static int check_bdq(struct dquot *dquot, u_long blocks, char prealloc) * Initialize a dquot-struct with new quota info. This is used by the * system call interface functions. */ -static int set_dqblk(kdev_t dev, int id, short type, int flags, struct dqblk *dqblk) +static int set_dqblk(struct super_block *sb, int id, short type, int flags, struct dqblk *dqblk) { struct dquot *dquot; int error = -EFAULT; @@ -909,7 +903,7 @@ static int set_dqblk(kdev_t dev, int id, short type, int flags, struct dqblk *dq } else memcpy((caddr_t)&dq_dqblk, (caddr_t)dqblk, sizeof(struct dqblk)); - if ((dquot = dqget(dev, id, type)) != NODQUOT) { + if (sb && (dquot = dqget(sb, id, type)) != NODQUOT) { lock_dquot(dquot); if (id > 0 && ((flags & SET_QUOTA) || (flags & SET_QLIMIT))) { @@ -923,22 +917,22 @@ static int set_dqblk(kdev_t dev, int id, short type, int flags, struct dqblk *dq if (dquot->dq_isoftlimit && dquot->dq_curinodes < dquot->dq_isoftlimit && dq_dqblk.dqb_curinodes >= dquot->dq_isoftlimit) - dquot->dq_itime = CURRENT_TIME + dquot->dq_mnt->mnt_dquot.inode_expire[type]; + dquot->dq_itime = CURRENT_TIME + dquot->dq_sb->s_dquot.inode_expire[type]; dquot->dq_curinodes = dq_dqblk.dqb_curinodes; if (dquot->dq_curinodes < dquot->dq_isoftlimit) dquot->dq_flags &= ~DQ_INODES; if (dquot->dq_bsoftlimit && dquot->dq_curblocks < dquot->dq_bsoftlimit && dq_dqblk.dqb_curblocks >= dquot->dq_bsoftlimit) - dquot->dq_btime = CURRENT_TIME + dquot->dq_mnt->mnt_dquot.block_expire[type]; + dquot->dq_btime = CURRENT_TIME + dquot->dq_sb->s_dquot.block_expire[type]; dquot->dq_curblocks = dq_dqblk.dqb_curblocks; if (dquot->dq_curblocks < dquot->dq_bsoftlimit) dquot->dq_flags &= ~DQ_BLKS; } if (id == 0) { - dquot->dq_mnt->mnt_dquot.block_expire[type] = dquot->dq_btime = dq_dqblk.dqb_btime; - dquot->dq_mnt->mnt_dquot.inode_expire[type] = dquot->dq_itime = dq_dqblk.dqb_itime; + dquot->dq_sb->s_dquot.block_expire[type] = dquot->dq_btime = dq_dqblk.dqb_btime; + dquot->dq_sb->s_dquot.inode_expire[type] = dquot->dq_itime = dq_dqblk.dqb_itime; } if (dq_dqblk.dqb_bhardlimit == 0 && dq_dqblk.dqb_bsoftlimit == 0 && @@ -954,14 +948,14 @@ static int set_dqblk(kdev_t dev, int id, short type, int flags, struct dqblk *dq return(0); } -static int get_quota(kdev_t dev, int id, short type, struct dqblk *dqblk) +static int get_quota(struct super_block *sb, int id, short type, struct dqblk *dqblk) { struct dquot *dquot; int error = -ESRCH; - if (!dev_has_quota_enabled(dev, type)) + if (!sb || !sb_has_quota_enabled(sb, type)) goto out; - dquot = dqget(dev, id, type); + dquot = dqget(sb, id, type); if (dquot == NODQUOT) goto out; @@ -990,17 +984,16 @@ static int get_stats(caddr_t addr) return error; } -static int quota_root_squash(kdev_t dev, short type, int *addr) +static int quota_root_squash(struct super_block *sb, short type, int *addr) { - struct vfsmount *vfsmnt; int new_value, error; - if ((vfsmnt = lookup_vfsmnt(dev)) == (struct vfsmount *)NULL) + if (!sb) return(-ENODEV); error = -EFAULT; if (!copy_from_user(&new_value, addr, sizeof(int))) { - vfsmnt->mnt_dquot.rsquash[type] = new_value; + sb_dqopt(sb)->rsquash[type] = new_value; error = 0; } return error; @@ -1063,7 +1056,7 @@ void dquot_initialize(struct inode *inode, short type) id = inode->i_gid; break; } - dquot = dqget(inode->i_dev, id, cnt); + dquot = dqget(inode->i_sb, id, cnt); if (dquot == NODQUOT) continue; if (inode->i_dquot[cnt] != NODQUOT) { @@ -1219,10 +1212,13 @@ int dquot_transfer(struct dentry *dentry, struct iattr *iattr) if (!inode) return -ENOENT; + /* Arguably we could consider that as error, but... no fs - no quota */ + if (!inode->i_sb) + return 0; /* * Find out if this filesystem uses i_blocks. */ - if (!inode->i_sb || !inode->i_sb->s_blocksize) + if (!inode->i_sb->s_blocksize) blocks = isize_to_blocks(inode->i_size, BLOCK_SIZE_BITS); else blocks = (inode->i_blocks >> 1); @@ -1243,14 +1239,14 @@ int dquot_transfer(struct dentry *dentry, struct iattr *iattr) if (inode->i_uid == iattr->ia_uid) continue; /* We can get transfer_from from inode, can't we? */ - transfer_from[cnt] = dqget(inode->i_dev, inode->i_uid, cnt); - transfer_to[cnt] = dqget(inode->i_dev, iattr->ia_uid, cnt); + transfer_from[cnt] = dqget(inode->i_sb, inode->i_uid, cnt); + transfer_to[cnt] = dqget(inode->i_sb, iattr->ia_uid, cnt); break; case GRPQUOTA: if (inode->i_gid == iattr->ia_gid) continue; - transfer_from[cnt] = dqget(inode->i_dev, inode->i_gid, cnt); - transfer_to[cnt] = dqget(inode->i_dev, iattr->ia_gid, cnt); + transfer_from[cnt] = dqget(inode->i_sb, inode->i_gid, cnt); + transfer_to[cnt] = dqget(inode->i_sb, iattr->ia_gid, cnt); break; } @@ -1286,7 +1282,7 @@ int dquot_transfer(struct dentry *dentry, struct iattr *iattr) * dqget() could block and so the first structure might got * invalidated or locked... */ - if (!transfer_to[cnt]->dq_mnt || !transfer_from[cnt]->dq_mnt || + if (!transfer_to[cnt]->dq_sb || !transfer_from[cnt]->dq_sb || check_idq(transfer_to[cnt], 1) == NO_QUOTA || check_bdq(transfer_to[cnt], blocks, 0) == NO_QUOTA) { cnt++; @@ -1371,26 +1367,26 @@ struct dquot_operations dquot_operations = { dquot_transfer }; -static inline void set_enable_flags(struct vfsmount *vfsmnt, short type) +static inline void set_enable_flags(struct quota_mount_options *dqopt, short type) { switch (type) { case USRQUOTA: - vfsmnt->mnt_dquot.flags |= DQUOT_USR_ENABLED; + dqopt->flags |= DQUOT_USR_ENABLED; break; case GRPQUOTA: - vfsmnt->mnt_dquot.flags |= DQUOT_GRP_ENABLED; + dqopt->flags |= DQUOT_GRP_ENABLED; break; } } -static inline void reset_enable_flags(struct vfsmount *vfsmnt, short type) +static inline void reset_enable_flags(struct quota_mount_options *dqopt, short type) { switch (type) { case USRQUOTA: - vfsmnt->mnt_dquot.flags &= ~DQUOT_USR_ENABLED; + dqopt->flags &= ~DQUOT_USR_ENABLED; break; case GRPQUOTA: - vfsmnt->mnt_dquot.flags &= ~DQUOT_GRP_ENABLED; + dqopt->flags &= ~DQUOT_GRP_ENABLED; break; } } @@ -1401,38 +1397,36 @@ extern void remove_dquot_ref(kdev_t, short); /* * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount) */ -int quota_off(kdev_t dev, short type) +int quota_off(struct super_block *sb, short type) { - struct vfsmount *vfsmnt; struct file *filp; short cnt; int enabled = 0; + struct quota_mount_options *dqopt = sb_dqopt(sb); - /* We don't need to search for vfsmnt each time - umount has to wait for us */ - vfsmnt = lookup_vfsmnt(dev); - if (!vfsmnt || !vfsmnt->mnt_sb) + if (!sb) goto out; /* We need to serialize quota_off() for device */ - down(&vfsmnt->mnt_dquot.dqoff_sem); + down(&dqopt->dqoff_sem); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (type != -1 && cnt != type) continue; - if (!is_enabled(vfsmnt, cnt)) + if (!is_enabled(dqopt, cnt)) continue; - reset_enable_flags(vfsmnt, cnt); + reset_enable_flags(dqopt, cnt); /* Note: these are blocking operations */ - remove_dquot_ref(dev, cnt); - invalidate_dquots(dev, cnt); + remove_dquot_ref(sb->s_dev, cnt); + invalidate_dquots(sb->s_dev, cnt); /* Wait for any pending IO - remove me as soon as invalidate is more polite */ - down(&vfsmnt->mnt_dquot.dqio_sem); - filp = vfsmnt->mnt_dquot.files[cnt]; - vfsmnt->mnt_dquot.files[cnt] = (struct file *)NULL; - vfsmnt->mnt_dquot.inode_expire[cnt] = 0; - vfsmnt->mnt_dquot.block_expire[cnt] = 0; - up(&vfsmnt->mnt_dquot.dqio_sem); + down(&dqopt->dqio_sem); + filp = dqopt->files[cnt]; + dqopt->files[cnt] = (struct file *)NULL; + dqopt->inode_expire[cnt] = 0; + dqopt->block_expire[cnt] = 0; + up(&dqopt->dqio_sem); fput(filp); } @@ -1441,10 +1435,10 @@ int quota_off(kdev_t dev, short type) * and if not clear the dq_op pointer. */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) - enabled |= is_enabled(vfsmnt, cnt); + enabled |= is_enabled(dqopt, cnt); if (!enabled) - vfsmnt->mnt_sb->dq_op = NULL; - up(&vfsmnt->mnt_dquot.dqoff_sem); + sb->dq_op = NULL; + up(&dqopt->dqoff_sem); out: return(0); } @@ -1457,31 +1451,25 @@ static inline int check_quotafile_size(loff_t size) return !(((blocks % sizeof(struct dqblk)) * BLOCK_SIZE + off % sizeof(struct dqblk)) % sizeof(struct dqblk)); } -int quota_on(kdev_t dev, short type, char *path) +static int quota_on(struct super_block *sb, short type, char *path) { struct file *f; - struct vfsmount *vfsmnt; struct inode *inode; struct dquot *dquot; - struct quota_mount_options *mnt_dquot; + struct quota_mount_options *dqopt = sb_dqopt(sb); char *tmp; int error; - vfsmnt = lookup_vfsmnt(dev); - if (vfsmnt == (struct vfsmount *)NULL) - return -ENODEV; - - if (is_enabled(vfsmnt, type)) + if (is_enabled(dqopt, type)) return -EBUSY; - mnt_dquot = &vfsmnt->mnt_dquot; - down(&mnt_dquot->dqoff_sem); + down(&dqopt->dqoff_sem); tmp = getname(path); error = PTR_ERR(tmp); if (IS_ERR(tmp)) goto out_lock; - f = filp_open(tmp, O_RDWR, 0600); + f = filp_open(tmp, O_RDWR, 0600, NULL); putname(tmp); error = PTR_ERR(f); @@ -1499,24 +1487,24 @@ int quota_on(kdev_t dev, short type, char *path) goto out_f; dquot_drop(inode); /* We don't want quota on quota files */ - set_enable_flags(vfsmnt, type); - mnt_dquot->files[type] = f; + set_enable_flags(dqopt, type); + dqopt->files[type] = f; - dquot = dqget(dev, 0, type); - mnt_dquot->inode_expire[type] = (dquot != NODQUOT) ? dquot->dq_itime : MAX_IQ_TIME; - mnt_dquot->block_expire[type] = (dquot != NODQUOT) ? dquot->dq_btime : MAX_DQ_TIME; + dquot = dqget(sb, 0, type); + dqopt->inode_expire[type] = (dquot != NODQUOT) ? dquot->dq_itime : MAX_IQ_TIME; + dqopt->block_expire[type] = (dquot != NODQUOT) ? dquot->dq_btime : MAX_DQ_TIME; dqput(dquot); - vfsmnt->mnt_sb->dq_op = &dquot_operations; - add_dquot_ref(dev, type); + sb->dq_op = &dquot_operations; + add_dquot_ref(sb, type); - up(&mnt_dquot->dqoff_sem); + up(&dqopt->dqoff_sem); return 0; out_f: filp_close(f, NULL); out_lock: - up(&mnt_dquot->dqoff_sem); + up(&dqopt->dqoff_sem); return error; } @@ -1531,6 +1519,7 @@ asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr) { int cmds = 0, type = 0, flags = 0; kdev_t dev; + struct super_block *sb = NULL; int ret = -EINVAL; lock_kernel(); @@ -1575,18 +1564,19 @@ asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr) ret = -ENOTBLK; if (!S_ISBLK(mode)) goto out; + sb = get_super(dev); } ret = -EINVAL; switch (cmds) { case Q_QUOTAON: - ret = quota_on(dev, type, (char *) addr); + ret = sb ? quota_on(sb, type, (char *) addr) : -ENODEV; goto out; case Q_QUOTAOFF: - ret = quota_off(dev, type); + ret = quota_off(sb, type); goto out; case Q_GETQUOTA: - ret = get_quota(dev, id, type, (struct dqblk *) addr); + ret = get_quota(sb, id, type, (struct dqblk *) addr); goto out; case Q_SETQUOTA: flags |= SET_QUOTA; @@ -1604,7 +1594,7 @@ asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr) ret = get_stats(addr); goto out; case Q_RSQUASH: - ret = quota_root_squash(dev, type, (int *) addr); + ret = quota_root_squash(sb, type, (int *) addr); goto out; default: goto out; @@ -1613,8 +1603,8 @@ asmlinkage long sys_quotactl(int cmd, const char *special, int id, caddr_t addr) flags |= QUOTA_SYSCALL; ret = -ESRCH; - if (dev_has_quota_enabled(dev, type)) - ret = set_dqblk(dev, id, type, flags, (struct dqblk *) addr); + if (sb && sb_has_quota_enabled(sb, type)) + ret = set_dqblk(sb, id, type, flags, (struct dqblk *) addr); out: unlock_kernel(); return ret; @@ -165,14 +165,12 @@ asmlinkage long sys_uselib(const char * library) if (file && file->f_dentry && file->f_op && file->f_op->read) { spin_lock(&binfmt_lock); for (fmt = formats ; fmt ; fmt = fmt->next) { - int (*fn)(int) = fmt->load_shlib; - if (!fn) + if (!fmt->load_shlib) continue; if (!try_inc_mod_count(fmt->module)) continue; spin_unlock(&binfmt_lock); - /* N.B. Should use file instead of fd */ - retval = fn(fd); + retval = fmt->load_shlib(file); spin_lock(&binfmt_lock); put_binfmt(fmt); if (retval != -ENOEXEC) @@ -718,6 +716,8 @@ void compute_creds(struct linux_binprm *bprm) if (current->euid != current->uid || current->egid != current->gid || !cap_issubset(new_permitted, current->cap_permitted)) current->dumpable = 0; + + current->keep_capabilities = 0; } @@ -775,7 +775,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) bprm_loader.page[i] = NULL; lock_kernel(); - dentry = open_namei(dynloader[0], 0, 0); + dentry = open_namei(dynloader[0]); unlock_kernel(); retval = PTR_ERR(dentry); if (IS_ERR(dentry)) @@ -855,7 +855,7 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0])); lock_kernel(); - dentry = open_namei(filename, 0, 0); + dentry = open_namei(filename); unlock_kernel(); retval = PTR_ERR(dentry); @@ -944,7 +944,7 @@ int do_coredump(long signr, struct pt_regs * regs) #else corename[4] = '\0'; #endif - file = filp_open(corename, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600); + file = filp_open(corename, O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600, NULL); if (IS_ERR(file)) goto fail; dentry = file->f_dentry; diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 67dedf6d6..3a18b375c 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -137,8 +137,8 @@ revalidate: bh, offset)) { /* On error, skip the f_pos to the next block. */ - filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1)) - + sb->s_blocksize; + filp->f_pos = (filp->f_pos | (sb->s_blocksize - 1)) + + 1; brelse (bh); return stored; } diff --git a/fs/namei.c b/fs/namei.c index 97c239929..8675e28c5 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -451,6 +451,76 @@ no_inode: } /* + * Restricted form of lookup. Doesn't follow links, single-component only, + * needs parent already locked. Doesn't follow mounts. + */ +struct dentry * lookup_one(const char * name, struct dentry * base) +{ + struct dentry * dentry; + struct inode *inode; + int err; + unsigned long hash; + struct qstr this; + unsigned int c; + + inode = base->d_inode; + err = permission(inode, MAY_EXEC); + dentry = ERR_PTR(err); + if (err) + goto out; + + this.name = name; + c = *(const unsigned char *)name; + if (!c) + goto access; + + hash = init_name_hash(); + do { + name++; + if (c == '/') + goto access; + hash = partial_name_hash(c, hash); + c = *(const unsigned char *)name; + } while (c); + this.len = name - (const char *) this.name; + this.hash = end_name_hash(hash); + + /* + * See if the low-level filesystem might want + * to use its own hash.. + */ + if (base->d_op && base->d_op->d_hash) { + err = base->d_op->d_hash(base, &this); + dentry = ERR_PTR(err); + if (err < 0) + goto out; + } + + dentry = cached_lookup(base, &this, 0); + if (!dentry) { + struct dentry *new = d_alloc(base, &this); + dentry = ERR_PTR(-ENOMEM); + if (!new) + goto out; + dentry = inode->i_op->lookup(inode, new); + if (!dentry) + dentry = new; + else { + dput(new); + if (IS_ERR(dentry)) + goto out; + } + } + +out: + dput(base); + return dentry; +access: + dentry = ERR_PTR(-EACCES); + goto out; +} + +/* * namei() * * is used by most simple commands to get the inode of a specified name. @@ -609,13 +679,13 @@ exit_lock: * which is a lot more logical, and also allows the "no perm" needed * for symlinks (where the permissions are checked later). */ -struct dentry * open_namei(const char * pathname, int flag, int mode) +struct dentry * __open_namei(const char * pathname, int flag, int mode, struct dentry * dir) { int acc_mode, error; struct inode *inode; struct dentry *dentry; - dentry = lookup_dentry(pathname, NULL, lookup_flags(flag)); + dentry = lookup_dentry(pathname, dir, lookup_flags(flag)); if (IS_ERR(dentry)) return dentry; @@ -1012,13 +1082,13 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) return error; } -int do_unlink(const char * name) +int do_unlink(const char * name, struct dentry * base) { int error; struct dentry *dir; struct dentry *dentry; - dentry = lookup_dentry(name, NULL, 0); + dentry = lookup_dentry(name, base, 0); error = PTR_ERR(dentry); if (IS_ERR(dentry)) goto exit; @@ -1043,7 +1113,7 @@ asmlinkage long sys_unlink(const char * pathname) if(IS_ERR(tmp)) return PTR_ERR(tmp); lock_kernel(); - error = do_unlink(tmp); + error = do_unlink(tmp, NULL); unlock_kernel(); putname(tmp); @@ -1427,16 +1497,17 @@ asmlinkage long sys_rename(const char * oldname, const char * newname) int vfs_readlink(struct dentry *dentry, char *buffer, int buflen, const char *link) { - u32 len; + int len; len = PTR_ERR(link); if (IS_ERR(link)) goto out; len = strlen(link); - if (len > buflen) + if (len > (unsigned) buflen) len = buflen; - copy_to_user(buffer, link, len); + if (copy_to_user(buffer, link, len)) + len = -EFAULT; out: return len; } diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 7dc5739eb..6e102db9c 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -727,25 +727,40 @@ encode_entry(struct readdir_cd *cd, const char *name, /* throw in readdirplus baggage */ if (plus) { struct svc_fh fh; + struct svc_export *exp; + struct dentry *dparent, *dchild; + + dparent = cd->dirfh->fh_dentry; + exp = cd->dirfh->fh_export; fh_init(&fh, NFS3_FHSIZE); - /* Disabled for now because of lock-up */ - if (0 && nfsd_lookup(cd->rqstp, cd->dirfh, name, namlen, &fh) == 0) { - p = encode_post_op_attr(cd->rqstp, p, fh.fh_dentry); - p = encode_fh(p, &fh); - fh_put(&fh); - } else { - /* Didn't find this entry... weird. - * Proceed without the attrs anf fh anyway. - */ - *p++ = 0; - *p++ = 0; - } + if (fh_verify(cd->rqstp, cd->dirfh, S_IFDIR, MAY_EXEC) != 0) + goto noexec; + if (isdotent(name, namlen)) { + dchild = dparent; + if (namlen == 2) + dchild = dchild->d_parent; + dchild = dget(dchild); + } else + dchild = lookup_one(name, dget(dparent)); + if (IS_ERR(dchild)) + goto noexec; + if (fh_compose(&fh, exp, dchild) != 0 || !dchild->d_inode) + goto noexec; + p = encode_post_op_attr(cd->rqstp, p, fh.fh_dentry); + p = encode_fh(p, &fh); + fh_put(&fh); } +out: cd->buflen = buflen; cd->buffer = p; return 0; + +noexec: + *p++ = 0; + *p++ = 0; + goto out; } int diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 815208e09..f755adc8c 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -42,8 +42,10 @@ static int nfsctl_export(struct nfsctl_export *data); static int nfsctl_unexport(struct nfsctl_export *data); static int nfsctl_getfh(struct nfsctl_fhparm *, __u8 *); static int nfsctl_getfd(struct nfsctl_fdparm *, __u8 *); +#ifdef notyet static int nfsctl_getfs(struct nfsctl_fsparm *, struct knfsd_fh *); -/* static int nfsctl_ugidupdate(struct nfsctl_ugidmap *data); */ +static int nfsctl_ugidupdate(struct nfsctl_ugidmap *data); +#endif static int initialized = 0; diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 7baab32d9..a5fcdcf7d 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -147,7 +147,7 @@ static struct dentry *nfsd_iget(struct super_block *sb, unsigned long ino, __u32 generation); iput(inode); - return NULL; + return ERR_PTR(-ESTALE); } /* now to find a dentry. * If possible, get a well-connected one @@ -353,10 +353,6 @@ find_fh_dentry(struct super_block *sb, ino_t ino, int generation, ino_t dirino, if (IS_ERR(result)) goto err_out; err = -ESTALE; - if (!result) { - dprintk("find_fh_dentry: No inode found.\n"); - goto err_out; - } if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) return result; diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 7d570299f..6f69225cc 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -195,6 +195,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, svc_fh *newfhp = &resp->fh; struct iattr *attr = &argp->attrs; struct inode *inode; + struct dentry *dchild; int nfserr, type, mode, rdonly = 0; dev_t rdev = NODEV; @@ -214,14 +215,24 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, } else if (nfserr) goto done; - /* - * Do a lookup to verify the new file handle. - */ + nfserr = nfserr_acces; + if (!argp->len) + goto done; + nfserr = nfserr_exist; + if (isdotent(argp->name, argp->len)) + goto done; + fh_lock(dirfhp); + dchild = lookup_one(argp->name, dget(dirfhp->fh_dentry)); + nfserr = nfserrno(PTR_ERR(dchild)); + if (IS_ERR(dchild)) + goto out_unlock; fh_init(newfhp, NFS_FHSIZE); - nfserr = nfsd_lookup(rqstp, dirfhp, argp->name, argp->len, newfhp); + nfserr = fh_compose(newfhp, dirfhp->fh_export, dchild); + if (!nfserr && !dchild->d_inode) + nfserr = nfserr_noent; if (nfserr) { if (nfserr != nfserr_noent) - goto done; + goto out_unlock; /* * If the new file handle wasn't verified, we can't tell * whether the file exists or not. Time to bail ... @@ -230,22 +241,11 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, if (!newfhp->fh_dverified) { printk(KERN_WARNING "nfsd_proc_create: file handle not verified\n"); - goto done; + goto out_unlock; } } - /* - * Lock the parent directory and check for existence. - */ - nfserr = fh_lock_parent(dirfhp, newfhp->fh_dentry); - if (nfserr) - goto done; inode = newfhp->fh_dentry->d_inode; - if (inode && newfhp->fh_handle.fh_fileid_type == 0) - /* inode might have been instantiated while we slept */ - nfserr = fh_update(newfhp); - if (nfserr) - goto done; /* Unfudge the mode bits */ if (attr->ia_valid & ATTR_MODE) { diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 06a795841..e3be271a2 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -52,9 +52,6 @@ */ #define IS_ISMNDLK(i) (S_ISREG((i)->i_mode) && MANDATORY_LOCK(i)) -/* Check for dir entries '.' and '..' */ -#define isdotent(n, l) (l < 3 && n[0] == '.' && (l == 1 || n[1] == '.')) - /* * This is a cache of readahead params that help us choose the proper * readahead strategy. Initially, we set all readahead parameters to 0 @@ -77,47 +74,6 @@ struct raparms { static struct raparms * raparml = NULL; static struct raparms * raparm_cache = NULL; - -/* - * We need to do a check-parent every time - * after we have locked the parent - to verify - * that the parent is still our parent and - * that we are still hashed onto it.. - * - * This is required in case two processes race - * on removing (or moving) the same entry: the - * parent lock will serialize them, but the - * other process will be too late.. - * - * Note that this nfsd_check_parent is identical - * the check_parent in linux/fs/namei.c. - */ -#define nfsd_check_parent(dir, dentry) \ - ((dir) == (dentry)->d_parent && !d_unhashed(dentry)) - -/* - * Lock a parent directory following the VFS locking protocol. - */ -int -fh_lock_parent(struct svc_fh *parent_fh, struct dentry *dchild) -{ - fh_lock(parent_fh); - /* - * Make sure the parent->child relationship still holds, - * and that the child is still hashed. - */ - if (nfsd_check_parent(parent_fh->fh_dentry, dchild)) - return 0; - - printk(KERN_WARNING - "fh_lock_parent: %s/%s parent changed or child unhashed\n", - dchild->d_parent->d_name.name, dchild->d_name.name); - - fh_unlock(parent_fh); - return nfserr_noent; -} - - /* * Look up one component of a pathname. * N.B. After this call _both_ fhp and resfh need an fh_put @@ -156,35 +112,57 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, err = nfserr_acces; /* Lookup the name, but don't follow links */ - if (strcmp(name,"..")==0 && dparent->d_covers != dparent) - dchild = dget(dparent); - else + if (strcmp(name, "..")==0) { + /* checking mountpoint crossing is very different when stepping up */ + if (dparent == exp->ex_dentry) { + if (!EX_CROSSMNT(exp)) + dchild = dget(dparent); /* .. == . just like at / */ + else + { + struct svc_export *exp2 = NULL; + struct dentry *dp; + dchild = dparent->d_covers->d_parent; + for (dp=dchild; + exp2 == NULL && dp->d_covers->d_parent != dp; + dp=dp->d_covers->d_parent) + exp2 = exp_get(exp->ex_client, dp->d_inode->i_dev, dp->d_inode->i_ino); + if (exp2==NULL || dchild->d_sb != exp2->ex_dentry->d_sb) { + dchild = dget(dparent); + } else { + dget(dchild); + exp = exp2; + } + } + } else + dchild = dget(dparent->d_parent); + } else { dchild = lookup_dentry(name, dget(dparent), 0); - if (IS_ERR(dchild)) - goto out_nfserr; - /* - * check if we have crossed a mount point ... - */ - if (dchild->d_sb != dparent->d_sb) { - struct svc_export *exp2 = NULL; - exp2 = exp_get(rqstp->rq_client, - dchild->d_inode->i_dev, - dchild->d_inode->i_ino); - if (exp2 && EX_CROSSMNT(exp2)) - /* successfully crossed mount point */ - exp = exp2; - else if (dchild->d_covers->d_sb == dparent->d_sb) { - /* stay in the original filesystem */ - struct dentry *tdentry = dget(dchild->d_covers); - dput(dchild); - dchild = tdentry; - } else { - /* This cannot possibly happen */ - printk("nfsd_lookup: %s/%s impossible mount point!\n", dparent->d_name.name, dchild->d_name.name); - dput(dchild); - err = nfserr_acces; - goto out; + if (IS_ERR(dchild)) + goto out_nfserr; + /* + * check if we have crossed a mount point ... + */ + if (dchild->d_sb != dparent->d_sb) { + struct svc_export *exp2 = NULL; + exp2 = exp_get(rqstp->rq_client, + dchild->d_inode->i_dev, + dchild->d_inode->i_ino); + if (exp2 && EX_CROSSMNT(exp2)) + /* successfully crossed mount point */ + exp = exp2; + else if (dchild->d_covers->d_sb == dparent->d_sb) { + /* stay in the original filesystem */ + struct dentry *tdentry = dget(dchild->d_covers); + dput(dchild); + dchild = tdentry; + } else { + /* This cannot possibly happen */ + printk("nfsd_lookup: %s/%s impossible mount point!\n", dparent->d_name.name, dchild->d_name.name); + dput(dchild); + err = nfserr_acces; + goto out; + } } } /* @@ -216,6 +194,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap) int imode; int err; kernel_cap_t saved_cap = 0; + int size_change = 0; if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE)) accmode |= MAY_WRITE; @@ -305,14 +284,31 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap) saved_cap = current->cap_effective; cap_clear(current->cap_effective); } +#ifdef CONFIG_QUOTA + /* DQUOT_TRANSFER needs both ia_uid and ia_gid defined */ + if (iap->ia_valid & (ATTR_UID|ATTR_GID)) { + if (! (iap->ia_valid & ATTR_UID)) + iap->ia_uid = inode->i_uid; + if (! (iap->ia_valid & ATTR_GID)) + iap->ia_gid = inode->i_gid; + iap->ia_valid |= ATTR_UID|ATTR_GID; + } +#endif /* CONFIG_QUOTA */ + if (iap->ia_valid & ATTR_SIZE) { fh_lock(fhp); + size_change = 1; + } +#ifdef CONFIG_QUOTA + if (iap->ia_valid & (ATTR_UID|ATTR_GID)) + err = DQUOT_TRANSFER(dentry, iap); + else +#endif err = notify_change(dentry, iap); + if (size_change) { fh_unlock(fhp); put_write_access(inode); } - else - err = notify_change(dentry, iap); if (current->fsuid != 0) current->cap_effective = saved_cap; if (err) @@ -647,11 +643,11 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, uid_t saved_euid; #endif - if (!cnt) - goto out; err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file); if (err) goto out; + if (!cnt) + goto out_close; err = nfserr_perm; if (!file.f_op->write) goto out_close; @@ -812,6 +808,9 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, err = nfserr_perm; if (!flen) goto out; + err = nfserr_exist; + if (isdotent(fname, flen)) + goto out; err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE); if (err) @@ -829,14 +828,11 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, */ if (!resfhp->fh_dverified) { /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */ - dchild = lookup_dentry(fname, dget(dentry), 0); + fh_lock(fhp); + dchild = lookup_one(fname, dget(dentry)); err = PTR_ERR(dchild); if (IS_ERR(dchild)) goto out_nfserr; - /* Lock the parent and check for errors ... */ - err = fh_lock_parent(fhp, dchild); - if (err) - goto out; err = fh_compose(resfhp, fhp->fh_export, dchild); if (err) goto out; @@ -934,6 +930,9 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, err = nfserr_perm; if (!flen) goto out; + err = nfserr_exist; + if (isdotent(fname, flen)) + goto out; if (!(iap->ia_valid & ATTR_MODE)) iap->ia_mode = 0; err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE); @@ -948,21 +947,16 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, err = nfserr_notdir; if(!dirp->i_op || !dirp->i_op->lookup) goto out; + fh_lock(fhp); /* * Compose the response file handle. */ - dchild = lookup_dentry(fname, dget(dentry), 0); + dchild = lookup_one(fname, dget(dentry)); err = PTR_ERR(dchild); if(IS_ERR(dchild)) goto out_nfserr; - /* - * We must lock the directory before we check for the inode. - */ - err = fh_lock_parent(fhp, dchild); - if (err) - goto out; err = fh_compose(resfhp, fhp->fh_export, dchild); if (err) goto out; @@ -1096,24 +1090,20 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, err = nfserr_noent; if (!flen || !plen) goto out; + err = nfserr_exist; + if (isdotent(fname, flen)) + goto out; err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE); if (err) goto out; + fh_lock(fhp); dentry = fhp->fh_dentry; - - dnew = lookup_dentry(fname, dget(dentry), 0); + dnew = lookup_one(fname, dget(dentry)); err = PTR_ERR(dnew); if (IS_ERR(dnew)) goto out_nfserr; - /* - * Lock the parent before checking for existence - */ - err = fh_lock_parent(fhp, dnew); - if (err) - goto out_compose; - err = vfs_symlink(dentry->d_inode, dnew, path); if (!err) { if (EX_ISSYNC(fhp->fh_export)) @@ -1134,7 +1124,6 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, fh_unlock(fhp); /* Compose the fh so the dentry will be freed ... */ -out_compose: cerr = fh_compose(resfhp, fhp->fh_export, dnew); if (err==0) err = cerr; out: @@ -1167,20 +1156,18 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, err = nfserr_perm; if (!len) goto out; + err = nfserr_exist; + if (isdotent(fname, len)) + goto out; + fh_lock(ffhp); ddir = ffhp->fh_dentry; dirp = ddir->d_inode; - dnew = lookup_dentry(fname, dget(ddir), 0); + dnew = lookup_one(fname, dget(ddir)); err = PTR_ERR(dnew); if (IS_ERR(dnew)) goto out_nfserr; - /* - * Lock the parent before checking for existence - */ - err = fh_lock_parent(ffhp, dnew); - if (err) - goto out_dput; dold = tfhp->fh_dentry; dest = dold->d_inode; @@ -1199,7 +1186,6 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, } fh_unlock(ffhp); -out_dput: dput(dnew); out: return err; @@ -1210,29 +1196,6 @@ out_nfserr: } /* - * This follows the model of double_lock() in the VFS. - */ -static inline void nfsd_double_down(struct semaphore *s1, struct semaphore *s2) -{ - if (s1 != s2) { - if ((unsigned long) s1 < (unsigned long) s2) { - struct semaphore *tmp = s1; - s1 = s2; - s2 = tmp; - } - down(s1); - } - down(s2); -} - -static inline void nfsd_double_up(struct semaphore *s1, struct semaphore *s2) -{ - up(s1); - if (s1 != s2) - up(s2); -} - -/* * Rename a file * N.B. After this call _both_ ffhp and tfhp need an fh_put */ @@ -1261,15 +1224,12 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, if (fdir->i_dev != tdir->i_dev) goto out; - /* N.B. We shouldn't need this ... dentry layer handles it */ err = nfserr_perm; - if (!flen || (fname[0] == '.' && - (flen == 1 || (flen == 2 && fname[1] == '.'))) || - !tlen || (tname[0] == '.' && - (tlen == 1 || (tlen == 2 && tname[1] == '.')))) + if (!flen || isdotent(fname, flen) || !tlen || isdotent(tname, tlen)) goto out; - odentry = lookup_dentry(fname, dget(fdentry), 0); + double_down(&tdir->i_sem, &fdir->i_sem); + odentry = lookup_one(fname, dget(fdentry)); err = PTR_ERR(odentry); if (IS_ERR(odentry)) goto out_nfserr; @@ -1278,16 +1238,11 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, if (!odentry->d_inode) goto out_dput_old; - ndentry = lookup_dentry(tname, dget(tdentry), 0); + ndentry = lookup_one(tname, dget(tdentry)); err = PTR_ERR(ndentry); if (IS_ERR(ndentry)) goto out_dput_old; - /* - * Lock the parent directories. - */ - nfsd_double_down(&tdir->i_sem, &fdir->i_sem); - #ifdef CONFIG_NFSD_V3 /* Fill in the pre-op attr for the wcc data for both * tdir and fdir @@ -1296,19 +1251,11 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, fill_pre_wcc(tfhp); #endif /* CONFIG_NFSD_V3 */ - err = -ENOENT; - /* GAM3 check for parent changes after locking. */ - if (nfsd_check_parent(fdentry, odentry) && - nfsd_check_parent(tdentry, ndentry)) { - - err = vfs_rename(fdir, odentry, tdir, ndentry); - if (!err && EX_ISSYNC(tfhp->fh_export)) { - nfsd_sync_dir(tdentry); - nfsd_sync_dir(fdentry); - } - } else - dprintk("nfsd: Caught race in nfsd_rename"); - + err = vfs_rename(fdir, odentry, tdir, ndentry); + if (!err && EX_ISSYNC(tfhp->fh_export)) { + nfsd_sync_dir(tdentry); + nfsd_sync_dir(fdentry); + } #ifdef CONFIG_NFSD_V3 /* Fill in the post-op attr for the wcc data for both * tdir and fdir @@ -1316,7 +1263,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, fill_post_wcc(ffhp); fill_post_wcc(tfhp); #endif /* CONFIG_NFSD_V3 */ - nfsd_double_up(&tdir->i_sem, &fdir->i_sem); + double_up(&tdir->i_sem, &fdir->i_sem); dput(ndentry); out_dput_old: @@ -1343,7 +1290,6 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, struct inode *dirp; int err; - /* N.B. We shouldn't need this test ... handled by dentry layer */ err = nfserr_acces; if (!flen || isdotent(fname, flen)) goto out; @@ -1351,10 +1297,11 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, if (err) goto out; + fh_lock(fhp); dentry = fhp->fh_dentry; dirp = dentry->d_inode; - rdentry = lookup_dentry(fname, dget(dentry), 0); + rdentry = lookup_one(fname, dget(dentry)); err = PTR_ERR(rdentry); if (IS_ERR(rdentry)) goto out_nfserr; @@ -1365,12 +1312,6 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, goto out; } - err = fh_lock_parent(fhp, rdentry); - if (err) { - dput(rdentry); - goto out; - } - if (type != S_IFDIR) { /* It's UNLINK */ err = vfs_unlink(dirp, rdentry); } else { /* It's RMDIR */ @@ -1436,6 +1377,7 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, * may choose to do less. */ inode = file.f_dentry->d_inode; + down(&inode->i_sem); while (1) { oldlen = cd.buflen; @@ -1444,9 +1386,7 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, file.f_inode->i_dev, file.f_inode->i_ino, (int) file.f_pos, (int) oldlen, (int) cd.buflen); */ - down(&inode->i_sem); err = file.f_op->readdir(&file, &cd, (filldir_t) func); - up(&inode->i_sem); if (err < 0) goto out_nfserr; if (oldlen == cd.buflen) @@ -1454,6 +1394,7 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, if (cd.eob) break; } + up(&inode->i_sem); /* If we didn't fill the buffer completely, we're at EOF */ eof = !cd.eob; @@ -1482,6 +1423,7 @@ out: return err; out_nfserr: + up(&inode->i_sem); err = nfserrno(err); goto out_close; } @@ -644,7 +644,7 @@ out: * for the internal routines (ie open_namei()/follow_link() etc). 00 is * used by symlinks. */ -struct file *filp_open(const char * filename, int flags, int mode) +struct file *filp_open(const char * filename, int flags, int mode, struct dentry * base) { struct inode * inode; struct dentry * dentry; @@ -661,7 +661,7 @@ struct file *filp_open(const char * filename, int flags, int mode) flag++; if (flag & O_TRUNC) flag |= 2; - dentry = open_namei(filename,flag,mode); + dentry = __open_namei(filename, flag, mode, base); error = PTR_ERR(dentry); if (IS_ERR(dentry)) goto cleanup_file; @@ -787,7 +787,7 @@ asmlinkage long sys_open(const char * filename, int flags, int mode) if (fd >= 0) { struct file * f; lock_kernel(); - f = filp_open(tmp, flags, mode); + f = filp_open(tmp, flags, mode, NULL); unlock_kernel(); error = PTR_ERR(f); if (IS_ERR(f)) diff --git a/fs/partitions/acorn.c b/fs/partitions/acorn.c index 856cc30aa..561c87065 100644 --- a/fs/partitions/acorn.c +++ b/fs/partitions/acorn.c @@ -98,7 +98,7 @@ static int riscix_partition(struct gendisk *hd, kdev_t dev, unsigned long first_ } } - printk(" >"); + printk(" >\n"); if (hd->part[riscix_minor].nr_sects > 2) hd->part[riscix_minor].nr_sects = 2; @@ -139,7 +139,7 @@ static int linux_partition(struct gendisk *hd, kdev_t dev, unsigned long first_s le32_to_cpu(linuxp->nr_sects)); linuxp ++; } - printk(" >"); + printk(" >\n"); /* * Prevent someone doing a mkswap or mkfs on this partition */ diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c index 2f315ccd9..fc9555b77 100644 --- a/fs/partitions/msdos.c +++ b/fs/partitions/msdos.c @@ -347,19 +347,19 @@ int msdos_partition(struct gendisk *hd, kdev_t dev, unsigned char *data; int mask = (1 << hd->minor_shift) - 1; int sector_size = get_hardsect_size(dev) / 512; -#ifdef CONFIG_BLK_DEV_IDE +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) int tested_for_xlate = 0; read_mbr: -#endif /* CONFIG_BLK_DEV_IDE */ +#endif /* (CONFIG_BLK_DEV_IDE) || (CONFIG_BLK_DEV_IDE_MODULE) */ if (!(bh = bread(dev,0,get_ptable_blocksize(dev)))) { if (warn_no_part) printk(" unable to read partition table\n"); return -1; } data = bh->b_data; -#ifdef CONFIG_BLK_DEV_IDE +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) check_table: -#endif /* CONFIG_BLK_DEV_IDE */ +#endif /* (CONFIG_BLK_DEV_IDE) || (CONFIG_BLK_DEV_IDE_MODULE) */ /* Use bforget(), because we may have changed the disk geometry */ if (*(unsigned short *) (0x1fe + data) != cpu_to_le16(MSDOS_LABEL_MAGIC)) { bforget(bh); @@ -367,7 +367,7 @@ check_table: } p = (struct partition *) (0x1be + data); -#ifdef CONFIG_BLK_DEV_IDE +#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) if (!tested_for_xlate++) { /* Do this only once per disk */ /* * Look for various forms of IDE disk geometry translation @@ -423,7 +423,7 @@ check_table: (void) ide_xlate_1024(dev, 2, heads, " [PTBL]"); } } -#endif /* CONFIG_BLK_DEV_IDE */ +#endif /* (CONFIG_BLK_DEV_IDE) || (CONFIG_BLK_DEV_IDE_MODULE) */ /* Look for partitions in two passes: First find the primary partitions, and the DOS-type extended partitions. diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index cef1e93cf..9ed649a3b 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -546,7 +546,7 @@ static int __init init_smb_fs(void) smb_current_vmalloced = 0; #endif - return init_smb_fs(); + return register_filesystem(&smb_fs_type); } static void __exit exit_smb_fs(void) diff --git a/fs/super.c b/fs/super.c index 8aed9ce90..dd34ddc70 100644 --- a/fs/super.c +++ b/fs/super.c @@ -247,32 +247,9 @@ static struct file_system_type *get_fs_type(const char *name) return fs; } - struct vfsmount *vfsmntlist = NULL; static struct vfsmount *vfsmnttail = NULL, *mru_vfsmnt = NULL; -/* - * This part handles the management of the list of mounted filesystems. - */ -struct vfsmount *lookup_vfsmnt(kdev_t dev) -{ - struct vfsmount *lptr; - - if (vfsmntlist == NULL) - return NULL; - - if (mru_vfsmnt != NULL && mru_vfsmnt->mnt_dev == dev) - return (mru_vfsmnt); - - for (lptr = vfsmntlist; lptr != NULL; lptr = lptr->mnt_next) - if (lptr->mnt_dev == dev) { - mru_vfsmnt = lptr; - return (lptr); - } - - return NULL; -} - static struct vfsmount *add_vfsmnt(struct super_block *sb, const char *dev_name, const char *dir_name) { @@ -286,11 +263,6 @@ static struct vfsmount *add_vfsmnt(struct super_block *sb, lptr->mnt_sb = sb; lptr->mnt_dev = sb->s_dev; - lptr->mnt_flags = sb->s_flags; - - sema_init(&lptr->mnt_dquot.dqio_sem, 1); - sema_init(&lptr->mnt_dquot.dqoff_sem, 1); - lptr->mnt_dquot.flags = 0; /* N.B. Is it really OK to have a vfsmount without names? */ if (dev_name && !IS_ERR(tmp = getname(dev_name))) { @@ -399,9 +371,9 @@ int get_filesystem_info( char *buf ) len += sprintf( buf + len, "%s %s %s %s", tmp->mnt_devname, path, tmp->mnt_sb->s_type->name, - tmp->mnt_flags & MS_RDONLY ? "ro" : "rw" ); + tmp->mnt_sb->s_flags & MS_RDONLY ? "ro" : "rw" ); for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { - if (tmp->mnt_flags & fs_infop->flag) { + if (tmp->mnt_sb->s_flags & fs_infop->flag) { strcpy(buf + len, fs_infop->str); len += strlen(fs_infop->str); } @@ -592,6 +564,9 @@ static struct super_block * read_super(kdev_t dev, struct block_device *bdev, sema_init(&s->s_vfs_rename_sem,1); sema_init(&s->s_nfsd_free_path_sem,1); s->s_type = type; + sema_init(&s->s_dquot.dqio_sem, 1); + sema_init(&s->s_dquot.dqoff_sem, 1); + s->s_dquot.flags = 0; lock_super(s); if (!type->read_super(s, data, silent)) goto out_fail; @@ -606,7 +581,6 @@ out_fail: s->s_dev = 0; s->s_bdev = 0; s->s_type = NULL; - put_filesystem(type); unlock_super(s); return NULL; } @@ -688,7 +662,7 @@ static struct block_device *do_umount(kdev_t dev, int unmount_root, int flags) * on the device. If the umount fails, too bad -- there * are no quotas running any more. Just turn them on again. */ - DQUOT_OFF(dev); + DQUOT_OFF(sb); acct_auto_close(dev); /* @@ -990,7 +964,6 @@ out: static int do_remount_sb(struct super_block *sb, int flags, char *data) { int retval; - struct vfsmount *vfsmnt; if (!(flags & MS_RDONLY) && sb->s_dev && is_read_only(sb->s_dev)) return -EACCES; @@ -1007,9 +980,6 @@ static int do_remount_sb(struct super_block *sb, int flags, char *data) return retval; } sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK); - vfsmnt = lookup_vfsmnt(sb->s_dev); - if (vfsmnt) - vfsmnt->mnt_flags = sb->s_flags; /* * Invalidate the inodes, as some mount options may be changed. @@ -1093,8 +1063,8 @@ static int copy_mount_options (const void * data, unsigned long *where) * aren't used, as the syscall assumes we are talking to an older * version that didn't understand them. */ -asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, - unsigned long new_flags, void * data) +long do_sys_mount(char * dev_name, char * dir_name, unsigned long type_page, + unsigned long new_flags, unsigned long data_page) { struct file_system_type * fstype; struct dentry * dentry = NULL; @@ -1102,28 +1072,19 @@ asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, struct block_device *bdev = NULL; int retval; unsigned long flags = 0; - unsigned long page = 0; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - lock_kernel(); + if ((new_flags & (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) { - retval = copy_mount_options (data, &page); - if (retval < 0) - goto out; retval = do_remount(dir_name, new_flags & ~MS_MGC_MSK & ~MS_REMOUNT, - (char *) page); - free_page(page); + (char *) data_page); goto out; } - retval = copy_mount_options (type, &page); - if (retval < 0) - goto out; - fstype = get_fs_type((char *) page); - free_page(page); + fstype = get_fs_type((char *) type_page); retval = -ENODEV; if (!fstype) goto out; @@ -1150,22 +1111,50 @@ asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, if (bdops) bdev->bd_op = bdops; } - page = 0; - if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) { + if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) flags = new_flags & ~MS_MGC_MSK; - retval = copy_mount_options(data, &page); - if (retval < 0) - goto dput_and_out; - } + retval = do_mount(bdev, dev_name, dir_name, fstype->name, flags, - (void *) page); - free_page(page); + (void *) data_page); dput_and_out: dput(dentry); fs_out: put_filesystem(fstype); out: + return retval; +} + +asmlinkage long sys_mount(char * dev_name, char * dir_name, char * type, + unsigned long new_flags, void * data) +{ + int retval; + unsigned long data_page = 0; + unsigned long type_page = 0; + + lock_kernel(); + retval = copy_mount_options (type, &type_page); + if (retval < 0) + goto out; + + /* copy_mount_options allows a NULL user pointer, + * and just returns zero in that case. But if we + * allow the type to be NULL we will crash. + * Previously we did not check this case. + */ + if (type_page == 0) { + retval = -EINVAL; + goto out; + } + + retval = copy_mount_options (data, &data_page); + if (retval >= 0) { + retval = do_sys_mount(dev_name, dir_name, type_page, + new_flags, data_page); + free_page(data_page); + } + free_page(type_page); +out: unlock_kernel(); return retval; } @@ -1255,7 +1244,7 @@ void __init mount_root(void) * devfs crap and checking it right now. Later. */ if (!ROOT_DEV) - panic("I have no root and I want to sream"); + panic("I have no root and I want to scream"); bdev = bdget(kdev_t_to_nr(ROOT_DEV)); if (!bdev) diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c index c1fb13c31..08fa1f4bf 100644 --- a/fs/ufs/dir.c +++ b/fs/ufs/dir.c @@ -106,9 +106,9 @@ revalidate: bh, offset)) { /* On error, skip the f_pos to the next block. */ - filp->f_pos = (filp->f_pos & + filp->f_pos = (filp->f_pos | (sb->s_blocksize - 1)) + - sb->s_blocksize; + 1; brelse (bh); return stored; } |