Hello community, here is the log from the commit of package drbd for openSUSE:Factory checked in at 2017-06-23 09:18:17 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/drbd (Old) and /work/SRC/openSUSE:Factory/.drbd.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "drbd" Fri Jun 23 09:18:17 2017 rev:59 rq:505630 version:9.0.8+git.c8bc3670 Changes: -------- --- /work/SRC/openSUSE:Factory/drbd/drbd.changes 2017-05-29 22:19:25.189937271 +0200 +++ /work/SRC/openSUSE:Factory/.drbd.new/drbd.changes 2017-06-23 09:18:45.627080839 +0200 @@ -1,0 +2,15 @@ +Wed Jun 14 03:21:59 UTC 2017 - nw...@suse.com + +- bsc#1045473, update to 9.0.8 + fix a race condition between adding connections and receiving data + fix a OOPS on a diskfull node when a request from a diskless node + fix a distributed deadlock when doing a discard/write-same burst + fix an issue with diskless nodes adopting wrong current UUIDs + fix wrongly rejected two-phase-state transactions + fix initial resync, triggered by "--force primary"(regression 9.0.7) + Speed-up AL-updates with bio flags REQ_META and REQ_PRIO + Merged changes from 8.4.10 and with that compatibility with Linux-4.12 +- Remove patch fix-initial-sync-stop.patch +- Fix the license to GPL-2.0+ + +------------------------------------------------------------------- Old: ---- drbd-9.0.7rc2+git.36abd387.tar.bz2 fix-initial-sync-stop.patch New: ---- drbd-9.0.8+git.c8bc3670.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ drbd.spec ++++++ --- /var/tmp/diff_new_pack.Y5oLyz/_old 2017-06-23 09:18:46.238994374 +0200 +++ /var/tmp/diff_new_pack.Y5oLyz/_new 2017-06-23 09:18:46.238994374 +0200 @@ -1,7 +1,7 @@ # # spec file for package drbd # -# Copyright (c) 2017 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -25,10 +25,10 @@ %endif Name: drbd -Version: 9.0.7rc2+git.36abd387 +Version: 9.0.8+git.c8bc3670 Release: 0 Summary: DRBD driver for Linux -License: GPL-2.0 +License: GPL-2.0+ Group: Productivity/Clustering/HA Url: http://drbd.linbit.com/ Source: %{name}-%{version}.tar.bz2 @@ -37,12 +37,11 @@ Source2: Module.supported Source3: drbd_git_revision Patch1: fix-resync-finished-with-syncs-have-bits-set.patch -Patch2: fix-initial-sync-stop.patch BuildRequires: kernel-source BuildRequires: kernel-syms BuildRequires: module-init-tools -Requires: drbd-utils >= 8.9.11 -Supplements: drbd-utils >= 8.9.11 +Requires: drbd-utils >= 9.0.0 +Supplements: drbd-utils >= 9.0.0 Obsoletes: drbd-kmp < %{version} BuildRoot: %{_tmppath}/%{name}-%{version}-build ExcludeArch: i586 s390 @@ -70,7 +69,6 @@ %prep %setup -q -n drbd-%{version} %patch1 -p1 -%patch2 -p1 mkdir source cp -a drbd/. source/. || : @@ -100,7 +98,7 @@ done mkdir -p %{buildroot}/%{_sbindir} -%{__ln_s} -f %{_sbindir}/service %{buildroot}/%{_sbindir}/rc%{name} +ln -s -f %{_sbindir}/service %{buildroot}/%{_sbindir}/rc%{name} rm -f drbd.conf %clean ++++++ _service ++++++ --- /var/tmp/diff_new_pack.Y5oLyz/_old 2017-06-23 09:18:46.286987593 +0200 +++ /var/tmp/diff_new_pack.Y5oLyz/_new 2017-06-23 09:18:46.286987593 +0200 @@ -7,10 +7,10 @@ To update to a new release, change "revision" to the desired git commit hash and bump "version" if necessary - <param name="version">9.0.7rc2</param> + <param name="version">9.0.8</param> --> - <param name="versionformat">9.0.7rc2+git.%h</param> - <param name="revision">36abd387b6e4341a58117711b2e95777c1dad8ab</param> + <param name="versionformat">9.0.8+git.%h</param> + <param name="revision">c8bc36701c7c7ffc2c208f620c6d89e4ec265704</param> </service> <service name="recompress" mode="disabled"> ++++++ drbd-9.0.7rc2+git.36abd387.tar.bz2 -> drbd-9.0.8+git.c8bc3670.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/ChangeLog new/drbd-9.0.8+git.c8bc3670/ChangeLog --- old/drbd-9.0.7rc2+git.36abd387/ChangeLog 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/ChangeLog 2017-06-19 15:49:34.000000000 +0200 @@ -2,6 +2,38 @@ ------ For even more detail, use "git log" or visit http://git.drbd.org/. +9.0.8-1 (api:genl2/proto:86-112/transport:14) +-------- + * fix a race condition between adding connections and receiving data + blocks; When you hit it caused an OOPS + * fix a OOPS on a diskfull node when a request from a diskless + node causes an error from the back-end device. (This is a regression that + was introduced with the 9.0.7 release) + * fix a distributed deadlock when doing a discard/write-same burst + * fix an issue with diskless nodes adopting wrong current UUIDs + * fix wrongly rejected two-phase-state transactions; this issue was a + cause for drbdmanage init failing for 3 nodes + * fix attach of first disk after resource had no disk at all + * fix to not clear bitmap content and UUIDs in case we ignored a + split-brain situation + * fix a possible OOPS, caused when the sender thread tries to send + something after the sockets where free()'ed + * fix ignoring split-brain situations to the rare cases it was + intended to in the first place + * fix an issue with current-uuid not getting written for 5 seconds. When a + resources was down'd/up'd or the node rebooted, you got split brain + afterwards + * fix a race that caused DRBD to go StandAlone instead of Connecting + after loosing a connection + * Serialize reconciliation resync after the nodes found it if they + are UpToDate + * fix initial resync, triggered by "--force primary"; this is a fix + for a regression introduced in 9.0.7 + * new configuration option that allows to report back IO errors instead + of freezing IO in case a partition looses quorum + * Speed-up AL-updates with bio flags REQ_META and REQ_PRIO + * merged changes from 8.4.10 and with that compatibility with Linux-4.12 + 9.0.7-1 (api:genl2/proto:86-112/transport:14) -------- * various fixes to the 2-phase-commit online resize diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/Makefile new/drbd-9.0.8+git.c8bc3670/Makefile --- old/drbd-9.0.7rc2+git.36abd387/Makefile 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/Makefile 2017-06-19 15:49:34.000000000 +0200 @@ -246,7 +246,7 @@ ifdef DEBBUILD .PHONY: km-deb -km-deb: distclean drbd/.drbd_git_revision +km-deb: check-submods distclean drbd/.drbd_git_revision $(DEBBUILD) -i -us -uc -b endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/debian/changelog new/drbd-9.0.8+git.c8bc3670/debian/changelog --- old/drbd-9.0.7rc2+git.36abd387/debian/changelog 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/debian/changelog 2017-06-19 15:49:34.000000000 +0200 @@ -1,3 +1,9 @@ +drbd (9.0.8-1) unstable; urgency=low + + * New upstream release. + + -- Philipp Reisner <p...@linbit.com> Mon, 19 Jun 2017 15:27:42 +0800 + drbd (9.0.7-1) unstable; urgency=low * New upstream release. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/debian/control new/drbd-9.0.8+git.c8bc3670/debian/control --- old/drbd-9.0.7rc2+git.36abd387/debian/control 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/debian/control 2017-06-19 15:49:34.000000000 +0200 @@ -15,7 +15,7 @@ Section: admin Depends: debhelper (>=7), dkms (>= 1.9.5), - drbd-utils (>= 8.9.11), + drbd-utils (>= 9.0.0), ${misc:Depends} Conflicts: drbd-module-source, drbd8-module-source diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd/drbd-kernel-compat/blkdev_issue_zeroout.c new/drbd-9.0.8+git.c8bc3670/drbd/drbd-kernel-compat/blkdev_issue_zeroout.c --- old/drbd-9.0.7rc2+git.36abd387/drbd/drbd-kernel-compat/blkdev_issue_zeroout.c 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/drbd/drbd-kernel-compat/blkdev_issue_zeroout.c 2017-06-19 15:49:34.000000000 +0200 @@ -28,15 +28,14 @@ * @sector: start sector * @nr_sects: number of sectors to write * @gfp_mask: memory allocation flags (for bio_alloc) - * @discard: whether to discard the block range. - * IGNORED in this compat implementation. + * @flags: controls detailed behavior (ignored) * * Description: * Generate and issue number of bios with zerofiled pages. */ int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, - sector_t nr_sects, gfp_t gfp_mask, bool discard) + sector_t nr_sects, gfp_t gfp_mask, unsigned int flags) { int ret; struct bio *bio; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd/drbd-kernel-compat/drbd_wrappers.h new/drbd-9.0.8+git.c8bc3670/drbd/drbd-kernel-compat/drbd_wrappers.h --- old/drbd-9.0.7rc2+git.36abd387/drbd/drbd-kernel-compat/drbd_wrappers.h 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/drbd/drbd-kernel-compat/drbd_wrappers.h 2017-06-19 15:49:34.000000000 +0200 @@ -906,20 +906,28 @@ } \ } while(0) -#ifdef COMPAT_HAVE_POINTER_BACKING_DEV_INFO +#ifdef BDI_CAP_STABLE_WRITES /* >= v3.9 */ +#define set_bdi_cap_stable_writes(cap) do { (cap) |= BDI_CAP_STABLE_WRITES; } while (0) +#else /* < v3.9 */ +#define set_bdi_cap_stable_writes(cap) do { } while (0) +#endif + +#ifdef COMPAT_HAVE_POINTER_BACKING_DEV_INFO /* >= v4.11 */ #define bdi_from_device(device) (device->ldev->backing_bdev->bd_disk->queue->backing_dev_info) #define init_bdev_info(bdev_info, drbd_congested, device) do { \ (bdev_info)->congested_fn = drbd_congested; \ (bdev_info)->congested_data = device; \ + set_bdi_cap_stable_writes(bdev_info->capabilities); \ } while(0) #define adjust_ra_pages(q, b) _adjust_ra_pages((q)->backing_dev_info->ra_pages, (b)->backing_dev_info->ra_pages) -#else +#else /* < v4.11 */ #define bdi_rw_congested(BDI) bdi_rw_congested(&BDI) #define bdi_congested(BDI, BDI_BITS) bdi_congested(&BDI, (BDI_BITS)) #define bdi_from_device(device) (&device->ldev->backing_bdev->bd_disk->queue->backing_dev_info) #define init_bdev_info(bdev_info, drbd_congested, device) do { \ (bdev_info).congested_fn = drbd_congested; \ (bdev_info).congested_data = device; \ + set_bdi_cap_stable_writes((bdev_info).capabilities); \ } while(0) #define adjust_ra_pages(q, b) _adjust_ra_pages((q)->backing_dev_info.ra_pages, (b)->backing_dev_info.ra_pages) #endif @@ -1203,6 +1211,18 @@ #endif /* + * v4.12 fceb6435e852 netlink: pass extended ACK struct to parsing functions + * and some preparation commits introduce a new "netlink extended ack" error + * reporting mechanism. For now, only work around that here. As trigger, use + * NETLINK_MAX_COOKIE_LEN introduced somewhere in the middle of that patchset. + */ +#ifndef NETLINK_MAX_COOKIE_LEN +#include <net/netlink.h> +#define nla_parse_nested(tb, maxtype, nla, policy, extack) \ + nla_parse_nested(tb, maxtype, nla, policy) +#endif + +/* * genlmsg_reply() was added to <net/genetlink.h> in mainline commit 81878d27 * (v2.6.20-rc2). */ @@ -1339,18 +1359,6 @@ #endif /* - * kref_sub() was introduced in mainline commit ecf7ace9 (v2.6.38-rc1). - */ -#ifndef COMPAT_HAVE_KREF_SUB -static inline void kref_sub(struct kref *kref, unsigned int count, - void (*release) (struct kref *kref)) -{ - while (count--) - kref_put(kref, release); -} -#endif - -/* * list_for_each_entry_continue_rcu() was introduced in mainline commit * 254245d2 (v2.6.33-rc1). */ @@ -1455,13 +1463,22 @@ #ifndef BLKDEV_ISSUE_ZEROOUT_EXPORTED /* Was introduced with 2.6.34 */ extern int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, - sector_t nr_sects, gfp_t gfp_mask, bool discard); + sector_t nr_sects, gfp_t gfp_mask, unsigned flags); #else /* synopsis changed a few times, though */ -#ifdef COMPAT_BLKDEV_ISSUE_ZEROOUT_BLKDEV_IFL_WAIT -#define blkdev_issue_zeroout(BDEV, SS, NS, GFP, discard) \ +#if defined(BLKDEV_ZERO_NOUNMAP) +/* >= v4.12 */ +/* use blkdev_issue_zeroout() as written out in the actual source code. + * right now, we only use it with flags = BLKDEV_ZERO_NOUNMAP */ +#elif defined(COMPAT_BLKDEV_ISSUE_ZEROOUT_BLKDEV_IFL_WAIT) +/* cannot yet tell it to use (or not use) discard, + * but must tell it to be synchronous */ blkdev_issue_zeroout(BDEV, SS, NS, GFP, BLKDEV_IFL_WAIT) -#elif !defined(COMPAT_BLKDEV_ISSUE_ZEROOUT_DISCARD) +#elif defined(COMPAT_BLKDEV_ISSUE_ZEROOUT_DISCARD) +/* no BLKDEV_ZERO_NOUNMAP as last parameter, but a bool discard instead */ +#define blkdev_issue_zeroout(BDEV, SS, NS, GFP, flags /* = NOUNMAP */) \ + blkdev_issue_zeroout(BDEV, SS, NS, GFP, false /* bool discard */) +#else /* !defined(COMPAT_BLKDEV_ISSUE_ZEROOUT_DISCARD) */ #define blkdev_issue_zeroout(BDEV, SS, NS, GFP, discard) \ blkdev_issue_zeroout(BDEV, SS, NS, GFP) #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd/drbd-kernel-compat/tests/have_ib_get_dma_mr.c new/drbd-9.0.8+git.c8bc3670/drbd/drbd-kernel-compat/tests/have_ib_get_dma_mr.c --- old/drbd-9.0.7rc2+git.36abd387/drbd/drbd-kernel-compat/tests/have_ib_get_dma_mr.c 1970-01-01 01:00:00.000000000 +0100 +++ new/drbd-9.0.8+git.c8bc3670/drbd/drbd-kernel-compat/tests/have_ib_get_dma_mr.c 2017-06-19 15:49:34.000000000 +0200 @@ -0,0 +1,11 @@ +#include <rdma/ib_verbs.h> + +struct ib_mr * foo(void) +{ + struct ib_pd *pd = NULL; + struct ib_mr *mr; + + mr = ib_get_dma_mr(pd, 0); + + return mr; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd/drbd-kernel-compat/tests/have_kref_sub.c new/drbd-9.0.8+git.c8bc3670/drbd/drbd-kernel-compat/tests/have_kref_sub.c --- old/drbd-9.0.7rc2+git.36abd387/drbd/drbd-kernel-compat/tests/have_kref_sub.c 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/drbd/drbd-kernel-compat/tests/have_kref_sub.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,8 +0,0 @@ -#include <linux/kref.h> - -void test(void) -{ - struct kref kref = { }; - - kref_sub(&kref, 2, NULL); -} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_actlog.c new/drbd-9.0.8+git.c8bc3670/drbd/drbd_actlog.c --- old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_actlog.c 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/drbd/drbd_actlog.c 2017-06-19 15:49:34.000000000 +0200 @@ -159,6 +159,12 @@ op_flags |= DRBD_REQ_FUA | DRBD_REQ_PREFLUSH; op_flags |= DRBD_REQ_UNPLUG | DRBD_REQ_SYNC | REQ_NOIDLE; +#ifdef REQ_PRIO + op_flags |= REQ_PRIO; +#endif +#ifdef REQ_META + op_flags |= REQ_META; +#endif #ifdef COMPAT_MAYBE_RETRY_HARDBARRIER /* < 2.6.36, "barrier" semantic may fail with EOPNOTSUPP */ retry: @@ -1144,6 +1150,9 @@ return 0; } + if (peer_device->bitmap_index == -1) /* no bitmap... */ + return 0; + if (!get_ldev(device)) return 0; /* no disk, no metadata, no bitmap to manipulate bits in */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_debugfs.c new/drbd-9.0.8+git.c8bc3670/drbd/drbd_debugfs.c --- old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_debugfs.c 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/drbd/drbd_debugfs.c 2017-06-19 15:49:34.000000000 +0200 @@ -1299,7 +1299,7 @@ seq_putc(seq, '='); seq_putc(seq, '>'); for (i = 0; i < y; i++) - seq_printf(seq, "."); + seq_putc(seq, '.'); seq_puts(seq, "] "); if (repl_state == L_VERIFY_S || repl_state == L_VERIFY_T) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_int.h new/drbd-9.0.8+git.c8bc3670/drbd/drbd_int.h --- old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_int.h 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/drbd/drbd_int.h 2017-06-19 15:49:34.000000000 +0200 @@ -748,6 +748,7 @@ RECONNECT, CONN_DISCARD_MY_DATA, SEND_STATE_AFTER_AHEAD_C, + NOTIFY_PEERS_LOST_PRIMARY, }; /* flag bits per resource */ @@ -1274,7 +1275,7 @@ * are deferred to this single-threaded work queue */ struct submit_worker submit; u64 read_nodes; /* used for balancing read requests among peers */ - bool susp_quorum[2]; /* IO suspended quorum lost */ + bool have_quorum[2]; /* no quorum -> suspend IO or error IO */ }; struct drbd_bm_aio_ctx { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_main.c new/drbd-9.0.8+git.c8bc3670/drbd/drbd_main.c --- old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_main.c 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/drbd/drbd_main.c 2017-06-19 15:49:34.000000000 +0200 @@ -759,19 +759,19 @@ #define drbd_calc_cpu_mask(A) ({}) #endif -static bool drbd_all_neighbor_secondary(struct drbd_resource *resource, u64 *authoritative_ptr) +static bool drbd_all_neighbor_secondary(struct drbd_device *device, u64 *authoritative_ptr) { - struct drbd_connection *connection; + struct drbd_peer_device *peer_device; bool all_secondary = true; u64 authoritative = 0; int id; rcu_read_lock(); - for_each_connection_rcu(connection, resource) { - if (connection->cstate[NOW] >= C_CONNECTED && - connection->peer_role[NOW] == R_PRIMARY) { + for_each_peer_device_rcu(peer_device, device) { + if (peer_device->repl_state[NOW] >= L_ESTABLISHED && + peer_device->connection->peer_role[NOW] == R_PRIMARY) { all_secondary = false; - id = connection->peer_node_id; + id = peer_device->node_id; authoritative |= NODE_MASK(id); } } @@ -796,7 +796,7 @@ if (resource->role[NOW] == R_PRIMARY) return true; - if (!drbd_all_neighbor_secondary(resource, authoritative_ptr)) + if (!drbd_all_neighbor_secondary(device, authoritative_ptr)) return false; rcu_read_lock(); @@ -3677,6 +3677,8 @@ } add_disk(disk); + device->have_quorum[OLD] = true; + device->have_quorum[NEW] = true; for_each_peer_device(peer_device, device) { connection = peer_device->connection; @@ -3760,17 +3762,21 @@ void drbd_put_device(struct drbd_device *device) { struct drbd_peer_device *peer_device; - int refs = 3; + int i; destroy_workqueue(device->submit.wq); device->submit.wq = NULL; del_timer_sync(&device->request_timer); - for_each_peer_device(peer_device, device) - refs++; + for_each_peer_device(peer_device, device) { + kref_debug_put(&device->kref_debug, 1); + kref_put(&device->kref, drbd_destroy_device); + } - kref_debug_sub(&device->kref_debug, refs, 1); - kref_sub(&device->kref, refs, drbd_destroy_device); + for (i = 0; i < 3; i++) { + kref_debug_put(&device->kref_debug, 1); + kref_put(&device->kref, drbd_destroy_device); + } } /** @@ -3812,11 +3818,9 @@ void drbd_put_connection(struct drbd_connection *connection) { struct drbd_peer_device *peer_device; - int vnr, rr, refs = 1; + int vnr, rr; del_connect_timer(connection); - idr_for_each_entry(&connection->peer_devices, peer_device, vnr) - refs++; rr = drbd_free_peer_reqs(connection->resource, &connection->done_ee, false); if (rr) @@ -3828,9 +3832,12 @@ drbd_transport_shutdown(connection, DESTROY_TRANSPORT); - kref_debug_sub(&connection->kref_debug, refs - 1, 3); + idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { + kref_debug_put(&connection->kref_debug, 3); + kref_put(&connection->kref, drbd_destroy_connection); + } kref_debug_put(&connection->kref_debug, 10); - kref_sub(&connection->kref, refs, drbd_destroy_connection); + kref_put(&connection->kref, drbd_destroy_connection); } static int __init drbd_init(void) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_nl.c new/drbd-9.0.8+git.c8bc3670/drbd/drbd_nl.c --- old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_nl.c 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/drbd/drbd_nl.c 2017-06-19 15:49:34.000000000 +0200 @@ -3385,6 +3385,33 @@ goto unlock_fail_free_connection; } + /* Set bitmap_index if it was allocated previously */ + idr_for_each_entry(&connection->peer_devices, peer_device, i) { + unsigned int bitmap_index; + + device = peer_device->device; + if (!get_ldev(device)) + continue; + + bitmap_index = device->ldev->md.peers[adm_ctx->peer_node_id].bitmap_index; + if (bitmap_index != -1) + peer_device->bitmap_index = bitmap_index; + put_ldev(device); + } + + idr_for_each_entry(&connection->peer_devices, peer_device, i) { + if (get_ldev_if_state(peer_device->device, D_NEGOTIATING)) { + err = drbd_attach_peer_device(peer_device); + put_ldev(peer_device->device); + if (err) { + retcode = ERR_NOMEM; + goto unlock_fail_free_connection; + } + } + peer_device->send_cnt = 0; + peer_device->recv_cnt = 0; + } + idr_for_each_entry(&connection->peer_devices, peer_device, i) { struct drbd_device *device = peer_device->device; @@ -3422,20 +3449,6 @@ if (connection->peer_node_id > adm_ctx->resource->max_node_id) adm_ctx->resource->max_node_id = connection->peer_node_id; - /* Set bitmap_index if it was allocated previously */ - idr_for_each_entry(&connection->peer_devices, peer_device, i) { - unsigned int bitmap_index; - - device = peer_device->device; - if (!get_ldev(device)) - continue; - - bitmap_index = device->ldev->md.peers[adm_ctx->peer_node_id].bitmap_index; - if (bitmap_index != -1) - peer_device->bitmap_index = bitmap_index; - put_ldev(device); - } - connection_to_info(&connection_info, connection); flags = (peer_devices--) ? NOTIFY_CONTINUES : 0; mutex_lock(¬ification_mutex); @@ -3449,18 +3462,6 @@ } mutex_unlock(¬ification_mutex); - idr_for_each_entry(&connection->peer_devices, peer_device, i) { - if (get_ldev_if_state(peer_device->device, D_NEGOTIATING)) { - err = drbd_attach_peer_device(peer_device); - put_ldev(peer_device->device); - if (err) { - retcode = ERR_NOMEM; - goto unlock_fail_free_connection; - } - } - peer_device->send_cnt = 0; - peer_device->recv_cnt = 0; - } mutex_unlock(&adm_ctx->resource->conf_update); drbd_debugfs_connection_add(connection); /* after ->net_conf was assigned */ @@ -4506,7 +4507,10 @@ __change_io_susp_no_data(resource, false); for_each_connection(connection, resource) __change_io_susp_fencing(connection, false); - __change_io_susp_quorum(device, false); + + if (resource->res_opts.on_no_quorum == ONQ_SUSPEND_IO) + __change_have_quorum(device, true); + /* TODO: Throw away queued IO requests... */ retcode = end_state_change(resource, &irq_flags); if (retcode == SS_SUCCESS) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_nla.c new/drbd-9.0.8+git.c8bc3670/drbd/drbd_nla.c --- old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_nla.c 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/drbd/drbd_nla.c 2017-06-19 15:49:34.000000000 +0200 @@ -35,7 +35,7 @@ err = drbd_nla_check_mandatory(maxtype, nla); if (!err) - err = nla_parse_nested(tb, maxtype, nla, policy); + err = nla_parse_nested(tb, maxtype, nla, policy, NULL); return err; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_receiver.c new/drbd-9.0.8+git.c8bc3670/drbd/drbd_receiver.c --- old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_receiver.c 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/drbd/drbd_receiver.c 2017-06-19 15:49:34.000000000 +0200 @@ -1287,7 +1287,7 @@ tmp = start + granularity - sector_div(tmp, granularity); nr = tmp - start; - err |= blkdev_issue_zeroout(bdev, start, nr, GFP_NOIO, 0); + err |= blkdev_issue_zeroout(bdev, start, nr, GFP_NOIO, BLKDEV_ZERO_NOUNMAP); nr_sectors -= nr; start = tmp; } @@ -1299,7 +1299,7 @@ } zero_out: if (nr_sectors) { - err |= blkdev_issue_zeroout(bdev, start, nr_sectors, GFP_NOIO, 0); + err |= blkdev_issue_zeroout(bdev, start, nr_sectors, GFP_NOIO, BLKDEV_ZERO_NOUNMAP); } return err != 0; } @@ -3740,8 +3740,11 @@ } else if (hg < 0) { /* become sync target */ rv = L_WF_BITMAP_T; } else { + u64 peer_current_uuid = peer_device->current_uuid & ~UUID_PRIMARY; + u64 my_current_uuid = drbd_current_uuid(device) & ~UUID_PRIMARY; + rv = L_ESTABLISHED; - if (drbd_bitmap_uuid(peer_device)) { + if (drbd_bitmap_uuid(peer_device) && peer_current_uuid == my_current_uuid) { drbd_info(peer_device, "clearing bitmap UUID and bitmap content (%lu bits)\n", drbd_bm_total_weight(peer_device)); drbd_uuid_set_bitmap(peer_device, 0); @@ -8559,7 +8562,7 @@ drbd_uncork(connection, CONTROL_STREAM); if (err) - change_cstate(connection, C_DISCONNECTING, CS_HARD); + change_cstate(connection, C_NETWORK_FAILURE, CS_HARD); } void drbd_send_peer_ack_wf(struct work_struct *ws) @@ -8568,7 +8571,7 @@ container_of(ws, struct drbd_connection, peer_ack_work); if (process_peer_ack_list(connection)) - change_cstate(connection, C_DISCONNECTING, CS_HARD); + change_cstate(connection, C_NETWORK_FAILURE, CS_HARD); } EXPORT_SYMBOL(drbd_alloc_pages); /* for transports */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_req.c new/drbd-9.0.8+git.c8bc3670/drbd/drbd_req.c --- old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_req.c 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/drbd/drbd_req.c 2017-06-19 15:49:34.000000000 +0200 @@ -179,22 +179,10 @@ struct drbd_request *destroy_next; struct drbd_device *device; struct drbd_peer_device *peer_device; - unsigned int s, device_refs = 0; + unsigned int s; bool was_last_ref = false; tail_recursion: - if (device_refs > 0 && device != req->device) { - /* We accumulate device refs to put, it is very likely that we - * destroy a number of requests for the same volume in a row. - * But if the tail-recursed request happens to be for a - * different volume, we need to put the accumulated device refs - * now, while we still know the corresponding device, - * and start accumulating for the other device. - */ - kref_debug_sub(&device->kref_debug, device_refs, 6); - kref_sub(&device->kref, device_refs, drbd_destroy_device); - device_refs = 0; - } device = req->device; s = req->rq_state[0]; destroy_next = req->destroy_next; @@ -210,7 +198,7 @@ drbd_err(device, "drbd_req_destroy: Logic BUG rq_state: (0:%x, %d:%x), completion_ref = %d\n", s, 1 + peer_device->node_id, ns, atomic_read(&req->completion_ref)); - goto out; + return; } /* more paranoia */ @@ -218,7 +206,7 @@ atomic_read(&req->completion_ref) || (s & RQ_LOCAL_PENDING)) { drbd_err(device, "drbd_req_destroy: Logic BUG rq_state: %x, completion_ref = %d\n", s, atomic_read(&req->completion_ref)); - goto out; + return; } list_del_init(&req->tl_requests); @@ -293,7 +281,6 @@ } } - device_refs++; /* In both branches of the if the reference to device gets released */ if (s & RQ_WRITE && req->i.size) { struct drbd_resource *resource = device->resource; struct drbd_request *peer_ack_req = resource->peer_ack_req; @@ -317,6 +304,10 @@ } else mempool_free(req, drbd_request_mempool); + /* In both branches of the if above, the reference to device gets released */ + kref_debug_put(&device->kref_debug, 6); + kref_put(&device->kref, drbd_destroy_device); + /* * Do the equivalent of: * kref_put(&req->kref, drbd_req_destroy) @@ -327,10 +318,6 @@ if (refcount_dec_and_test(&req->kref.refcount)) goto tail_recursion; } - -out: - kref_debug_sub(&device->kref_debug, device_refs, 6); - kref_sub(&device->kref, device_refs, drbd_destroy_device); } static void wake_all_senders(struct drbd_resource *resource) { @@ -494,23 +481,31 @@ } /* still holds resource->req_lock */ -static int drbd_req_put_completion_ref(struct drbd_request *req, struct bio_and_error *m, int put) +static void drbd_req_put_completion_ref(struct drbd_request *req, struct bio_and_error *m, int put) { D_ASSERT(req->device, m || (req->rq_state[0] & RQ_POSTPONED)); + if (!put) + return; + if (!atomic_sub_and_test(put, &req->completion_ref)) - return 0; + return; drbd_req_complete(req, m); + /* local completion may still come in later, + * we need to keep the req object around. */ + if (req->rq_state[0] & RQ_LOCAL_ABORTED) + return; + if (req->rq_state[0] & RQ_POSTPONED) { /* don't destroy the req object just yet, * but queue it for retry */ drbd_restart_request(req); - return 0; + return; } - return 1; + kref_put(&req->kref, drbd_req_destroy); } static void set_if_null_req_next(struct drbd_peer_device *peer_device, struct drbd_request *req) @@ -602,7 +597,6 @@ unsigned set_local = set & RQ_STATE_0_MASK; unsigned clear_local = clear & RQ_STATE_0_MASK; int c_put = 0; - int k_put = 0; const int idx = peer_device ? 1 + peer_device->node_id : 0; /* FIXME n_connections, when this request was created/scheduled. */ @@ -639,6 +633,8 @@ /* intent: get references */ + kref_get(&req->kref); + if (!(old_local & RQ_LOCAL_PENDING) && (set_local & RQ_LOCAL_PENDING)) atomic_inc(&req->completion_ref); @@ -675,15 +671,12 @@ if (!(old_local & RQ_LOCAL_ABORTED) && (set_local & RQ_LOCAL_ABORTED)) { D_ASSERT(req->device, req->rq_state[0] & RQ_LOCAL_PENDING); - /* local completion may still come in later, - * we need to keep the req object around. */ - kref_get(&req->kref); ++c_put; } if ((old_local & RQ_LOCAL_PENDING) && (clear_local & RQ_LOCAL_PENDING)) { if (req->rq_state[0] & RQ_LOCAL_ABORTED) - ++k_put; + kref_put(&req->kref, drbd_req_destroy); else ++c_put; list_del_init(&req->req_pending_local); @@ -705,7 +698,7 @@ if (old_net & RQ_NET_SENT) atomic_sub(req->i.size >> 9, &peer_device->connection->ap_in_flight); if (old_net & RQ_EXP_BARR_ACK) - ++k_put; + kref_put(&req->kref, drbd_req_destroy); req->net_done_jif[peer_device->node_id] = jiffies; /* in ahead/behind mode, or just in case, @@ -718,27 +711,12 @@ /* potentially complete and destroy */ - if (k_put || c_put) { - /* Completion does it's own kref_put. If we are going to - * kref_sub below, we need req to be still around then. */ - int at_least = k_put + !!c_put; - int refcount = refcount_read(&req->kref.refcount); - if (refcount < at_least) - drbd_err(req->device, - "mod_rq_state: Logic BUG: 0: %x -> %x, %d: %x -> %x: refcount = %d, should be >= %d\n", - old_local, req->rq_state[0], - idx, old_net, req->rq_state[idx], - refcount, at_least); - } - /* If we made progress, retry conflicting peer requests, if any. */ if (req->i.waiting) wake_up(&req->device->misc_wait); - if (c_put) - k_put += drbd_req_put_completion_ref(req, m, c_put); - if (k_put) - kref_sub(&req->kref, k_put, drbd_req_destroy); + drbd_req_put_completion_ref(req, m, c_put); + kref_put(&req->kref, drbd_req_destroy); } static void drbd_report_io_error(struct drbd_device *device, struct drbd_request *req) @@ -1748,8 +1726,7 @@ } out: - if (drbd_req_put_completion_ref(req, &m, 1)) - kref_put(&req->kref, drbd_req_destroy); + drbd_req_put_completion_ref(req, &m, 1); spin_unlock_irq(&resource->req_lock); /* Even though above is a kref_put(), this is safe. @@ -2104,13 +2081,38 @@ drbd_kick_lo(device); } +/* 54efd50 block: make generic_make_request handle arbitrarily sized bios + * introduced blk_queue_split(), which is supposed to split (and put on the + * current->bio_list bio chain) any bio that is violating the queue limits. + * Before that, any user was supposed to go through bio_add_page(), which + * would call our merge bvec function, and that should already be sufficient + * to not violate queue limits. + * + * The way blk_queue_split() was implemented, together with the recursion-to- + * iteration loop in generic_make_request(), introduced a possible deadlock, + * which we worked around with drbd out-of-tree commit + * ab6ab5061f6d drbd: fix for possible deadlock in kernel >= 4.3 + * + * Upstream 4.11 finally took and improved our suggested fix with: + * 79bd99596b73 blk: improve order of bio handling in generic_make_request() + * f5fe1b51905d blk: Ensure users for current->bio_list can see the full list. + */ +#undef COMPAT_NEED_MAKE_REQUEST_RECURSION +#ifdef COMPAT_HAVE_BLK_QUEUE_SPLIT +# if LINUX_VERSION_CODE < KERNEL_VERSION(4,11,0) +# define COMPAT_NEED_MAKE_REQUEST_RECURSION +# endif +#else +# define blk_queue_split(q,b,l) do { } while (0) +#endif + MAKE_REQUEST_TYPE drbd_make_request(struct request_queue *q, struct bio *bio) { struct drbd_device *device = (struct drbd_device *) q->queuedata; + struct drbd_resource *resource = device->resource; unsigned long start_jif; -#ifdef COMPAT_HAVE_BLK_QUEUE_SPLIT - struct bio_list *current_bio_list = NULL; - struct bio_list my_on_stack_bl; +#ifdef COMPAT_NEED_MAKE_REQUEST_RECURSION + struct bio_list *current_bio_list; #endif /* We never supported BIO_RW_BARRIER. @@ -2122,35 +2124,24 @@ MAKE_REQUEST_RETURN; } -#ifdef COMPAT_HAVE_BLK_QUEUE_SPLIT -/* 54efd50 block: make generic_make_request handle arbitrarily sized bios - * introduced blk_queue_split(), which is supposed to split (and put on the - * current->bio_list bio chain) any bio that is violating the queue limits. - * Before that, any user was supposed to go through bio_add_page(), which - * would call our merge bvec function, and that should already be sufficient - * to not violate queue limits. - */ blk_queue_split(q, &bio, q->bio_split); - if (current->bio_list && !bio_list_empty(current->bio_list)) { - bio_list_init(&my_on_stack_bl); - current_bio_list = current->bio_list; - current->bio_list = &my_on_stack_bl; - } +#ifdef COMPAT_NEED_MAKE_REQUEST_RECURSION + current_bio_list = current->bio_list; + current->bio_list = NULL; #endif + if (!device->have_quorum[NOW] && resource->res_opts.on_no_quorum == ONQ_IO_ERROR) { + bio_endio(bio, -EIO); + MAKE_REQUEST_RETURN; + } + start_jif = jiffies; inc_ap_bio(device, bio_data_dir(bio)); __drbd_make_request(device, bio, start_jif); -#ifdef COMPAT_HAVE_BLK_QUEUE_SPLIT - if (current_bio_list) { - /* REAL RECURSION */ - current->bio_list = NULL; - while ((bio = bio_list_pop(&my_on_stack_bl))) - generic_make_request(bio); - current->bio_list = current_bio_list; - } +#ifdef COMPAT_NEED_MAKE_REQUEST_RECURSION + current->bio_list = current_bio_list; #endif MAKE_REQUEST_RETURN; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_sender.c new/drbd-9.0.8+git.c8bc3670/drbd/drbd_sender.c --- old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_sender.c 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/drbd/drbd_sender.c 2017-06-19 15:49:34.000000000 +0200 @@ -43,6 +43,7 @@ static int make_ov_request(struct drbd_peer_device *, int); static int make_resync_request(struct drbd_peer_device *, int); +static bool should_send_barrier(struct drbd_connection *, unsigned int epoch); static void maybe_send_barrier(struct drbd_connection *, unsigned int); /* endio handlers: @@ -2158,6 +2159,7 @@ up(&resource->state_sem); if (rv == SS_TIMEOUT || rv == SS_CONCURRENT_ST_CHG) goto repost; + drbd_notify_peers_lost_primary(resource); } else { repost: mod_timer(&resource->repost_up_to_date_timer, jiffies + HZ/10); @@ -2486,17 +2488,22 @@ * from the epoch of the last request we communicated, it is * safe to send the epoch separating barrier now. */ - send_barrier = - atomic_read(&connection->resource->current_tle_nr) != - connection->send.current_epoch_nr; + send_barrier = should_send_barrier(connection, + atomic_read(&connection->resource->current_tle_nr)); spin_unlock_irq(&connection->resource->req_lock); - if (send_barrier) + if (send_barrier) { + finish_wait(&connection->sender_work.q_wait, &wait); maybe_send_barrier(connection, connection->send.current_epoch_nr + 1); + continue; + } - if (test_and_clear_bit(SEND_STATE_AFTER_AHEAD_C, &connection->flags)) + if (test_and_clear_bit(SEND_STATE_AFTER_AHEAD_C, &connection->flags)) { + finish_wait(&connection->sender_work.q_wait, &wait); maybe_send_state_afer_ahead(connection); + continue; + } /* drbd_send() may have called flush_signals() */ if (get_t_state(&connection->sender) != RUNNING) @@ -2533,12 +2540,16 @@ } } +static bool should_send_barrier(struct drbd_connection *connection, unsigned int epoch) +{ + if (!connection->send.seen_any_write_yet) + return false; + return connection->send.current_epoch_nr != epoch; +} static void maybe_send_barrier(struct drbd_connection *connection, unsigned int epoch) { /* re-init if first write on this connection */ - if (!connection->send.seen_any_write_yet) - return; - if (connection->send.current_epoch_nr != epoch) { + if (should_send_barrier(connection, epoch)) { if (connection->send.current_epoch_writes) drbd_send_barrier(connection); connection->send.current_epoch_nr = epoch; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_state.c new/drbd-9.0.8+git.c8bc3670/drbd/drbd_state.c --- old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_state.c 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/drbd/drbd_state.c 2017-06-19 15:49:34.000000000 +0200 @@ -64,6 +64,11 @@ PH_COMMIT, }; +struct change_disk_state_context { + struct change_context context; + struct drbd_device *device; +}; + static bool lost_contact_to_peer_data(enum drbd_disk_state *peer_disk_state); static bool got_contact_to_peer_data(enum drbd_disk_state *peer_disk_state); static bool peer_returns_diskless(struct drbd_peer_device *peer_device, @@ -196,9 +201,12 @@ bool rv = false; int vnr; + if (resource->res_opts.on_no_quorum != ONQ_SUSPEND_IO) + return false; + rcu_read_lock(); idr_for_each_entry(&resource->devices, device, vnr) { - if (device->susp_quorum[which]) { + if (!device->have_quorum[which]) { rv = true; break; } @@ -302,8 +310,8 @@ device_state_change->device = device; memcpy(device_state_change->disk_state, device->disk_state, sizeof(device->disk_state)); - memcpy(device_state_change->susp_quorum, - device->susp_quorum, sizeof(device->susp_quorum)); + memcpy(device_state_change->have_quorum, + device->have_quorum, sizeof(device->have_quorum)); if (test_and_clear_bit(HAVE_LDEV, &device->flags)) device_state_change->have_ldev = true; @@ -378,7 +386,7 @@ &state_change->devices[n_device]; OLD_TO_NEW(device_state_change->disk_state); - OLD_TO_NEW(device_state_change->susp_quorum); + OLD_TO_NEW(device_state_change->have_quorum); } n_peer_devices = state_change->n_devices * state_change->n_connections; @@ -453,7 +461,7 @@ struct drbd_peer_device *peer_device; if (device->disk_state[OLD] != device->disk_state[NEW] || - device->susp_quorum[OLD] != device->susp_quorum[NEW]) + device->have_quorum[OLD] != device->have_quorum[NEW]) return true; for_each_peer_device(peer_device, device) { @@ -494,7 +502,7 @@ struct drbd_peer_device *peer_device; device->disk_state[NEW] = device->disk_state[NOW]; - device->susp_quorum[NEW] = device->susp_quorum[NOW]; + device->have_quorum[NEW] = device->have_quorum[NOW]; for_each_peer_device(peer_device, device) { peer_device->disk_state[NEW] = peer_device->disk_state[NOW]; @@ -618,7 +626,7 @@ struct drbd_peer_device *peer_device; device->disk_state[NOW] = device->disk_state[NEW]; - device->susp_quorum[NOW] = device->susp_quorum[NEW]; + device->have_quorum[NOW] = device->have_quorum[NEW]; for_each_peer_device(peer_device, device) { peer_device->disk_state[NOW] = peer_device->disk_state[NEW]; @@ -1837,7 +1845,7 @@ bool have_quorum = calc_quorum(device, NEW, NULL); if (had_quorum && !have_quorum) - device->susp_quorum[NEW] = true; + device->have_quorum[NEW] = false; } put_ldev(device); } @@ -2375,13 +2383,17 @@ static inline bool state_change_is_susp_quorum(struct drbd_state_change *state_change, enum which_state which) { + struct drbd_resource *resource = state_change->resource[0].resource; int n_device; + if (resource->res_opts.on_no_quorum != ONQ_SUSPEND_IO) + return false; + for (n_device = 0; n_device < state_change->n_devices; n_device++) { struct drbd_device_state_change *device_state_change = &state_change->devices[n_device]; - if (device_state_change->susp_quorum[which]) + if (!device_state_change->have_quorum[which]) return true; } @@ -2621,12 +2633,22 @@ } } -static void notify_peers_lost_primary(struct drbd_connection *lost_peer) +void drbd_notify_peers_lost_primary(struct drbd_resource *resource) { - struct drbd_resource *resource = lost_peer->resource; - struct drbd_connection *connection; + struct drbd_connection *connection, *lost_peer; u64 im; + rcu_read_lock(); + for_each_connection_rcu(lost_peer, resource) { + if (test_and_clear_bit(NOTIFY_PEERS_LOST_PRIMARY, &lost_peer->flags)) { + rcu_read_unlock(); + goto found; + } + } + rcu_read_unlock(); + return; +found: + for_each_connection_ref(connection, im, resource) { if (connection == lost_peer) continue; @@ -2800,7 +2822,7 @@ struct drbd_device_state_change *device_state_change = &state_change->devices[n_device]; struct drbd_device *device = device_state_change->device; enum drbd_disk_state *disk_state = device_state_change->disk_state; - bool *susp_quorum = device_state_change->susp_quorum; + bool *have_quorum = device_state_change->have_quorum; bool effective_disk_size_determined = false; bool one_peer_disk_up_to_date[2] = { }; bool device_stable[2]; @@ -3038,9 +3060,13 @@ if (disk_state[OLD] < D_UP_TO_DATE && repl_state[OLD] >= L_SYNC_SOURCE && repl_state[NEW] == L_ESTABLISHED) send_new_state_to_all_peer_devices(state_change, n_device); - /* Outdated myself, or became D_UP_TO_DATE tell peers */ - if (disk_state[NEW] >= D_INCONSISTENT && disk_state[NEW] != disk_state[OLD] && - repl_state[OLD] >= L_ESTABLISHED && repl_state[NEW] >= L_ESTABLISHED) + /* Outdated myself, or became D_UP_TO_DATE tell peers + * Do not do it, when the local node was forced from R_SECONDARY to R_PRIMARY, + * because that is part of the 2-phase-commit and that is necessary to trigger + * the initial resync. */ + if ((disk_state[NEW] >= D_INCONSISTENT && disk_state[NEW] != disk_state[OLD] && + repl_state[OLD] >= L_ESTABLISHED && repl_state[NEW] >= L_ESTABLISHED) && + !(role[OLD] == R_SECONDARY && role[NEW] == R_PRIMARY)) send_state = true; /* Skipped resync with peer_device, tell others... */ @@ -3116,7 +3142,7 @@ drbd_uuid_new_current(device, false); } - if (device->susp_quorum[NEW] && got_contact_to_peer_data(peer_disk_state) && + if (!device->have_quorum[NEW] && got_contact_to_peer_data(peer_disk_state) && get_ldev(device)) { bool have_quorum = calc_quorum(device, NEW, NULL); if (have_quorum) { @@ -3126,7 +3152,7 @@ begin_state_change(resource, &irq_flags, CS_VERBOSE); _tl_restart(connection, RESEND); - __change_io_susp_quorum(device, false); + __change_have_quorum(device, true); end_state_change(resource, &irq_flags); } put_ldev(device); @@ -3237,7 +3263,7 @@ drbd_md_sync_if_dirty(device); - if (!susp_quorum[OLD] && susp_quorum[NEW]) + if (have_quorum[OLD] && !have_quorum[NEW]) drbd_khelper(device, NULL, "quorum-lost"); } @@ -3261,7 +3287,7 @@ if (peer_role[OLD] == R_PRIMARY && cstate[OLD] == C_CONNECTED && cstate[NEW] < C_CONNECTED) { /* A connection to a primary went down, notify other peers about that */ - notify_peers_lost_primary(connection); + set_bit(NOTIFY_PEERS_LOST_PRIMARY, &connection->flags); } } @@ -3275,6 +3301,8 @@ if (try_become_up_to_date) drbd_post_work(resource, TRY_BECOME_UP_TO_DATE); + else + drbd_notify_peers_lost_primary(resource); if (!still_connected) mod_timer_pending(&resource->twopc_timer, jiffies); @@ -3895,6 +3923,13 @@ if (have_peers && context->change_local_state_last) twopc_phase2(resource, context->vnr, rv >= SS_SUCCESS, &request, reach_immediately); + + if (context->flags & CS_INHIBIT_MD_IO) { + struct drbd_device *device = + container_of(context, struct change_disk_state_context, context)->device; + drbd_md_get_buffer(device, __func__); + } + end_remote_state_change(resource, &irq_flags, context->flags | CS_TWOPC); if (rv >= SS_SUCCESS) { change(context, PH_COMMIT); @@ -3909,6 +3944,13 @@ } else { abort_state_change(resource, &irq_flags); } + + if (context->flags & CS_INHIBIT_MD_IO) { + struct drbd_device *device = + container_of(context, struct change_disk_state_context, context)->device; + drbd_md_put_buffer(device); + } + if (have_peers && !context->change_local_state_last) twopc_phase2(resource, context->vnr, rv >= SS_SUCCESS, &request, reach_immediately); @@ -4164,7 +4206,7 @@ role_context->context.val.disk |= D_UP_TO_DATE; } } else if (role == R_SECONDARY) { - device->susp_quorum[NEW] = false; + device->have_quorum[NEW] = true; } } rcu_read_unlock(); @@ -4246,9 +4288,9 @@ connection->susp_fen[NEW] = value; } -void __change_io_susp_quorum(struct drbd_device *device, bool value) +void __change_have_quorum(struct drbd_device *device, bool value) { - device->susp_quorum[NEW] = value; + device->have_quorum[NEW] = value; } void __change_disk_state(struct drbd_device *device, enum drbd_disk_state disk_state) @@ -4299,8 +4341,8 @@ To avoid a race in receive_state, "clear" uuids while holding req_lock. I.e. atomic with the state change */ peer_device->uuids_received = false; - if (peer_device->disk_state[NOW] != D_UNKNOWN || - peer_device->repl_state[NOW] != L_OFF) + if (peer_device->disk_state[NOW] > D_DISKLESS && + peer_device->disk_state[NOW] != D_UNKNOWN) rv = true; } } @@ -4368,11 +4410,6 @@ return change_cluster_wide_state(do_change_from_consistent, &context); } -struct change_disk_state_context { - struct change_context context; - struct drbd_device *device; -}; - static bool do_change_disk_state(struct change_context *context, enum change_phase phase) { struct drbd_device *device = @@ -4418,6 +4455,10 @@ }, .device = device, }; + + if (disk_state == D_DETACHING && !(flags & CS_HARD)) + disk_state_context.context.flags |= CS_INHIBIT_MD_IO; + return change_cluster_wide_state(do_change_disk_state, &disk_state_context.context); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_state.h new/drbd-9.0.8+git.c8bc3670/drbd/drbd_state.h --- old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_state.h 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/drbd/drbd_state.h 2017-06-19 15:49:34.000000000 +0200 @@ -38,6 +38,10 @@ CS_TWOPC = 1 << 9, CS_IGN_OUTD_FAIL = 1 << 10, CS_DONT_RETRY = 1 << 11, /* Disable internal retry. Caller has a retry loop */ + + /* Make sure no meta data IO is in flight, by calling + * drbd_md_get_buffer(). Used for graceful detach. */ + CS_INHIBIT_MD_IO = 1 << 12, }; extern void drbd_resume_al(struct drbd_device *device); @@ -87,7 +91,7 @@ extern enum drbd_state_rv change_io_susp_user(struct drbd_resource *, bool, enum chg_state_flags); extern void __change_io_susp_no_data(struct drbd_resource *, bool); extern void __change_io_susp_fencing(struct drbd_connection *, bool); -extern void __change_io_susp_quorum(struct drbd_device *, bool); +extern void __change_have_quorum(struct drbd_device *, bool); extern void __change_disk_state(struct drbd_device *, enum drbd_disk_state); extern void __change_disk_states(struct drbd_resource *, enum drbd_disk_state); @@ -135,4 +139,5 @@ change_cluster_wide_device_size(struct drbd_device *, sector_t, uint64_t, enum dds_flags, struct resize_parms *); +extern void drbd_notify_peers_lost_primary(struct drbd_resource *resource); #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_state_change.h new/drbd-9.0.8+git.c8bc3670/drbd/drbd_state_change.h --- old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_state_change.h 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/drbd/drbd_state_change.h 2017-06-19 15:49:34.000000000 +0200 @@ -11,7 +11,7 @@ struct drbd_device_state_change { struct drbd_device *device; enum drbd_disk_state disk_state[2]; - bool susp_quorum[2]; + bool have_quorum[2]; bool have_ldev; }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_transport.c new/drbd-9.0.8+git.c8bc3670/drbd/drbd_transport.c --- old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_transport.c 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/drbd/drbd_transport.c 2017-06-19 15:49:34.000000000 +0200 @@ -206,6 +206,7 @@ err = init_listener(transport, addr, new_listener); if (err) { kfree(new_listener); + new_listener = NULL; if (err == -EADDRINUSE && ++tries < 3) { schedule_timeout_uninterruptible(HZ / 20); continue; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_transport_tcp.c new/drbd-9.0.8+git.c8bc3670/drbd/drbd_transport_tcp.c --- old/drbd-9.0.7rc2+git.36abd387/drbd/drbd_transport_tcp.c 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/drbd/drbd_transport_tcp.c 2017-06-19 15:49:34.000000000 +0200 @@ -317,6 +317,9 @@ void *buffer; int rv; + if (!socket) + return -ENOTCONN; + if (flags & CALLER_BUFFER) { buffer = *buf; rv = dtt_recv_short(socket, buffer, size, flags & ~CALLER_BUFFER); @@ -348,6 +351,9 @@ struct page *page; int err; + if (!socket) + return -ENOTCONN; + drbd_alloc_page_chain(transport, chain, DIV_ROUND_UP(size, PAGE_SIZE), GFP_TRY); page = chain->head; if (!page) @@ -767,7 +773,7 @@ struct dtt_listener *listener = container_of(drbd_listener, struct dtt_listener, listener); struct socket *s_listen; struct net_conf *nc; - const char *what; + const char *what = ""; rcu_read_lock(); nc = rcu_dereference(transport->net_conf); @@ -781,24 +787,24 @@ my_addr = *(struct sockaddr_storage *)addr; - what = "sock_create_kern"; err = sock_create_kern(&init_net, my_addr.ss_family, SOCK_STREAM, IPPROTO_TCP, &s_listen); if (err) { s_listen = NULL; + what = "sock_create_kern"; goto out; } s_listen->sk->sk_reuse = SK_CAN_REUSE; /* SO_REUSEADDR */ dtt_setbufsize(s_listen, sndbuf_size, rcvbuf_size); - what = "bind before listen"; - addr_len = addr->sa_family == AF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); err = s_listen->ops->bind(s_listen, (struct sockaddr *)&my_addr, addr_len); - if (err < 0) + if (err < 0) { + what = "bind before listen"; goto out; + } listener->s_listen = s_listen; write_lock_bh(&s_listen->sk->sk_callback_lock); @@ -807,10 +813,11 @@ s_listen->sk->sk_user_data = listener; write_unlock_bh(&s_listen->sk->sk_callback_lock); - what = "listen"; err = s_listen->ops->listen(s_listen, DRBD_PEERS_MAX * 2); - if (err < 0) + if (err < 0) { + what = "listen"; goto out; + } listener->listener.listen_addr = my_addr; listener->listener.destroy = dtt_destroy_listener; @@ -1090,9 +1097,11 @@ { struct drbd_tcp_transport *tcp_transport = container_of(transport, struct drbd_tcp_transport, transport); - struct socket *socket = tcp_transport->stream[stream]; + if (!socket) + return; + socket->sk->sk_rcvtimeo = timeout; } @@ -1100,9 +1109,11 @@ { struct drbd_tcp_transport *tcp_transport = container_of(transport, struct drbd_tcp_transport, transport); - struct socket *socket = tcp_transport->stream[stream]; + if (!socket) + return -ENOTCONN; + return socket->sk->sk_rcvtimeo; } @@ -1110,7 +1121,6 @@ { struct drbd_tcp_transport *tcp_transport = container_of(transport, struct drbd_tcp_transport, transport); - struct socket *socket = tcp_transport->stream[stream]; return socket && socket->sk; @@ -1118,8 +1128,13 @@ static void dtt_update_congested(struct drbd_tcp_transport *tcp_transport) { - struct sock *sock = tcp_transport->stream[DATA_STREAM]->sk; + struct socket *socket = tcp_transport->stream[DATA_STREAM]; + struct sock *sock; + + if (!socket) + return; + sock = socket->sk; if (sock->sk_wmem_queued > sock->sk_sndbuf * 4 / 5) set_bit(NET_CONGESTED, &tcp_transport->transport.flags); } @@ -1130,11 +1145,13 @@ struct drbd_tcp_transport *tcp_transport = container_of(transport, struct drbd_tcp_transport, transport); struct socket *socket = tcp_transport->stream[stream]; - mm_segment_t oldfs = get_fs(); int len = size; int err = -EIO; + if (!socket) + return -ENOTCONN; + msg_flags |= MSG_NOSIGNAL; dtt_update_congested(tcp_transport); set_fs(KERNEL_DS); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd/linux/drbd_config.h new/drbd-9.0.8+git.c8bc3670/drbd/linux/drbd_config.h --- old/drbd-9.0.7rc2+git.36abd387/drbd/linux/drbd_config.h 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/drbd/linux/drbd_config.h 2017-06-19 15:49:34.000000000 +0200 @@ -32,7 +32,7 @@ /* End of external module for 2.6.33 stuff */ -#define REL_VERSION "9.0.7-1" +#define REL_VERSION "9.0.8-1" #define PRO_VERSION_MIN 86 #define PRO_VERSION_MAX 112 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd-headers/linux/drbd.h new/drbd-9.0.8+git.c8bc3670/drbd-headers/linux/drbd.h --- old/drbd-9.0.7rc2+git.36abd387/drbd-headers/linux/drbd.h 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/drbd-headers/linux/drbd.h 2017-06-19 15:49:34.000000000 +0200 @@ -88,6 +88,11 @@ OND_SUSPEND_IO }; +enum drbd_on_no_quorum { + ONQ_IO_ERROR = OND_IO_ERROR, + ONQ_SUSPEND_IO = OND_SUSPEND_IO +}; + enum drbd_on_congestion { OC_BLOCK, OC_PULL_AHEAD, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd-headers/linux/drbd_genl.h new/drbd-9.0.8+git.c8bc3670/drbd-headers/linux/drbd_genl.h --- old/drbd-9.0.7rc2+git.36abd387/drbd-headers/linux/drbd_genl.h 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/drbd-headers/linux/drbd_genl.h 2017-06-19 15:49:34.000000000 +0200 @@ -143,6 +143,7 @@ __u32_field_def(9, 0 /* OPTIONAL */, auto_promote_timeout, DRBD_AUTO_PROMOTE_TIMEOUT_DEF) __u32_field_def(10, 0 /* OPTIONAL */, nr_requests, DRBD_NR_REQUESTS_DEF) __s32_field_def(11, 0 /* OPTIONAL */, quorum, DRBD_QUORUM_DEF) + __u32_field_def(12, 0 /* OPTIONAL */, on_no_quorum, DRBD_ON_NO_QUORUM_DEF) ) GENL_struct(DRBD_NLA_NET_CONF, 5, net_conf, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd-headers/linux/drbd_limits.h new/drbd-9.0.8+git.c8bc3670/drbd-headers/linux/drbd_limits.h --- old/drbd-9.0.7rc2+git.36abd387/drbd-headers/linux/drbd_limits.h 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/drbd-headers/linux/drbd_limits.h 2017-06-19 15:49:34.000000000 +0200 @@ -304,4 +304,7 @@ #define DRBD_QUORUM_DEF QOU_OFF /* kernel min/max includes symbolic values */ #define DRBD_QUORUM_SCALE '1' /* nodes */ +/* By default freeze IO, if set error all IOs as quick as possible */ +#define DRBD_ON_NO_QUORUM_DEF ONQ_SUSPEND_IO + #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/drbd-9.0.7rc2+git.36abd387/drbd-kernel.spec new/drbd-9.0.8+git.c8bc3670/drbd-kernel.spec --- old/drbd-9.0.7rc2+git.36abd387/drbd-kernel.spec 2017-05-22 14:34:52.000000000 +0200 +++ new/drbd-9.0.8+git.c8bc3670/drbd-kernel.spec 2017-06-19 15:49:34.000000000 +0200 @@ -1,10 +1,10 @@ Name: drbd-kernel Summary: Kernel driver for DRBD -Version: 9.0.7 +Version: 9.0.8 Release: 1%{?dist} # always require a suitable userland -Requires: drbd-utils >= 8.9.11 +Requires: drbd-utils >= 9.0.0 %global tarball_version %(echo "%{version}-%{?release}" | sed -e "s,%{?dist}$,,") Source: http://oss.linbit.com/drbd/drbd-%{tarball_version}.tar.gz @@ -103,6 +103,9 @@ rm -rf %{buildroot} %changelog +* Mon Jun 19 2017 Philipp Reisner <p...@linbit.com> - 9.0.8-1 +- New upstream release. + * Fri Mar 31 2017 Philipp Reisner <p...@linbit.com> - 9.0.7-1 - New upstream release. ++++++ drbd_git_revision ++++++ --- /var/tmp/diff_new_pack.Y5oLyz/_old 2017-06-23 09:18:46.578946338 +0200 +++ /var/tmp/diff_new_pack.Y5oLyz/_new 2017-06-23 09:18:46.578946338 +0200 @@ -1 +1 @@ -GIT-hash: 36abd387b6e4341a58117711b2e95777c1dad8ab +GIT-hash: c8bc36701c7c7ffc2c208f620c6d89e4ec265704