mirror of https://github.com/torvalds/linux.git
vfs-6.17-rc8.fixes
-----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCaNZQKAAKCRCRxhvAZXjc ol/SAQDWweiwhUQ6XCP34oeUEbwEZfNFe+l9Igr0Xxjv7JLtEwEA8z7YydWbvWI4 GamGbXSanr30orQXnHq0JpDapRWxVw4= =AimW -----END PGP SIGNATURE----- Merge tag 'vfs-6.17-rc8.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs Pull vfs fixes from Christian Brauner: - Prevent double unlock in netfs - Fix a NULL pointer dereference in afs_put_server() - Fix a reference leak in netfs * tag 'vfs-6.17-rc8.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: netfs: fix reference leak afs: Fix potential null pointer dereference in afs_put_server netfs: Prevent duplicate unlocking
This commit is contained in:
commit
d8743676b1
|
|
@ -331,13 +331,14 @@ struct afs_server *afs_use_server(struct afs_server *server, bool activate,
|
|||
void afs_put_server(struct afs_net *net, struct afs_server *server,
|
||||
enum afs_server_trace reason)
|
||||
{
|
||||
unsigned int a, debug_id = server->debug_id;
|
||||
unsigned int a, debug_id;
|
||||
bool zero;
|
||||
int r;
|
||||
|
||||
if (!server)
|
||||
return;
|
||||
|
||||
debug_id = server->debug_id;
|
||||
a = atomic_read(&server->active);
|
||||
zero = __refcount_dec_and_test(&server->ref, &r);
|
||||
trace_afs_server(debug_id, r - 1, a, reason);
|
||||
|
|
|
|||
|
|
@ -369,7 +369,7 @@ void netfs_readahead(struct readahead_control *ractl)
|
|||
return netfs_put_request(rreq, netfs_rreq_trace_put_return);
|
||||
|
||||
cleanup_free:
|
||||
return netfs_put_request(rreq, netfs_rreq_trace_put_failed);
|
||||
return netfs_put_failed_request(rreq);
|
||||
}
|
||||
EXPORT_SYMBOL(netfs_readahead);
|
||||
|
||||
|
|
@ -472,7 +472,7 @@ static int netfs_read_gaps(struct file *file, struct folio *folio)
|
|||
return ret < 0 ? ret : 0;
|
||||
|
||||
discard:
|
||||
netfs_put_request(rreq, netfs_rreq_trace_put_discard);
|
||||
netfs_put_failed_request(rreq);
|
||||
alloc_error:
|
||||
folio_unlock(folio);
|
||||
return ret;
|
||||
|
|
@ -532,7 +532,7 @@ int netfs_read_folio(struct file *file, struct folio *folio)
|
|||
return ret < 0 ? ret : 0;
|
||||
|
||||
discard:
|
||||
netfs_put_request(rreq, netfs_rreq_trace_put_discard);
|
||||
netfs_put_failed_request(rreq);
|
||||
alloc_error:
|
||||
folio_unlock(folio);
|
||||
return ret;
|
||||
|
|
@ -699,7 +699,7 @@ int netfs_write_begin(struct netfs_inode *ctx,
|
|||
return 0;
|
||||
|
||||
error_put:
|
||||
netfs_put_request(rreq, netfs_rreq_trace_put_failed);
|
||||
netfs_put_failed_request(rreq);
|
||||
error:
|
||||
if (folio) {
|
||||
folio_unlock(folio);
|
||||
|
|
@ -754,7 +754,7 @@ int netfs_prefetch_for_write(struct file *file, struct folio *folio,
|
|||
return ret < 0 ? ret : 0;
|
||||
|
||||
error_put:
|
||||
netfs_put_request(rreq, netfs_rreq_trace_put_discard);
|
||||
netfs_put_failed_request(rreq);
|
||||
error:
|
||||
_leave(" = %d", ret);
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -347,7 +347,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter,
|
|||
folio_put(folio);
|
||||
ret = filemap_write_and_wait_range(mapping, fpos, fpos + flen - 1);
|
||||
if (ret < 0)
|
||||
goto error_folio_unlock;
|
||||
goto out;
|
||||
continue;
|
||||
|
||||
copied:
|
||||
|
|
|
|||
|
|
@ -131,6 +131,7 @@ static ssize_t netfs_unbuffered_read(struct netfs_io_request *rreq, bool sync)
|
|||
|
||||
if (rreq->len == 0) {
|
||||
pr_err("Zero-sized read [R=%x]\n", rreq->debug_id);
|
||||
netfs_put_request(rreq, netfs_rreq_trace_put_discard);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
|
@ -205,7 +206,7 @@ ssize_t netfs_unbuffered_read_iter_locked(struct kiocb *iocb, struct iov_iter *i
|
|||
if (user_backed_iter(iter)) {
|
||||
ret = netfs_extract_user_iter(iter, rreq->len, &rreq->buffer.iter, 0);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
goto error_put;
|
||||
rreq->direct_bv = (struct bio_vec *)rreq->buffer.iter.bvec;
|
||||
rreq->direct_bv_count = ret;
|
||||
rreq->direct_bv_unpin = iov_iter_extract_will_pin(iter);
|
||||
|
|
@ -238,6 +239,10 @@ ssize_t netfs_unbuffered_read_iter_locked(struct kiocb *iocb, struct iov_iter *i
|
|||
if (ret > 0)
|
||||
orig_count -= ret;
|
||||
return ret;
|
||||
|
||||
error_put:
|
||||
netfs_put_failed_request(rreq);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(netfs_unbuffered_read_iter_locked);
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ ssize_t netfs_unbuffered_write_iter_locked(struct kiocb *iocb, struct iov_iter *
|
|||
n = netfs_extract_user_iter(iter, len, &wreq->buffer.iter, 0);
|
||||
if (n < 0) {
|
||||
ret = n;
|
||||
goto out;
|
||||
goto error_put;
|
||||
}
|
||||
wreq->direct_bv = (struct bio_vec *)wreq->buffer.iter.bvec;
|
||||
wreq->direct_bv_count = n;
|
||||
|
|
@ -101,6 +101,10 @@ ssize_t netfs_unbuffered_write_iter_locked(struct kiocb *iocb, struct iov_iter *
|
|||
out:
|
||||
netfs_put_request(wreq, netfs_rreq_trace_put_return);
|
||||
return ret;
|
||||
|
||||
error_put:
|
||||
netfs_put_failed_request(wreq);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(netfs_unbuffered_write_iter_locked);
|
||||
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping,
|
|||
void netfs_get_request(struct netfs_io_request *rreq, enum netfs_rreq_ref_trace what);
|
||||
void netfs_clear_subrequests(struct netfs_io_request *rreq);
|
||||
void netfs_put_request(struct netfs_io_request *rreq, enum netfs_rreq_ref_trace what);
|
||||
void netfs_put_failed_request(struct netfs_io_request *rreq);
|
||||
struct netfs_io_subrequest *netfs_alloc_subrequest(struct netfs_io_request *rreq);
|
||||
|
||||
static inline void netfs_see_request(struct netfs_io_request *rreq,
|
||||
|
|
|
|||
|
|
@ -116,10 +116,8 @@ static void netfs_free_request_rcu(struct rcu_head *rcu)
|
|||
netfs_stat_d(&netfs_n_rh_rreq);
|
||||
}
|
||||
|
||||
static void netfs_free_request(struct work_struct *work)
|
||||
static void netfs_deinit_request(struct netfs_io_request *rreq)
|
||||
{
|
||||
struct netfs_io_request *rreq =
|
||||
container_of(work, struct netfs_io_request, cleanup_work);
|
||||
struct netfs_inode *ictx = netfs_inode(rreq->inode);
|
||||
unsigned int i;
|
||||
|
||||
|
|
@ -149,6 +147,14 @@ static void netfs_free_request(struct work_struct *work)
|
|||
|
||||
if (atomic_dec_and_test(&ictx->io_count))
|
||||
wake_up_var(&ictx->io_count);
|
||||
}
|
||||
|
||||
static void netfs_free_request(struct work_struct *work)
|
||||
{
|
||||
struct netfs_io_request *rreq =
|
||||
container_of(work, struct netfs_io_request, cleanup_work);
|
||||
|
||||
netfs_deinit_request(rreq);
|
||||
call_rcu(&rreq->rcu, netfs_free_request_rcu);
|
||||
}
|
||||
|
||||
|
|
@ -167,6 +173,24 @@ void netfs_put_request(struct netfs_io_request *rreq, enum netfs_rreq_ref_trace
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a request (synchronously) that was just allocated but has
|
||||
* failed before it could be submitted.
|
||||
*/
|
||||
void netfs_put_failed_request(struct netfs_io_request *rreq)
|
||||
{
|
||||
int r = refcount_read(&rreq->ref);
|
||||
|
||||
/* new requests have two references (see
|
||||
* netfs_alloc_request(), and this function is only allowed on
|
||||
* new request objects
|
||||
*/
|
||||
WARN_ON_ONCE(r != 2);
|
||||
|
||||
trace_netfs_rreq_ref(rreq->debug_id, r, netfs_rreq_trace_put_failed);
|
||||
netfs_free_request(&rreq->cleanup_work);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate and partially initialise an I/O request structure.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ static struct netfs_io_request *netfs_pgpriv2_begin_copy_to_cache(
|
|||
return creq;
|
||||
|
||||
cancel_put:
|
||||
netfs_put_request(creq, netfs_rreq_trace_put_return);
|
||||
netfs_put_failed_request(creq);
|
||||
cancel:
|
||||
rreq->copy_to_cache = ERR_PTR(-ENOBUFS);
|
||||
clear_bit(NETFS_RREQ_FOLIO_COPY_TO_CACHE, &rreq->flags);
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ ssize_t netfs_read_single(struct inode *inode, struct file *file, struct iov_ite
|
|||
return ret;
|
||||
|
||||
cleanup_free:
|
||||
netfs_put_request(rreq, netfs_rreq_trace_put_failed);
|
||||
netfs_put_failed_request(rreq);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(netfs_read_single);
|
||||
|
|
|
|||
|
|
@ -133,8 +133,7 @@ struct netfs_io_request *netfs_create_write_req(struct address_space *mapping,
|
|||
|
||||
return wreq;
|
||||
nomem:
|
||||
wreq->error = -ENOMEM;
|
||||
netfs_put_request(wreq, netfs_rreq_trace_put_failed);
|
||||
netfs_put_failed_request(wreq);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue