From: Greg Kroah-Hartman <greg@kroah.com>
To: linux-kernel@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
stable@vger.kernel.org, Jim Schutt <jaschut@sandia.gov>,
Alex Elder <elder@inktank.com>
Subject: [ 04/26] ceph: ceph_pagelist_append might sleep while atomic
Date: Tue, 18 Jun 2013 09:14:44 -0700 [thread overview]
Message-ID: <20130618161232.103441477@linuxfoundation.org> (raw)
In-Reply-To: <20130618161231.154881788@linuxfoundation.org>
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
3.4-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jim Schutt <jaschut@sandia.gov>
commit 39be95e9c8c0b5668c9f8806ffe29bf9f4bc0f40 upstream.
Ceph's encode_caps_cb() worked hard to not call __page_cache_alloc()
while holding a lock, but it's spoiled because ceph_pagelist_addpage()
always calls kmap(), which might sleep. Here's the result:
[13439.295457] ceph: mds0 reconnect start
[13439.300572] BUG: sleeping function called from invalid context at include/linux/highmem.h:58
[13439.309243] in_atomic(): 1, irqs_disabled(): 0, pid: 12059, name: kworker/1:1
. . .
[13439.376225] Call Trace:
[13439.378757] [<ffffffff81076f4c>] __might_sleep+0xfc/0x110
[13439.384353] [<ffffffffa03f4ce0>] ceph_pagelist_append+0x120/0x1b0 [libceph]
[13439.391491] [<ffffffffa0448fe9>] ceph_encode_locks+0x89/0x190 [ceph]
[13439.398035] [<ffffffff814ee849>] ? _raw_spin_lock+0x49/0x50
[13439.403775] [<ffffffff811cadf5>] ? lock_flocks+0x15/0x20
[13439.409277] [<ffffffffa045e2af>] encode_caps_cb+0x41f/0x4a0 [ceph]
[13439.415622] [<ffffffff81196748>] ? igrab+0x28/0x70
[13439.420610] [<ffffffffa045e9f8>] ? iterate_session_caps+0xe8/0x250 [ceph]
[13439.427584] [<ffffffffa045ea25>] iterate_session_caps+0x115/0x250 [ceph]
[13439.434499] [<ffffffffa045de90>] ? set_request_path_attr+0x2d0/0x2d0 [ceph]
[13439.441646] [<ffffffffa0462888>] send_mds_reconnect+0x238/0x450 [ceph]
[13439.448363] [<ffffffffa0464542>] ? ceph_mdsmap_decode+0x5e2/0x770 [ceph]
[13439.455250] [<ffffffffa0462e42>] check_new_map+0x352/0x500 [ceph]
[13439.461534] [<ffffffffa04631ad>] ceph_mdsc_handle_map+0x1bd/0x260 [ceph]
[13439.468432] [<ffffffff814ebc7e>] ? mutex_unlock+0xe/0x10
[13439.473934] [<ffffffffa043c612>] extra_mon_dispatch+0x22/0x30 [ceph]
[13439.480464] [<ffffffffa03f6c2c>] dispatch+0xbc/0x110 [libceph]
[13439.486492] [<ffffffffa03eec3d>] process_message+0x1ad/0x1d0 [libceph]
[13439.493190] [<ffffffffa03f1498>] ? read_partial_message+0x3e8/0x520 [libceph]
. . .
[13439.587132] ceph: mds0 reconnect success
[13490.720032] ceph: mds0 caps stale
[13501.235257] ceph: mds0 recovery completed
[13501.300419] ceph: mds0 caps renewed
Fix it up by encoding locks into a buffer first, and when the number
of encoded locks is stable, copy that into a ceph_pagelist.
[elder@inktank.com: abbreviated the stack info a bit.]
Signed-off-by: Jim Schutt <jaschut@sandia.gov>
Reviewed-by: Alex Elder <elder@inktank.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/ceph/locks.c | 76 +++++++++++++++++++++++++++++++--------------------
fs/ceph/mds_client.c | 63 ++++++++++++++++++++++--------------------
fs/ceph/super.h | 9 ++++--
3 files changed, 88 insertions(+), 60 deletions(-)
--- a/fs/ceph/locks.c
+++ b/fs/ceph/locks.c
@@ -191,29 +191,23 @@ void ceph_count_locks(struct inode *inod
}
/**
- * Encode the flock and fcntl locks for the given inode into the pagelist.
- * Format is: #fcntl locks, sequential fcntl locks, #flock locks,
- * sequential flock locks.
- * Must be called with lock_flocks() already held.
- * If we encounter more of a specific lock type than expected,
- * we return the value 1.
+ * Encode the flock and fcntl locks for the given inode into the ceph_filelock
+ * array. Must be called with lock_flocks() already held.
+ * If we encounter more of a specific lock type than expected, return -ENOSPC.
*/
-int ceph_encode_locks(struct inode *inode, struct ceph_pagelist *pagelist,
- int num_fcntl_locks, int num_flock_locks)
+int ceph_encode_locks_to_buffer(struct inode *inode,
+ struct ceph_filelock *flocks,
+ int num_fcntl_locks, int num_flock_locks)
{
struct file_lock *lock;
- struct ceph_filelock cephlock;
int err = 0;
int seen_fcntl = 0;
int seen_flock = 0;
- __le32 nlocks;
+ int l = 0;
dout("encoding %d flock and %d fcntl locks", num_flock_locks,
num_fcntl_locks);
- nlocks = cpu_to_le32(num_fcntl_locks);
- err = ceph_pagelist_append(pagelist, &nlocks, sizeof(nlocks));
- if (err)
- goto fail;
+
for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) {
if (lock->fl_flags & FL_POSIX) {
++seen_fcntl;
@@ -221,20 +215,12 @@ int ceph_encode_locks(struct inode *inod
err = -ENOSPC;
goto fail;
}
- err = lock_to_ceph_filelock(lock, &cephlock);
+ err = lock_to_ceph_filelock(lock, &flocks[l]);
if (err)
goto fail;
- err = ceph_pagelist_append(pagelist, &cephlock,
- sizeof(struct ceph_filelock));
+ ++l;
}
- if (err)
- goto fail;
}
-
- nlocks = cpu_to_le32(num_flock_locks);
- err = ceph_pagelist_append(pagelist, &nlocks, sizeof(nlocks));
- if (err)
- goto fail;
for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) {
if (lock->fl_flags & FL_FLOCK) {
++seen_flock;
@@ -242,19 +228,51 @@ int ceph_encode_locks(struct inode *inod
err = -ENOSPC;
goto fail;
}
- err = lock_to_ceph_filelock(lock, &cephlock);
+ err = lock_to_ceph_filelock(lock, &flocks[l]);
if (err)
goto fail;
- err = ceph_pagelist_append(pagelist, &cephlock,
- sizeof(struct ceph_filelock));
+ ++l;
}
- if (err)
- goto fail;
}
fail:
return err;
}
+/**
+ * Copy the encoded flock and fcntl locks into the pagelist.
+ * Format is: #fcntl locks, sequential fcntl locks, #flock locks,
+ * sequential flock locks.
+ * Returns zero on success.
+ */
+int ceph_locks_to_pagelist(struct ceph_filelock *flocks,
+ struct ceph_pagelist *pagelist,
+ int num_fcntl_locks, int num_flock_locks)
+{
+ int err = 0;
+ __le32 nlocks;
+
+ nlocks = cpu_to_le32(num_fcntl_locks);
+ err = ceph_pagelist_append(pagelist, &nlocks, sizeof(nlocks));
+ if (err)
+ goto out_fail;
+
+ err = ceph_pagelist_append(pagelist, flocks,
+ num_fcntl_locks * sizeof(*flocks));
+ if (err)
+ goto out_fail;
+
+ nlocks = cpu_to_le32(num_flock_locks);
+ err = ceph_pagelist_append(pagelist, &nlocks, sizeof(nlocks));
+ if (err)
+ goto out_fail;
+
+ err = ceph_pagelist_append(pagelist,
+ &flocks[num_fcntl_locks],
+ num_flock_locks * sizeof(*flocks));
+out_fail:
+ return err;
+}
+
/*
* Given a pointer to a lock, convert it to a ceph filelock
*/
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -2455,39 +2455,44 @@ static int encode_caps_cb(struct inode *
if (recon_state->flock) {
int num_fcntl_locks, num_flock_locks;
- struct ceph_pagelist_cursor trunc_point;
+ struct ceph_filelock *flocks;
- ceph_pagelist_set_cursor(pagelist, &trunc_point);
- do {
- lock_flocks();
- ceph_count_locks(inode, &num_fcntl_locks,
- &num_flock_locks);
- rec.v2.flock_len = cpu_to_le32(2*sizeof(u32) +
- (num_fcntl_locks+num_flock_locks) *
- sizeof(struct ceph_filelock));
- unlock_flocks();
-
- /* pre-alloc pagelist */
- ceph_pagelist_truncate(pagelist, &trunc_point);
- err = ceph_pagelist_append(pagelist, &rec, reclen);
- if (!err)
- err = ceph_pagelist_reserve(pagelist,
- rec.v2.flock_len);
-
- /* encode locks */
- if (!err) {
- lock_flocks();
- err = ceph_encode_locks(inode,
- pagelist,
- num_fcntl_locks,
- num_flock_locks);
- unlock_flocks();
- }
- } while (err == -ENOSPC);
+encode_again:
+ lock_flocks();
+ ceph_count_locks(inode, &num_fcntl_locks, &num_flock_locks);
+ unlock_flocks();
+ flocks = kmalloc((num_fcntl_locks+num_flock_locks) *
+ sizeof(struct ceph_filelock), GFP_NOFS);
+ if (!flocks) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+ lock_flocks();
+ err = ceph_encode_locks_to_buffer(inode, flocks,
+ num_fcntl_locks,
+ num_flock_locks);
+ unlock_flocks();
+ if (err) {
+ kfree(flocks);
+ if (err == -ENOSPC)
+ goto encode_again;
+ goto out_free;
+ }
+ /*
+ * number of encoded locks is stable, so copy to pagelist
+ */
+ rec.v2.flock_len = cpu_to_le32(2*sizeof(u32) +
+ (num_fcntl_locks+num_flock_locks) *
+ sizeof(struct ceph_filelock));
+ err = ceph_pagelist_append(pagelist, &rec, reclen);
+ if (!err)
+ err = ceph_locks_to_pagelist(flocks, pagelist,
+ num_fcntl_locks,
+ num_flock_locks);
+ kfree(flocks);
} else {
err = ceph_pagelist_append(pagelist, &rec, reclen);
}
-
out_free:
kfree(path);
out_dput:
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -847,8 +847,13 @@ extern const struct export_operations ce
extern int ceph_lock(struct file *file, int cmd, struct file_lock *fl);
extern int ceph_flock(struct file *file, int cmd, struct file_lock *fl);
extern void ceph_count_locks(struct inode *inode, int *p_num, int *f_num);
-extern int ceph_encode_locks(struct inode *i, struct ceph_pagelist *p,
- int p_locks, int f_locks);
+extern int ceph_encode_locks_to_buffer(struct inode *inode,
+ struct ceph_filelock *flocks,
+ int num_fcntl_locks,
+ int num_flock_locks);
+extern int ceph_locks_to_pagelist(struct ceph_filelock *flocks,
+ struct ceph_pagelist *pagelist,
+ int num_fcntl_locks, int num_flock_locks);
extern int lock_to_ceph_filelock(struct file_lock *fl, struct ceph_filelock *c);
/* debugfs.c */
next prev parent reply other threads:[~2013-06-18 16:14 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-06-18 16:14 [ 00/26] 3.4.50-stable review Greg Kroah-Hartman
2013-06-18 16:14 ` [ 01/26] b43: stop format string leaking into error msgs Greg Kroah-Hartman
2013-06-18 16:14 ` [ 02/26] libceph: must hold mutex for reset_changed_osds() Greg Kroah-Hartman
2013-06-18 16:14 ` [ 03/26] ceph: add cpu_to_le32() calls when encoding a reconnect capability Greg Kroah-Hartman
2013-06-18 16:14 ` Greg Kroah-Hartman [this message]
2013-06-18 16:14 ` [ 05/26] drivers/rtc/rtc-twl.c: fix missing device_init_wakeup() when booted with device tree Greg Kroah-Hartman
2013-06-18 16:14 ` [ 06/26] drm/gma500/psb: Unpin framebuffer on crtc disable Greg Kroah-Hartman
2013-06-18 16:14 ` [ 07/26] drm/gma500/cdv: " Greg Kroah-Hartman
2013-06-18 16:14 ` [ 08/26] Bluetooth: Fix mgmt handling of power on failures Greg Kroah-Hartman
2013-06-18 16:14 ` [ 09/26] ath9k: Disable PowerSave by default Greg Kroah-Hartman
2013-06-18 16:14 ` [ 10/26] ath9k: Use minstrel rate control " Greg Kroah-Hartman
2013-06-18 16:14 ` [ 11/26] CPU hotplug: provide a generic helper to disable/enable CPU hotplug Greg Kroah-Hartman
2013-06-18 16:14 ` [ 12/26] reboot: rigrate shutdown/reboot to boot cpu Greg Kroah-Hartman
2013-06-18 16:14 ` [ 13/26] cciss: fix broken mutex usage in ioctl Greg Kroah-Hartman
2013-06-18 16:14 ` [ 14/26] drm/i915: prefer VBT modes for SVDO-LVDS over EDID Greg Kroah-Hartman
2013-06-18 16:14 ` [ 15/26] swap: avoid read_swap_cache_async() race to deadlock while waiting on discard I/O completion Greg Kroah-Hartman
2013-06-18 16:14 ` [ 16/26] md/raid1: consider WRITE as successful only if at least one non-Faulty and non-rebuilding drive completed it Greg Kroah-Hartman
2013-06-18 16:14 ` [ 17/26] mm: migration: add migrate_entry_wait_huge() Greg Kroah-Hartman
2013-06-18 16:14 ` [ 18/26] x86: Fix typo in kexec register clearing Greg Kroah-Hartman
2013-06-18 16:14 ` [ 19/26] libceph: clear messenger auth_retry flag when we authenticate Greg Kroah-Hartman
2013-06-18 16:15 ` [ 20/26] libceph: fix authorizer invalidation Greg Kroah-Hartman
2013-06-18 16:15 ` [ 21/26] libceph: add update_authorizer auth method Greg Kroah-Hartman
2013-06-18 16:15 ` [ 22/26] libceph: wrap auth ops in wrapper functions Greg Kroah-Hartman
2013-06-18 16:15 ` [ 23/26] libceph: wrap auth methods in a mutex Greg Kroah-Hartman
2013-06-18 16:15 ` [ 24/26] ceph: fix statvfs fr_size Greg Kroah-Hartman
2013-06-18 16:15 ` [ 25/26] powerpc: Fix stack overflow crash in resume_kernel when ftracing Greg Kroah-Hartman
2013-06-18 16:15 ` [ 26/26] powerpc: Fix missing/delayed calls to irq_work Greg Kroah-Hartman
[not found] ` <CAKocOOOnfMbYymOamd8Woy=tmjnQ1i9xGLx-U2Unj8j7sk2RQA@mail.gmail.com>
2013-06-18 22:23 ` [ 00/26] 3.4.50-stable review Shuah Khan
2013-06-20 10:53 ` Satoru Takeuchi
2013-06-20 16:59 ` Greg Kroah-Hartman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20130618161232.103441477@linuxfoundation.org \
--to=greg@kroah.com \
--cc=elder@inktank.com \
--cc=gregkh@linuxfoundation.org \
--cc=jaschut@sandia.gov \
--cc=linux-kernel@vger.kernel.org \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).