aboutsummaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/bio.c124
-rw-r--r--fs/compat.c11
-rw-r--r--fs/exec.c25
3 files changed, 74 insertions, 86 deletions
diff --git a/fs/bio.c b/fs/bio.c
index cd42bb882f3..7bbc98f0eda 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -175,14 +175,6 @@ struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned long *idx,
struct bio_vec *bvl;
/*
- * If 'bs' is given, lookup the pool and do the mempool alloc.
- * If not, this is a bio_kmalloc() allocation and just do a
- * kzalloc() for the exact number of vecs right away.
- */
- if (!bs)
- bvl = kmalloc(nr * sizeof(struct bio_vec), gfp_mask);
-
- /*
* see comment near bvec_array define!
*/
switch (nr) {
@@ -260,21 +252,6 @@ void bio_free(struct bio *bio, struct bio_set *bs)
mempool_free(p, bs->bio_pool);
}
-/*
- * default destructor for a bio allocated with bio_alloc_bioset()
- */
-static void bio_fs_destructor(struct bio *bio)
-{
- bio_free(bio, fs_bio_set);
-}
-
-static void bio_kmalloc_destructor(struct bio *bio)
-{
- if (bio_has_allocated_vec(bio))
- kfree(bio->bi_io_vec);
- kfree(bio);
-}
-
void bio_init(struct bio *bio)
{
memset(bio, 0, sizeof(*bio));
@@ -301,21 +278,15 @@ void bio_init(struct bio *bio)
**/
struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
{
+ unsigned long idx = BIO_POOL_NONE;
struct bio_vec *bvl = NULL;
- struct bio *bio = NULL;
- unsigned long idx = 0;
- void *p = NULL;
-
- if (bs) {
- p = mempool_alloc(bs->bio_pool, gfp_mask);
- if (!p)
- goto err;
- bio = p + bs->front_pad;
- } else {
- bio = kmalloc(sizeof(*bio), gfp_mask);
- if (!bio)
- goto err;
- }
+ struct bio *bio;
+ void *p;
+
+ p = mempool_alloc(bs->bio_pool, gfp_mask);
+ if (unlikely(!p))
+ return NULL;
+ bio = p + bs->front_pad;
bio_init(bio);
@@ -332,22 +303,50 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
nr_iovecs = bvec_nr_vecs(idx);
}
+out_set:
bio->bi_flags |= idx << BIO_POOL_OFFSET;
bio->bi_max_vecs = nr_iovecs;
-out_set:
bio->bi_io_vec = bvl;
-
return bio;
err_free:
- if (bs)
- mempool_free(p, bs->bio_pool);
- else
- kfree(bio);
-err:
+ mempool_free(p, bs->bio_pool);
return NULL;
}
+static void bio_fs_destructor(struct bio *bio)
+{
+ bio_free(bio, fs_bio_set);
+}
+
+/**
+ * bio_alloc - allocate a new bio, memory pool backed
+ * @gfp_mask: allocation mask to use
+ * @nr_iovecs: number of iovecs
+ *
+ * Allocate a new bio with @nr_iovecs bvecs. If @gfp_mask
+ * contains __GFP_WAIT, the allocation is guaranteed to succeed.
+ *
+ * RETURNS:
+ * Pointer to new bio on success, NULL on failure.
+ */
+struct bio *bio_alloc(gfp_t gfp_mask, int nr_iovecs)
+{
+ struct bio *bio = bio_alloc_bioset(gfp_mask, nr_iovecs, fs_bio_set);
+
+ if (bio)
+ bio->bi_destructor = bio_fs_destructor;
+
+ return bio;
+}
+
+static void bio_kmalloc_destructor(struct bio *bio)
+{
+ if (bio_integrity(bio))
+ bio_integrity_free(bio);
+ kfree(bio);
+}
+
/**
* bio_alloc - allocate a bio for I/O
* @gfp_mask: the GFP_ mask given to the slab allocator
@@ -366,29 +365,20 @@ err:
* do so can cause livelocks under memory pressure.
*
**/
-struct bio *bio_alloc(gfp_t gfp_mask, int nr_iovecs)
-{
- struct bio *bio = bio_alloc_bioset(gfp_mask, nr_iovecs, fs_bio_set);
-
- if (bio)
- bio->bi_destructor = bio_fs_destructor;
-
- return bio;
-}
-
-/*
- * Like bio_alloc(), but doesn't use a mempool backing. This means that
- * it CAN fail, but while bio_alloc() can only be used for allocations
- * that have a short (finite) life span, bio_kmalloc() should be used
- * for more permanent bio allocations (like allocating some bio's for
- * initalization or setup purposes).
- */
struct bio *bio_kmalloc(gfp_t gfp_mask, int nr_iovecs)
{
- struct bio *bio = bio_alloc_bioset(gfp_mask, nr_iovecs, NULL);
+ struct bio *bio;
- if (bio)
- bio->bi_destructor = bio_kmalloc_destructor;
+ bio = kmalloc(sizeof(struct bio) + nr_iovecs * sizeof(struct bio_vec),
+ gfp_mask);
+ if (unlikely(!bio))
+ return NULL;
+
+ bio_init(bio);
+ bio->bi_flags |= BIO_POOL_NONE << BIO_POOL_OFFSET;
+ bio->bi_max_vecs = nr_iovecs;
+ bio->bi_io_vec = bio->bi_inline_vecs;
+ bio->bi_destructor = bio_kmalloc_destructor;
return bio;
}
@@ -832,7 +822,7 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
return ERR_PTR(-ENOMEM);
ret = -ENOMEM;
- bio = bio_alloc(gfp_mask, nr_pages);
+ bio = bio_kmalloc(gfp_mask, nr_pages);
if (!bio)
goto out_bmd;
@@ -956,7 +946,7 @@ static struct bio *__bio_map_user_iov(struct request_queue *q,
if (!nr_pages)
return ERR_PTR(-EINVAL);
- bio = bio_alloc(gfp_mask, nr_pages);
+ bio = bio_kmalloc(gfp_mask, nr_pages);
if (!bio)
return ERR_PTR(-ENOMEM);
@@ -1140,7 +1130,7 @@ static struct bio *__bio_map_kern(struct request_queue *q, void *data,
int offset, i;
struct bio *bio;
- bio = bio_alloc(gfp_mask, nr_pages);
+ bio = bio_kmalloc(gfp_mask, nr_pages);
if (!bio)
return ERR_PTR(-ENOMEM);
diff --git a/fs/compat.c b/fs/compat.c
index 379a399bf5c..681ed81e6be 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1476,6 +1476,7 @@ int compat_do_execve(char * filename,
struct linux_binprm *bprm;
struct file *file;
struct files_struct *displaced;
+ bool clear_in_exec;
int retval;
retval = unshare_files(&displaced);
@@ -1498,8 +1499,9 @@ int compat_do_execve(char * filename,
goto out_unlock;
retval = check_unsafe_exec(bprm);
- if (retval)
+ if (retval < 0)
goto out_unlock;
+ clear_in_exec = retval;
file = open_exec(filename);
retval = PTR_ERR(file);
@@ -1546,9 +1548,7 @@ int compat_do_execve(char * filename,
goto out;
/* execve succeeded */
- write_lock(&current->fs->lock);
current->fs->in_exec = 0;
- write_unlock(&current->fs->lock);
current->in_execve = 0;
mutex_unlock(&current->cred_exec_mutex);
acct_update_integrals(current);
@@ -1568,9 +1568,8 @@ out_file:
}
out_unmark:
- write_lock(&current->fs->lock);
- current->fs->in_exec = 0;
- write_unlock(&current->fs->lock);
+ if (clear_in_exec)
+ current->fs->in_exec = 0;
out_unlock:
current->in_execve = 0;
diff --git a/fs/exec.c b/fs/exec.c
index 052a961e41a..a3a8ce83940 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1060,7 +1060,6 @@ EXPORT_SYMBOL(install_exec_creds);
int check_unsafe_exec(struct linux_binprm *bprm)
{
struct task_struct *p = current, *t;
- unsigned long flags;
unsigned n_fs;
int res = 0;
@@ -1068,21 +1067,22 @@ int check_unsafe_exec(struct linux_binprm *bprm)
n_fs = 1;
write_lock(&p->fs->lock);
- lock_task_sighand(p, &flags);
+ rcu_read_lock();
for (t = next_thread(p); t != p; t = next_thread(t)) {
if (t->fs == p->fs)
n_fs++;
}
+ rcu_read_unlock();
if (p->fs->users > n_fs) {
bprm->unsafe |= LSM_UNSAFE_SHARE;
} else {
- if (p->fs->in_exec)
- res = -EAGAIN;
- p->fs->in_exec = 1;
+ res = -EAGAIN;
+ if (!p->fs->in_exec) {
+ p->fs->in_exec = 1;
+ res = 1;
+ }
}
-
- unlock_task_sighand(p, &flags);
write_unlock(&p->fs->lock);
return res;
@@ -1284,6 +1284,7 @@ int do_execve(char * filename,
struct linux_binprm *bprm;
struct file *file;
struct files_struct *displaced;
+ bool clear_in_exec;
int retval;
retval = unshare_files(&displaced);
@@ -1306,8 +1307,9 @@ int do_execve(char * filename,
goto out_unlock;
retval = check_unsafe_exec(bprm);
- if (retval)
+ if (retval < 0)
goto out_unlock;
+ clear_in_exec = retval;
file = open_exec(filename);
retval = PTR_ERR(file);
@@ -1355,9 +1357,7 @@ int do_execve(char * filename,
goto out;
/* execve succeeded */
- write_lock(&current->fs->lock);
current->fs->in_exec = 0;
- write_unlock(&current->fs->lock);
current->in_execve = 0;
mutex_unlock(&current->cred_exec_mutex);
acct_update_integrals(current);
@@ -1377,9 +1377,8 @@ out_file:
}
out_unmark:
- write_lock(&current->fs->lock);
- current->fs->in_exec = 0;
- write_unlock(&current->fs->lock);
+ if (clear_in_exec)
+ current->fs->in_exec = 0;
out_unlock:
current->in_execve = 0;