summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-03-23 02:25:38 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-03-23 02:25:38 +0000
commit16b5d462f73eb29d1f67fa01cc1ea66afdc72569 (patch)
tree5407bd573f4840e473ea27cbe61e5c7a07131fcd /fs
parentce8a076e11e7e5ee36007f9a3eee5bb3744cb8f6 (diff)
Merge with Linux 2.3.99-pre2.
Diffstat (limited to 'fs')
-rw-r--r--fs/autofs/inode.c1
-rw-r--r--fs/binfmt_aout.c28
-rw-r--r--fs/binfmt_elf.c28
-rw-r--r--fs/binfmt_em86.c4
-rw-r--r--fs/binfmt_misc.c2
-rw-r--r--fs/binfmt_script.c2
-rw-r--r--fs/buffer.c12
-rw-r--r--fs/dquot.c230
-rw-r--r--fs/exec.c14
-rw-r--r--fs/ext2/dir.c4
-rw-r--r--fs/namei.c87
-rw-r--r--fs/nfsd/nfs3xdr.c39
-rw-r--r--fs/nfsd/nfsctl.c4
-rw-r--r--fs/nfsd/nfsfh.c6
-rw-r--r--fs/nfsd/nfsproc.c34
-rw-r--r--fs/nfsd/vfs.c270
-rw-r--r--fs/open.c6
-rw-r--r--fs/partitions/acorn.c4
-rw-r--r--fs/partitions/msdos.c12
-rw-r--r--fs/smbfs/inode.c2
-rw-r--r--fs/super.c107
-rw-r--r--fs/ufs/dir.c4
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(&current->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(&current->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(&current->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(&current->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;
diff --git a/fs/exec.c b/fs/exec.c
index e3ff2d005..d7d5240be 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -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;
}
diff --git a/fs/open.c b/fs/open.c
index 6b11f4ab0..9f4d50a79 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -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;
}