diff options
author | Tim Shimmin <tes@chook.melbourne.sgi.com> | 2007-10-11 16:52:59 +1000 |
---|---|---|
committer | Tim Shimmin <tes@chook.melbourne.sgi.com> | 2007-10-11 16:52:59 +1000 |
commit | c1561cf463f4a480d1960e833c8fe628207b24e4 (patch) | |
tree | b612e5257611ef33196aacc00fba813c943384d5 /fs | |
parent | 053c59a0a7234bac669992f5b8b933b7d7fc189d (diff) | |
parent | bbf25010f1a6b761914430f5fca081ec8c7accd1 (diff) | |
download | op-kernel-dev-c1561cf463f4a480d1960e833c8fe628207b24e4.zip op-kernel-dev-c1561cf463f4a480d1960e833c8fe628207b24e4.tar.gz |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 into for-linus
Diffstat (limited to 'fs')
-rw-r--r-- | fs/aio.c | 2 | ||||
-rw-r--r-- | fs/binfmt_flat.c | 6 | ||||
-rw-r--r-- | fs/lockd/svclock.c | 4 | ||||
-rw-r--r-- | fs/ocfs2/localalloc.c | 4 | ||||
-rw-r--r-- | fs/splice.c | 46 |
5 files changed, 46 insertions, 16 deletions
@@ -1562,6 +1562,7 @@ int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, fput(file); return -EAGAIN; } + req->ki_filp = file; if (iocb->aio_flags & IOCB_FLAG_RESFD) { /* * If the IOCB_FLAG_RESFD flag of aio_flags is set, get an @@ -1576,7 +1577,6 @@ int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, } } - req->ki_filp = file; ret = put_user(req->ki_key, &user_iocb->aio_key); if (unlikely(ret)) { dprintk("EFAULT: aio_key\n"); diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index 861141b..fcb3405 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -742,6 +742,7 @@ static int load_flat_file(struct linux_binprm * bprm, * __start to address 4 so that is okay). */ if (rev > OLD_FLAT_VERSION) { + unsigned long persistent = 0; for (i=0; i < relocs; i++) { unsigned long addr, relval; @@ -749,6 +750,8 @@ static int load_flat_file(struct linux_binprm * bprm, relocated (of course, the address has to be relocated first). */ relval = ntohl(reloc[i]); + if (flat_set_persistent (relval, &persistent)) + continue; addr = flat_get_relocate_addr(relval); rp = (unsigned long *) calc_reloc(addr, libinfo, id, 1); if (rp == (unsigned long *)RELOC_FAILED) { @@ -757,7 +760,8 @@ static int load_flat_file(struct linux_binprm * bprm, } /* Get the pointer's value. */ - addr = flat_get_addr_from_rp(rp, relval, flags); + addr = flat_get_addr_from_rp(rp, relval, flags, + &persistent); if (addr != 0) { /* * Do the relocation. PIC relocs in the data section are diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c index d098c7a..d120ec39 100644 --- a/fs/lockd/svclock.c +++ b/fs/lockd/svclock.c @@ -485,8 +485,10 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, return nlm_granted; /* Create host handle for callback */ host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len); - if (host == NULL) + if (host == NULL) { + kfree(conf); return nlm_lck_denied_nolocks; + } block = nlmsvc_create_block(rqstp, host, file, lock, cookie); if (block == NULL) { kfree(conf); diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c index de984d2..d272847 100644 --- a/fs/ocfs2/localalloc.c +++ b/fs/ocfs2/localalloc.c @@ -514,8 +514,10 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb, ac->ac_bh = osb->local_alloc_bh; status = 0; bail: - if (status < 0 && local_alloc_inode) + if (status < 0 && local_alloc_inode) { + mutex_unlock(&local_alloc_inode->i_mutex); iput(local_alloc_inode); + } mlog_exit(status); return status; diff --git a/fs/splice.c b/fs/splice.c index c010a72..e95a362 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -1224,6 +1224,33 @@ static long do_splice(struct file *in, loff_t __user *off_in, } /* + * Do a copy-from-user while holding the mmap_semaphore for reading, in a + * manner safe from deadlocking with simultaneous mmap() (grabbing mmap_sem + * for writing) and page faulting on the user memory pointed to by src. + * This assumes that we will very rarely hit the partial != 0 path, or this + * will not be a win. + */ +static int copy_from_user_mmap_sem(void *dst, const void __user *src, size_t n) +{ + int partial; + + pagefault_disable(); + partial = __copy_from_user_inatomic(dst, src, n); + pagefault_enable(); + + /* + * Didn't copy everything, drop the mmap_sem and do a faulting copy + */ + if (unlikely(partial)) { + up_read(¤t->mm->mmap_sem); + partial = copy_from_user(dst, src, n); + down_read(¤t->mm->mmap_sem); + } + + return partial; +} + +/* * Map an iov into an array of pages and offset/length tupples. With the * partial_page structure, we can map several non-contiguous ranges into * our ones pages[] map instead of splitting that operation into pieces. @@ -1236,31 +1263,26 @@ static int get_iovec_page_array(const struct iovec __user *iov, { int buffers = 0, error = 0; - /* - * It's ok to take the mmap_sem for reading, even - * across a "get_user()". - */ down_read(¤t->mm->mmap_sem); while (nr_vecs) { unsigned long off, npages; + struct iovec entry; void __user *base; size_t len; int i; - /* - * Get user address base and length for this iovec. - */ - error = get_user(base, &iov->iov_base); - if (unlikely(error)) - break; - error = get_user(len, &iov->iov_len); - if (unlikely(error)) + error = -EFAULT; + if (copy_from_user_mmap_sem(&entry, iov, sizeof(entry))) break; + base = entry.iov_base; + len = entry.iov_len; + /* * Sanity check this iovec. 0 read succeeds. */ + error = 0; if (unlikely(!len)) break; error = -EFAULT; |