18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci drbd.c 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci This file is part of DRBD by Philipp Reisner and Lars Ellenberg. 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci Copyright (C) 2001-2008, LINBIT Information Technologies GmbH. 88c2ecf20Sopenharmony_ci Copyright (C) 1999-2008, Philipp Reisner <philipp.reisner@linbit.com>. 98c2ecf20Sopenharmony_ci Copyright (C) 2002-2008, Lars Ellenberg <lars.ellenberg@linbit.com>. 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci Thanks to Carter Burden, Bart Grantham and Gennadiy Nerubayev 128c2ecf20Sopenharmony_ci from Logicworks, Inc. for making SDP replication support possible. 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 218c2ecf20Sopenharmony_ci#include <linux/drbd.h> 228c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 238c2ecf20Sopenharmony_ci#include <asm/types.h> 248c2ecf20Sopenharmony_ci#include <net/sock.h> 258c2ecf20Sopenharmony_ci#include <linux/ctype.h> 268c2ecf20Sopenharmony_ci#include <linux/mutex.h> 278c2ecf20Sopenharmony_ci#include <linux/fs.h> 288c2ecf20Sopenharmony_ci#include <linux/file.h> 298c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 308c2ecf20Sopenharmony_ci#include <linux/init.h> 318c2ecf20Sopenharmony_ci#include <linux/mm.h> 328c2ecf20Sopenharmony_ci#include <linux/memcontrol.h> 338c2ecf20Sopenharmony_ci#include <linux/mm_inline.h> 348c2ecf20Sopenharmony_ci#include <linux/slab.h> 358c2ecf20Sopenharmony_ci#include <linux/random.h> 368c2ecf20Sopenharmony_ci#include <linux/reboot.h> 378c2ecf20Sopenharmony_ci#include <linux/notifier.h> 388c2ecf20Sopenharmony_ci#include <linux/kthread.h> 398c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 408c2ecf20Sopenharmony_ci#define __KERNEL_SYSCALLS__ 418c2ecf20Sopenharmony_ci#include <linux/unistd.h> 428c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 438c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#include <linux/drbd_limits.h> 468c2ecf20Sopenharmony_ci#include "drbd_int.h" 478c2ecf20Sopenharmony_ci#include "drbd_protocol.h" 488c2ecf20Sopenharmony_ci#include "drbd_req.h" /* only for _req_mod in tl_release and tl_clear */ 498c2ecf20Sopenharmony_ci#include "drbd_vli.h" 508c2ecf20Sopenharmony_ci#include "drbd_debugfs.h" 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(drbd_main_mutex); 538c2ecf20Sopenharmony_cistatic int drbd_open(struct block_device *bdev, fmode_t mode); 548c2ecf20Sopenharmony_cistatic void drbd_release(struct gendisk *gd, fmode_t mode); 558c2ecf20Sopenharmony_cistatic void md_sync_timer_fn(struct timer_list *t); 568c2ecf20Sopenharmony_cistatic int w_bitmap_io(struct drbd_work *w, int unused); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ciMODULE_AUTHOR("Philipp Reisner <phil@linbit.com>, " 598c2ecf20Sopenharmony_ci "Lars Ellenberg <lars@linbit.com>"); 608c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("drbd - Distributed Replicated Block Device v" REL_VERSION); 618c2ecf20Sopenharmony_ciMODULE_VERSION(REL_VERSION); 628c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 638c2ecf20Sopenharmony_ciMODULE_PARM_DESC(minor_count, "Approximate number of drbd devices (" 648c2ecf20Sopenharmony_ci __stringify(DRBD_MINOR_COUNT_MIN) "-" __stringify(DRBD_MINOR_COUNT_MAX) ")"); 658c2ecf20Sopenharmony_ciMODULE_ALIAS_BLOCKDEV_MAJOR(DRBD_MAJOR); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 688c2ecf20Sopenharmony_ci/* thanks to these macros, if compiled into the kernel (not-module), 698c2ecf20Sopenharmony_ci * these become boot parameters (e.g., drbd.minor_count) */ 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#ifdef CONFIG_DRBD_FAULT_INJECTION 728c2ecf20Sopenharmony_ciint drbd_enable_faults; 738c2ecf20Sopenharmony_ciint drbd_fault_rate; 748c2ecf20Sopenharmony_cistatic int drbd_fault_count; 758c2ecf20Sopenharmony_cistatic int drbd_fault_devs; 768c2ecf20Sopenharmony_ci/* bitmap of enabled faults */ 778c2ecf20Sopenharmony_cimodule_param_named(enable_faults, drbd_enable_faults, int, 0664); 788c2ecf20Sopenharmony_ci/* fault rate % value - applies to all enabled faults */ 798c2ecf20Sopenharmony_cimodule_param_named(fault_rate, drbd_fault_rate, int, 0664); 808c2ecf20Sopenharmony_ci/* count of faults inserted */ 818c2ecf20Sopenharmony_cimodule_param_named(fault_count, drbd_fault_count, int, 0664); 828c2ecf20Sopenharmony_ci/* bitmap of devices to insert faults on */ 838c2ecf20Sopenharmony_cimodule_param_named(fault_devs, drbd_fault_devs, int, 0644); 848c2ecf20Sopenharmony_ci#endif 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/* module parameters we can keep static */ 878c2ecf20Sopenharmony_cistatic bool drbd_allow_oos; /* allow_open_on_secondary */ 888c2ecf20Sopenharmony_cistatic bool drbd_disable_sendpage; 898c2ecf20Sopenharmony_ciMODULE_PARM_DESC(allow_oos, "DONT USE!"); 908c2ecf20Sopenharmony_cimodule_param_named(allow_oos, drbd_allow_oos, bool, 0); 918c2ecf20Sopenharmony_cimodule_param_named(disable_sendpage, drbd_disable_sendpage, bool, 0644); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* module parameters we share */ 948c2ecf20Sopenharmony_ciint drbd_proc_details; /* Detail level in proc drbd*/ 958c2ecf20Sopenharmony_cimodule_param_named(proc_details, drbd_proc_details, int, 0644); 968c2ecf20Sopenharmony_ci/* module parameters shared with defaults */ 978c2ecf20Sopenharmony_ciunsigned int drbd_minor_count = DRBD_MINOR_COUNT_DEF; 988c2ecf20Sopenharmony_ci/* Module parameter for setting the user mode helper program 998c2ecf20Sopenharmony_ci * to run. Default is /sbin/drbdadm */ 1008c2ecf20Sopenharmony_cichar drbd_usermode_helper[80] = "/sbin/drbdadm"; 1018c2ecf20Sopenharmony_cimodule_param_named(minor_count, drbd_minor_count, uint, 0444); 1028c2ecf20Sopenharmony_cimodule_param_string(usermode_helper, drbd_usermode_helper, sizeof(drbd_usermode_helper), 0644); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* in 2.6.x, our device mapping and config info contains our virtual gendisks 1058c2ecf20Sopenharmony_ci * as member "struct gendisk *vdisk;" 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_cistruct idr drbd_devices; 1088c2ecf20Sopenharmony_cistruct list_head drbd_resources; 1098c2ecf20Sopenharmony_cistruct mutex resources_mutex; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistruct kmem_cache *drbd_request_cache; 1128c2ecf20Sopenharmony_cistruct kmem_cache *drbd_ee_cache; /* peer requests */ 1138c2ecf20Sopenharmony_cistruct kmem_cache *drbd_bm_ext_cache; /* bitmap extents */ 1148c2ecf20Sopenharmony_cistruct kmem_cache *drbd_al_ext_cache; /* activity log extents */ 1158c2ecf20Sopenharmony_cimempool_t drbd_request_mempool; 1168c2ecf20Sopenharmony_cimempool_t drbd_ee_mempool; 1178c2ecf20Sopenharmony_cimempool_t drbd_md_io_page_pool; 1188c2ecf20Sopenharmony_cistruct bio_set drbd_md_io_bio_set; 1198c2ecf20Sopenharmony_cistruct bio_set drbd_io_bio_set; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/* I do not use a standard mempool, because: 1228c2ecf20Sopenharmony_ci 1) I want to hand out the pre-allocated objects first. 1238c2ecf20Sopenharmony_ci 2) I want to be able to interrupt sleeping allocation with a signal. 1248c2ecf20Sopenharmony_ci Note: This is a single linked list, the next pointer is the private 1258c2ecf20Sopenharmony_ci member of struct page. 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_cistruct page *drbd_pp_pool; 1288c2ecf20Sopenharmony_cispinlock_t drbd_pp_lock; 1298c2ecf20Sopenharmony_ciint drbd_pp_vacant; 1308c2ecf20Sopenharmony_ciwait_queue_head_t drbd_pp_wait; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ciDEFINE_RATELIMIT_STATE(drbd_ratelimit_state, 5 * HZ, 5); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic const struct block_device_operations drbd_ops = { 1358c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1368c2ecf20Sopenharmony_ci .submit_bio = drbd_submit_bio, 1378c2ecf20Sopenharmony_ci .open = drbd_open, 1388c2ecf20Sopenharmony_ci .release = drbd_release, 1398c2ecf20Sopenharmony_ci}; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistruct bio *bio_alloc_drbd(gfp_t gfp_mask) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci struct bio *bio; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (!bioset_initialized(&drbd_md_io_bio_set)) 1468c2ecf20Sopenharmony_ci return bio_alloc(gfp_mask, 1); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci bio = bio_alloc_bioset(gfp_mask, 1, &drbd_md_io_bio_set); 1498c2ecf20Sopenharmony_ci if (!bio) 1508c2ecf20Sopenharmony_ci return NULL; 1518c2ecf20Sopenharmony_ci return bio; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci#ifdef __CHECKER__ 1558c2ecf20Sopenharmony_ci/* When checking with sparse, and this is an inline function, sparse will 1568c2ecf20Sopenharmony_ci give tons of false positives. When this is a real functions sparse works. 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_ciint _get_ldev_if_state(struct drbd_device *device, enum drbd_disk_state mins) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci int io_allowed; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci atomic_inc(&device->local_cnt); 1638c2ecf20Sopenharmony_ci io_allowed = (device->state.disk >= mins); 1648c2ecf20Sopenharmony_ci if (!io_allowed) { 1658c2ecf20Sopenharmony_ci if (atomic_dec_and_test(&device->local_cnt)) 1668c2ecf20Sopenharmony_ci wake_up(&device->misc_wait); 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci return io_allowed; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci#endif 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/** 1748c2ecf20Sopenharmony_ci * tl_release() - mark as BARRIER_ACKED all requests in the corresponding transfer log epoch 1758c2ecf20Sopenharmony_ci * @connection: DRBD connection. 1768c2ecf20Sopenharmony_ci * @barrier_nr: Expected identifier of the DRBD write barrier packet. 1778c2ecf20Sopenharmony_ci * @set_size: Expected number of requests before that barrier. 1788c2ecf20Sopenharmony_ci * 1798c2ecf20Sopenharmony_ci * In case the passed barrier_nr or set_size does not match the oldest 1808c2ecf20Sopenharmony_ci * epoch of not yet barrier-acked requests, this function will cause a 1818c2ecf20Sopenharmony_ci * termination of the connection. 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_civoid tl_release(struct drbd_connection *connection, unsigned int barrier_nr, 1848c2ecf20Sopenharmony_ci unsigned int set_size) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci struct drbd_request *r; 1878c2ecf20Sopenharmony_ci struct drbd_request *req = NULL, *tmp = NULL; 1888c2ecf20Sopenharmony_ci int expect_epoch = 0; 1898c2ecf20Sopenharmony_ci int expect_size = 0; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci spin_lock_irq(&connection->resource->req_lock); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* find oldest not yet barrier-acked write request, 1948c2ecf20Sopenharmony_ci * count writes in its epoch. */ 1958c2ecf20Sopenharmony_ci list_for_each_entry(r, &connection->transfer_log, tl_requests) { 1968c2ecf20Sopenharmony_ci const unsigned s = r->rq_state; 1978c2ecf20Sopenharmony_ci if (!req) { 1988c2ecf20Sopenharmony_ci if (!(s & RQ_WRITE)) 1998c2ecf20Sopenharmony_ci continue; 2008c2ecf20Sopenharmony_ci if (!(s & RQ_NET_MASK)) 2018c2ecf20Sopenharmony_ci continue; 2028c2ecf20Sopenharmony_ci if (s & RQ_NET_DONE) 2038c2ecf20Sopenharmony_ci continue; 2048c2ecf20Sopenharmony_ci req = r; 2058c2ecf20Sopenharmony_ci expect_epoch = req->epoch; 2068c2ecf20Sopenharmony_ci expect_size ++; 2078c2ecf20Sopenharmony_ci } else { 2088c2ecf20Sopenharmony_ci if (r->epoch != expect_epoch) 2098c2ecf20Sopenharmony_ci break; 2108c2ecf20Sopenharmony_ci if (!(s & RQ_WRITE)) 2118c2ecf20Sopenharmony_ci continue; 2128c2ecf20Sopenharmony_ci /* if (s & RQ_DONE): not expected */ 2138c2ecf20Sopenharmony_ci /* if (!(s & RQ_NET_MASK)): not expected */ 2148c2ecf20Sopenharmony_ci expect_size++; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci /* first some paranoia code */ 2198c2ecf20Sopenharmony_ci if (req == NULL) { 2208c2ecf20Sopenharmony_ci drbd_err(connection, "BAD! BarrierAck #%u received, but no epoch in tl!?\n", 2218c2ecf20Sopenharmony_ci barrier_nr); 2228c2ecf20Sopenharmony_ci goto bail; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci if (expect_epoch != barrier_nr) { 2258c2ecf20Sopenharmony_ci drbd_err(connection, "BAD! BarrierAck #%u received, expected #%u!\n", 2268c2ecf20Sopenharmony_ci barrier_nr, expect_epoch); 2278c2ecf20Sopenharmony_ci goto bail; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (expect_size != set_size) { 2318c2ecf20Sopenharmony_ci drbd_err(connection, "BAD! BarrierAck #%u received with n_writes=%u, expected n_writes=%u!\n", 2328c2ecf20Sopenharmony_ci barrier_nr, set_size, expect_size); 2338c2ecf20Sopenharmony_ci goto bail; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* Clean up list of requests processed during current epoch. */ 2378c2ecf20Sopenharmony_ci /* this extra list walk restart is paranoia, 2388c2ecf20Sopenharmony_ci * to catch requests being barrier-acked "unexpectedly". 2398c2ecf20Sopenharmony_ci * It usually should find the same req again, or some READ preceding it. */ 2408c2ecf20Sopenharmony_ci list_for_each_entry(req, &connection->transfer_log, tl_requests) 2418c2ecf20Sopenharmony_ci if (req->epoch == expect_epoch) { 2428c2ecf20Sopenharmony_ci tmp = req; 2438c2ecf20Sopenharmony_ci break; 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci req = list_prepare_entry(tmp, &connection->transfer_log, tl_requests); 2468c2ecf20Sopenharmony_ci list_for_each_entry_safe_from(req, r, &connection->transfer_log, tl_requests) { 2478c2ecf20Sopenharmony_ci if (req->epoch != expect_epoch) 2488c2ecf20Sopenharmony_ci break; 2498c2ecf20Sopenharmony_ci _req_mod(req, BARRIER_ACKED); 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci spin_unlock_irq(&connection->resource->req_lock); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci return; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cibail: 2568c2ecf20Sopenharmony_ci spin_unlock_irq(&connection->resource->req_lock); 2578c2ecf20Sopenharmony_ci conn_request_state(connection, NS(conn, C_PROTOCOL_ERROR), CS_HARD); 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci/** 2628c2ecf20Sopenharmony_ci * _tl_restart() - Walks the transfer log, and applies an action to all requests 2638c2ecf20Sopenharmony_ci * @connection: DRBD connection to operate on. 2648c2ecf20Sopenharmony_ci * @what: The action/event to perform with all request objects 2658c2ecf20Sopenharmony_ci * 2668c2ecf20Sopenharmony_ci * @what might be one of CONNECTION_LOST_WHILE_PENDING, RESEND, FAIL_FROZEN_DISK_IO, 2678c2ecf20Sopenharmony_ci * RESTART_FROZEN_DISK_IO. 2688c2ecf20Sopenharmony_ci */ 2698c2ecf20Sopenharmony_ci/* must hold resource->req_lock */ 2708c2ecf20Sopenharmony_civoid _tl_restart(struct drbd_connection *connection, enum drbd_req_event what) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci struct drbd_request *req, *r; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci list_for_each_entry_safe(req, r, &connection->transfer_log, tl_requests) 2758c2ecf20Sopenharmony_ci _req_mod(req, what); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_civoid tl_restart(struct drbd_connection *connection, enum drbd_req_event what) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci spin_lock_irq(&connection->resource->req_lock); 2818c2ecf20Sopenharmony_ci _tl_restart(connection, what); 2828c2ecf20Sopenharmony_ci spin_unlock_irq(&connection->resource->req_lock); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci/** 2868c2ecf20Sopenharmony_ci * tl_clear() - Clears all requests and &struct drbd_tl_epoch objects out of the TL 2878c2ecf20Sopenharmony_ci * @device: DRBD device. 2888c2ecf20Sopenharmony_ci * 2898c2ecf20Sopenharmony_ci * This is called after the connection to the peer was lost. The storage covered 2908c2ecf20Sopenharmony_ci * by the requests on the transfer gets marked as our of sync. Called from the 2918c2ecf20Sopenharmony_ci * receiver thread and the worker thread. 2928c2ecf20Sopenharmony_ci */ 2938c2ecf20Sopenharmony_civoid tl_clear(struct drbd_connection *connection) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci tl_restart(connection, CONNECTION_LOST_WHILE_PENDING); 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci/** 2998c2ecf20Sopenharmony_ci * tl_abort_disk_io() - Abort disk I/O for all requests for a certain device in the TL 3008c2ecf20Sopenharmony_ci * @device: DRBD device. 3018c2ecf20Sopenharmony_ci */ 3028c2ecf20Sopenharmony_civoid tl_abort_disk_io(struct drbd_device *device) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct drbd_connection *connection = first_peer_device(device)->connection; 3058c2ecf20Sopenharmony_ci struct drbd_request *req, *r; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci spin_lock_irq(&connection->resource->req_lock); 3088c2ecf20Sopenharmony_ci list_for_each_entry_safe(req, r, &connection->transfer_log, tl_requests) { 3098c2ecf20Sopenharmony_ci if (!(req->rq_state & RQ_LOCAL_PENDING)) 3108c2ecf20Sopenharmony_ci continue; 3118c2ecf20Sopenharmony_ci if (req->device != device) 3128c2ecf20Sopenharmony_ci continue; 3138c2ecf20Sopenharmony_ci _req_mod(req, ABORT_DISK_IO); 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci spin_unlock_irq(&connection->resource->req_lock); 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic int drbd_thread_setup(void *arg) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct drbd_thread *thi = (struct drbd_thread *) arg; 3218c2ecf20Sopenharmony_ci struct drbd_resource *resource = thi->resource; 3228c2ecf20Sopenharmony_ci unsigned long flags; 3238c2ecf20Sopenharmony_ci int retval; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci snprintf(current->comm, sizeof(current->comm), "drbd_%c_%s", 3268c2ecf20Sopenharmony_ci thi->name[0], 3278c2ecf20Sopenharmony_ci resource->name); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci allow_kernel_signal(DRBD_SIGKILL); 3308c2ecf20Sopenharmony_ci allow_kernel_signal(SIGXCPU); 3318c2ecf20Sopenharmony_cirestart: 3328c2ecf20Sopenharmony_ci retval = thi->function(thi); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci spin_lock_irqsave(&thi->t_lock, flags); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* if the receiver has been "EXITING", the last thing it did 3378c2ecf20Sopenharmony_ci * was set the conn state to "StandAlone", 3388c2ecf20Sopenharmony_ci * if now a re-connect request comes in, conn state goes C_UNCONNECTED, 3398c2ecf20Sopenharmony_ci * and receiver thread will be "started". 3408c2ecf20Sopenharmony_ci * drbd_thread_start needs to set "RESTARTING" in that case. 3418c2ecf20Sopenharmony_ci * t_state check and assignment needs to be within the same spinlock, 3428c2ecf20Sopenharmony_ci * so either thread_start sees EXITING, and can remap to RESTARTING, 3438c2ecf20Sopenharmony_ci * or thread_start see NONE, and can proceed as normal. 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci if (thi->t_state == RESTARTING) { 3478c2ecf20Sopenharmony_ci drbd_info(resource, "Restarting %s thread\n", thi->name); 3488c2ecf20Sopenharmony_ci thi->t_state = RUNNING; 3498c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&thi->t_lock, flags); 3508c2ecf20Sopenharmony_ci goto restart; 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci thi->task = NULL; 3548c2ecf20Sopenharmony_ci thi->t_state = NONE; 3558c2ecf20Sopenharmony_ci smp_mb(); 3568c2ecf20Sopenharmony_ci complete_all(&thi->stop); 3578c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&thi->t_lock, flags); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci drbd_info(resource, "Terminating %s\n", current->comm); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* Release mod reference taken when thread was started */ 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (thi->connection) 3648c2ecf20Sopenharmony_ci kref_put(&thi->connection->kref, drbd_destroy_connection); 3658c2ecf20Sopenharmony_ci kref_put(&resource->kref, drbd_destroy_resource); 3668c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 3678c2ecf20Sopenharmony_ci return retval; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic void drbd_thread_init(struct drbd_resource *resource, struct drbd_thread *thi, 3718c2ecf20Sopenharmony_ci int (*func) (struct drbd_thread *), const char *name) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci spin_lock_init(&thi->t_lock); 3748c2ecf20Sopenharmony_ci thi->task = NULL; 3758c2ecf20Sopenharmony_ci thi->t_state = NONE; 3768c2ecf20Sopenharmony_ci thi->function = func; 3778c2ecf20Sopenharmony_ci thi->resource = resource; 3788c2ecf20Sopenharmony_ci thi->connection = NULL; 3798c2ecf20Sopenharmony_ci thi->name = name; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ciint drbd_thread_start(struct drbd_thread *thi) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci struct drbd_resource *resource = thi->resource; 3858c2ecf20Sopenharmony_ci struct task_struct *nt; 3868c2ecf20Sopenharmony_ci unsigned long flags; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* is used from state engine doing drbd_thread_stop_nowait, 3898c2ecf20Sopenharmony_ci * while holding the req lock irqsave */ 3908c2ecf20Sopenharmony_ci spin_lock_irqsave(&thi->t_lock, flags); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci switch (thi->t_state) { 3938c2ecf20Sopenharmony_ci case NONE: 3948c2ecf20Sopenharmony_ci drbd_info(resource, "Starting %s thread (from %s [%d])\n", 3958c2ecf20Sopenharmony_ci thi->name, current->comm, current->pid); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* Get ref on module for thread - this is released when thread exits */ 3988c2ecf20Sopenharmony_ci if (!try_module_get(THIS_MODULE)) { 3998c2ecf20Sopenharmony_ci drbd_err(resource, "Failed to get module reference in drbd_thread_start\n"); 4008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&thi->t_lock, flags); 4018c2ecf20Sopenharmony_ci return false; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci kref_get(&resource->kref); 4058c2ecf20Sopenharmony_ci if (thi->connection) 4068c2ecf20Sopenharmony_ci kref_get(&thi->connection->kref); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci init_completion(&thi->stop); 4098c2ecf20Sopenharmony_ci thi->reset_cpu_mask = 1; 4108c2ecf20Sopenharmony_ci thi->t_state = RUNNING; 4118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&thi->t_lock, flags); 4128c2ecf20Sopenharmony_ci flush_signals(current); /* otherw. may get -ERESTARTNOINTR */ 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci nt = kthread_create(drbd_thread_setup, (void *) thi, 4158c2ecf20Sopenharmony_ci "drbd_%c_%s", thi->name[0], thi->resource->name); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (IS_ERR(nt)) { 4188c2ecf20Sopenharmony_ci drbd_err(resource, "Couldn't start thread\n"); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci if (thi->connection) 4218c2ecf20Sopenharmony_ci kref_put(&thi->connection->kref, drbd_destroy_connection); 4228c2ecf20Sopenharmony_ci kref_put(&resource->kref, drbd_destroy_resource); 4238c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 4248c2ecf20Sopenharmony_ci return false; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci spin_lock_irqsave(&thi->t_lock, flags); 4278c2ecf20Sopenharmony_ci thi->task = nt; 4288c2ecf20Sopenharmony_ci thi->t_state = RUNNING; 4298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&thi->t_lock, flags); 4308c2ecf20Sopenharmony_ci wake_up_process(nt); 4318c2ecf20Sopenharmony_ci break; 4328c2ecf20Sopenharmony_ci case EXITING: 4338c2ecf20Sopenharmony_ci thi->t_state = RESTARTING; 4348c2ecf20Sopenharmony_ci drbd_info(resource, "Restarting %s thread (from %s [%d])\n", 4358c2ecf20Sopenharmony_ci thi->name, current->comm, current->pid); 4368c2ecf20Sopenharmony_ci fallthrough; 4378c2ecf20Sopenharmony_ci case RUNNING: 4388c2ecf20Sopenharmony_ci case RESTARTING: 4398c2ecf20Sopenharmony_ci default: 4408c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&thi->t_lock, flags); 4418c2ecf20Sopenharmony_ci break; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci return true; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_civoid _drbd_thread_stop(struct drbd_thread *thi, int restart, int wait) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci unsigned long flags; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci enum drbd_thread_state ns = restart ? RESTARTING : EXITING; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci /* may be called from state engine, holding the req lock irqsave */ 4558c2ecf20Sopenharmony_ci spin_lock_irqsave(&thi->t_lock, flags); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (thi->t_state == NONE) { 4588c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&thi->t_lock, flags); 4598c2ecf20Sopenharmony_ci if (restart) 4608c2ecf20Sopenharmony_ci drbd_thread_start(thi); 4618c2ecf20Sopenharmony_ci return; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (thi->t_state != ns) { 4658c2ecf20Sopenharmony_ci if (thi->task == NULL) { 4668c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&thi->t_lock, flags); 4678c2ecf20Sopenharmony_ci return; 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci thi->t_state = ns; 4718c2ecf20Sopenharmony_ci smp_mb(); 4728c2ecf20Sopenharmony_ci init_completion(&thi->stop); 4738c2ecf20Sopenharmony_ci if (thi->task != current) 4748c2ecf20Sopenharmony_ci send_sig(DRBD_SIGKILL, thi->task, 1); 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&thi->t_lock, flags); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci if (wait) 4808c2ecf20Sopenharmony_ci wait_for_completion(&thi->stop); 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ciint conn_lowest_minor(struct drbd_connection *connection) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 4868c2ecf20Sopenharmony_ci int vnr = 0, minor = -1; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci rcu_read_lock(); 4898c2ecf20Sopenharmony_ci peer_device = idr_get_next(&connection->peer_devices, &vnr); 4908c2ecf20Sopenharmony_ci if (peer_device) 4918c2ecf20Sopenharmony_ci minor = device_to_minor(peer_device->device); 4928c2ecf20Sopenharmony_ci rcu_read_unlock(); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci return minor; 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP 4988c2ecf20Sopenharmony_ci/** 4998c2ecf20Sopenharmony_ci * drbd_calc_cpu_mask() - Generate CPU masks, spread over all CPUs 5008c2ecf20Sopenharmony_ci * 5018c2ecf20Sopenharmony_ci * Forces all threads of a resource onto the same CPU. This is beneficial for 5028c2ecf20Sopenharmony_ci * DRBD's performance. May be overwritten by user's configuration. 5038c2ecf20Sopenharmony_ci */ 5048c2ecf20Sopenharmony_cistatic void drbd_calc_cpu_mask(cpumask_var_t *cpu_mask) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci unsigned int *resources_per_cpu, min_index = ~0; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci resources_per_cpu = kcalloc(nr_cpu_ids, sizeof(*resources_per_cpu), 5098c2ecf20Sopenharmony_ci GFP_KERNEL); 5108c2ecf20Sopenharmony_ci if (resources_per_cpu) { 5118c2ecf20Sopenharmony_ci struct drbd_resource *resource; 5128c2ecf20Sopenharmony_ci unsigned int cpu, min = ~0; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci rcu_read_lock(); 5158c2ecf20Sopenharmony_ci for_each_resource_rcu(resource, &drbd_resources) { 5168c2ecf20Sopenharmony_ci for_each_cpu(cpu, resource->cpu_mask) 5178c2ecf20Sopenharmony_ci resources_per_cpu[cpu]++; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci rcu_read_unlock(); 5208c2ecf20Sopenharmony_ci for_each_online_cpu(cpu) { 5218c2ecf20Sopenharmony_ci if (resources_per_cpu[cpu] < min) { 5228c2ecf20Sopenharmony_ci min = resources_per_cpu[cpu]; 5238c2ecf20Sopenharmony_ci min_index = cpu; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci kfree(resources_per_cpu); 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci if (min_index == ~0) { 5298c2ecf20Sopenharmony_ci cpumask_setall(*cpu_mask); 5308c2ecf20Sopenharmony_ci return; 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci cpumask_set_cpu(min_index, *cpu_mask); 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci/** 5368c2ecf20Sopenharmony_ci * drbd_thread_current_set_cpu() - modifies the cpu mask of the _current_ thread 5378c2ecf20Sopenharmony_ci * @device: DRBD device. 5388c2ecf20Sopenharmony_ci * @thi: drbd_thread object 5398c2ecf20Sopenharmony_ci * 5408c2ecf20Sopenharmony_ci * call in the "main loop" of _all_ threads, no need for any mutex, current won't die 5418c2ecf20Sopenharmony_ci * prematurely. 5428c2ecf20Sopenharmony_ci */ 5438c2ecf20Sopenharmony_civoid drbd_thread_current_set_cpu(struct drbd_thread *thi) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci struct drbd_resource *resource = thi->resource; 5468c2ecf20Sopenharmony_ci struct task_struct *p = current; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if (!thi->reset_cpu_mask) 5498c2ecf20Sopenharmony_ci return; 5508c2ecf20Sopenharmony_ci thi->reset_cpu_mask = 0; 5518c2ecf20Sopenharmony_ci set_cpus_allowed_ptr(p, resource->cpu_mask); 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci#else 5548c2ecf20Sopenharmony_ci#define drbd_calc_cpu_mask(A) ({}) 5558c2ecf20Sopenharmony_ci#endif 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci/** 5588c2ecf20Sopenharmony_ci * drbd_header_size - size of a packet header 5598c2ecf20Sopenharmony_ci * 5608c2ecf20Sopenharmony_ci * The header size is a multiple of 8, so any payload following the header is 5618c2ecf20Sopenharmony_ci * word aligned on 64-bit architectures. (The bitmap send and receive code 5628c2ecf20Sopenharmony_ci * relies on this.) 5638c2ecf20Sopenharmony_ci */ 5648c2ecf20Sopenharmony_ciunsigned int drbd_header_size(struct drbd_connection *connection) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci if (connection->agreed_pro_version >= 100) { 5678c2ecf20Sopenharmony_ci BUILD_BUG_ON(!IS_ALIGNED(sizeof(struct p_header100), 8)); 5688c2ecf20Sopenharmony_ci return sizeof(struct p_header100); 5698c2ecf20Sopenharmony_ci } else { 5708c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct p_header80) != 5718c2ecf20Sopenharmony_ci sizeof(struct p_header95)); 5728c2ecf20Sopenharmony_ci BUILD_BUG_ON(!IS_ALIGNED(sizeof(struct p_header80), 8)); 5738c2ecf20Sopenharmony_ci return sizeof(struct p_header80); 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci} 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_cistatic unsigned int prepare_header80(struct p_header80 *h, enum drbd_packet cmd, int size) 5788c2ecf20Sopenharmony_ci{ 5798c2ecf20Sopenharmony_ci h->magic = cpu_to_be32(DRBD_MAGIC); 5808c2ecf20Sopenharmony_ci h->command = cpu_to_be16(cmd); 5818c2ecf20Sopenharmony_ci h->length = cpu_to_be16(size); 5828c2ecf20Sopenharmony_ci return sizeof(struct p_header80); 5838c2ecf20Sopenharmony_ci} 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_cistatic unsigned int prepare_header95(struct p_header95 *h, enum drbd_packet cmd, int size) 5868c2ecf20Sopenharmony_ci{ 5878c2ecf20Sopenharmony_ci h->magic = cpu_to_be16(DRBD_MAGIC_BIG); 5888c2ecf20Sopenharmony_ci h->command = cpu_to_be16(cmd); 5898c2ecf20Sopenharmony_ci h->length = cpu_to_be32(size); 5908c2ecf20Sopenharmony_ci return sizeof(struct p_header95); 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic unsigned int prepare_header100(struct p_header100 *h, enum drbd_packet cmd, 5948c2ecf20Sopenharmony_ci int size, int vnr) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci h->magic = cpu_to_be32(DRBD_MAGIC_100); 5978c2ecf20Sopenharmony_ci h->volume = cpu_to_be16(vnr); 5988c2ecf20Sopenharmony_ci h->command = cpu_to_be16(cmd); 5998c2ecf20Sopenharmony_ci h->length = cpu_to_be32(size); 6008c2ecf20Sopenharmony_ci h->pad = 0; 6018c2ecf20Sopenharmony_ci return sizeof(struct p_header100); 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_cistatic unsigned int prepare_header(struct drbd_connection *connection, int vnr, 6058c2ecf20Sopenharmony_ci void *buffer, enum drbd_packet cmd, int size) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci if (connection->agreed_pro_version >= 100) 6088c2ecf20Sopenharmony_ci return prepare_header100(buffer, cmd, size, vnr); 6098c2ecf20Sopenharmony_ci else if (connection->agreed_pro_version >= 95 && 6108c2ecf20Sopenharmony_ci size > DRBD_MAX_SIZE_H80_PACKET) 6118c2ecf20Sopenharmony_ci return prepare_header95(buffer, cmd, size); 6128c2ecf20Sopenharmony_ci else 6138c2ecf20Sopenharmony_ci return prepare_header80(buffer, cmd, size); 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cistatic void *__conn_prepare_command(struct drbd_connection *connection, 6178c2ecf20Sopenharmony_ci struct drbd_socket *sock) 6188c2ecf20Sopenharmony_ci{ 6198c2ecf20Sopenharmony_ci if (!sock->socket) 6208c2ecf20Sopenharmony_ci return NULL; 6218c2ecf20Sopenharmony_ci return sock->sbuf + drbd_header_size(connection); 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_civoid *conn_prepare_command(struct drbd_connection *connection, struct drbd_socket *sock) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci void *p; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci mutex_lock(&sock->mutex); 6298c2ecf20Sopenharmony_ci p = __conn_prepare_command(connection, sock); 6308c2ecf20Sopenharmony_ci if (!p) 6318c2ecf20Sopenharmony_ci mutex_unlock(&sock->mutex); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci return p; 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_civoid *drbd_prepare_command(struct drbd_peer_device *peer_device, struct drbd_socket *sock) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci return conn_prepare_command(peer_device->connection, sock); 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic int __send_command(struct drbd_connection *connection, int vnr, 6428c2ecf20Sopenharmony_ci struct drbd_socket *sock, enum drbd_packet cmd, 6438c2ecf20Sopenharmony_ci unsigned int header_size, void *data, 6448c2ecf20Sopenharmony_ci unsigned int size) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci int msg_flags; 6478c2ecf20Sopenharmony_ci int err; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci /* 6508c2ecf20Sopenharmony_ci * Called with @data == NULL and the size of the data blocks in @size 6518c2ecf20Sopenharmony_ci * for commands that send data blocks. For those commands, omit the 6528c2ecf20Sopenharmony_ci * MSG_MORE flag: this will increase the likelihood that data blocks 6538c2ecf20Sopenharmony_ci * which are page aligned on the sender will end up page aligned on the 6548c2ecf20Sopenharmony_ci * receiver. 6558c2ecf20Sopenharmony_ci */ 6568c2ecf20Sopenharmony_ci msg_flags = data ? MSG_MORE : 0; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci header_size += prepare_header(connection, vnr, sock->sbuf, cmd, 6598c2ecf20Sopenharmony_ci header_size + size); 6608c2ecf20Sopenharmony_ci err = drbd_send_all(connection, sock->socket, sock->sbuf, header_size, 6618c2ecf20Sopenharmony_ci msg_flags); 6628c2ecf20Sopenharmony_ci if (data && !err) 6638c2ecf20Sopenharmony_ci err = drbd_send_all(connection, sock->socket, data, size, 0); 6648c2ecf20Sopenharmony_ci /* DRBD protocol "pings" are latency critical. 6658c2ecf20Sopenharmony_ci * This is supposed to trigger tcp_push_pending_frames() */ 6668c2ecf20Sopenharmony_ci if (!err && (cmd == P_PING || cmd == P_PING_ACK)) 6678c2ecf20Sopenharmony_ci tcp_sock_set_nodelay(sock->socket->sk); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci return err; 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistatic int __conn_send_command(struct drbd_connection *connection, struct drbd_socket *sock, 6738c2ecf20Sopenharmony_ci enum drbd_packet cmd, unsigned int header_size, 6748c2ecf20Sopenharmony_ci void *data, unsigned int size) 6758c2ecf20Sopenharmony_ci{ 6768c2ecf20Sopenharmony_ci return __send_command(connection, 0, sock, cmd, header_size, data, size); 6778c2ecf20Sopenharmony_ci} 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ciint conn_send_command(struct drbd_connection *connection, struct drbd_socket *sock, 6808c2ecf20Sopenharmony_ci enum drbd_packet cmd, unsigned int header_size, 6818c2ecf20Sopenharmony_ci void *data, unsigned int size) 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci int err; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci err = __conn_send_command(connection, sock, cmd, header_size, data, size); 6868c2ecf20Sopenharmony_ci mutex_unlock(&sock->mutex); 6878c2ecf20Sopenharmony_ci return err; 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ciint drbd_send_command(struct drbd_peer_device *peer_device, struct drbd_socket *sock, 6918c2ecf20Sopenharmony_ci enum drbd_packet cmd, unsigned int header_size, 6928c2ecf20Sopenharmony_ci void *data, unsigned int size) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci int err; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci err = __send_command(peer_device->connection, peer_device->device->vnr, 6978c2ecf20Sopenharmony_ci sock, cmd, header_size, data, size); 6988c2ecf20Sopenharmony_ci mutex_unlock(&sock->mutex); 6998c2ecf20Sopenharmony_ci return err; 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ciint drbd_send_ping(struct drbd_connection *connection) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci struct drbd_socket *sock; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci sock = &connection->meta; 7078c2ecf20Sopenharmony_ci if (!conn_prepare_command(connection, sock)) 7088c2ecf20Sopenharmony_ci return -EIO; 7098c2ecf20Sopenharmony_ci return conn_send_command(connection, sock, P_PING, 0, NULL, 0); 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ciint drbd_send_ping_ack(struct drbd_connection *connection) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci struct drbd_socket *sock; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci sock = &connection->meta; 7178c2ecf20Sopenharmony_ci if (!conn_prepare_command(connection, sock)) 7188c2ecf20Sopenharmony_ci return -EIO; 7198c2ecf20Sopenharmony_ci return conn_send_command(connection, sock, P_PING_ACK, 0, NULL, 0); 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ciint drbd_send_sync_param(struct drbd_peer_device *peer_device) 7238c2ecf20Sopenharmony_ci{ 7248c2ecf20Sopenharmony_ci struct drbd_socket *sock; 7258c2ecf20Sopenharmony_ci struct p_rs_param_95 *p; 7268c2ecf20Sopenharmony_ci int size; 7278c2ecf20Sopenharmony_ci const int apv = peer_device->connection->agreed_pro_version; 7288c2ecf20Sopenharmony_ci enum drbd_packet cmd; 7298c2ecf20Sopenharmony_ci struct net_conf *nc; 7308c2ecf20Sopenharmony_ci struct disk_conf *dc; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci sock = &peer_device->connection->data; 7338c2ecf20Sopenharmony_ci p = drbd_prepare_command(peer_device, sock); 7348c2ecf20Sopenharmony_ci if (!p) 7358c2ecf20Sopenharmony_ci return -EIO; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci rcu_read_lock(); 7388c2ecf20Sopenharmony_ci nc = rcu_dereference(peer_device->connection->net_conf); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci size = apv <= 87 ? sizeof(struct p_rs_param) 7418c2ecf20Sopenharmony_ci : apv == 88 ? sizeof(struct p_rs_param) 7428c2ecf20Sopenharmony_ci + strlen(nc->verify_alg) + 1 7438c2ecf20Sopenharmony_ci : apv <= 94 ? sizeof(struct p_rs_param_89) 7448c2ecf20Sopenharmony_ci : /* apv >= 95 */ sizeof(struct p_rs_param_95); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci cmd = apv >= 89 ? P_SYNC_PARAM89 : P_SYNC_PARAM; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci /* initialize verify_alg and csums_alg */ 7498c2ecf20Sopenharmony_ci memset(p->verify_alg, 0, 2 * SHARED_SECRET_MAX); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (get_ldev(peer_device->device)) { 7528c2ecf20Sopenharmony_ci dc = rcu_dereference(peer_device->device->ldev->disk_conf); 7538c2ecf20Sopenharmony_ci p->resync_rate = cpu_to_be32(dc->resync_rate); 7548c2ecf20Sopenharmony_ci p->c_plan_ahead = cpu_to_be32(dc->c_plan_ahead); 7558c2ecf20Sopenharmony_ci p->c_delay_target = cpu_to_be32(dc->c_delay_target); 7568c2ecf20Sopenharmony_ci p->c_fill_target = cpu_to_be32(dc->c_fill_target); 7578c2ecf20Sopenharmony_ci p->c_max_rate = cpu_to_be32(dc->c_max_rate); 7588c2ecf20Sopenharmony_ci put_ldev(peer_device->device); 7598c2ecf20Sopenharmony_ci } else { 7608c2ecf20Sopenharmony_ci p->resync_rate = cpu_to_be32(DRBD_RESYNC_RATE_DEF); 7618c2ecf20Sopenharmony_ci p->c_plan_ahead = cpu_to_be32(DRBD_C_PLAN_AHEAD_DEF); 7628c2ecf20Sopenharmony_ci p->c_delay_target = cpu_to_be32(DRBD_C_DELAY_TARGET_DEF); 7638c2ecf20Sopenharmony_ci p->c_fill_target = cpu_to_be32(DRBD_C_FILL_TARGET_DEF); 7648c2ecf20Sopenharmony_ci p->c_max_rate = cpu_to_be32(DRBD_C_MAX_RATE_DEF); 7658c2ecf20Sopenharmony_ci } 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci if (apv >= 88) 7688c2ecf20Sopenharmony_ci strcpy(p->verify_alg, nc->verify_alg); 7698c2ecf20Sopenharmony_ci if (apv >= 89) 7708c2ecf20Sopenharmony_ci strcpy(p->csums_alg, nc->csums_alg); 7718c2ecf20Sopenharmony_ci rcu_read_unlock(); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci return drbd_send_command(peer_device, sock, cmd, size, NULL, 0); 7748c2ecf20Sopenharmony_ci} 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ciint __drbd_send_protocol(struct drbd_connection *connection, enum drbd_packet cmd) 7778c2ecf20Sopenharmony_ci{ 7788c2ecf20Sopenharmony_ci struct drbd_socket *sock; 7798c2ecf20Sopenharmony_ci struct p_protocol *p; 7808c2ecf20Sopenharmony_ci struct net_conf *nc; 7818c2ecf20Sopenharmony_ci int size, cf; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci sock = &connection->data; 7848c2ecf20Sopenharmony_ci p = __conn_prepare_command(connection, sock); 7858c2ecf20Sopenharmony_ci if (!p) 7868c2ecf20Sopenharmony_ci return -EIO; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci rcu_read_lock(); 7898c2ecf20Sopenharmony_ci nc = rcu_dereference(connection->net_conf); 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci if (nc->tentative && connection->agreed_pro_version < 92) { 7928c2ecf20Sopenharmony_ci rcu_read_unlock(); 7938c2ecf20Sopenharmony_ci drbd_err(connection, "--dry-run is not supported by peer"); 7948c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci size = sizeof(*p); 7988c2ecf20Sopenharmony_ci if (connection->agreed_pro_version >= 87) 7998c2ecf20Sopenharmony_ci size += strlen(nc->integrity_alg) + 1; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci p->protocol = cpu_to_be32(nc->wire_protocol); 8028c2ecf20Sopenharmony_ci p->after_sb_0p = cpu_to_be32(nc->after_sb_0p); 8038c2ecf20Sopenharmony_ci p->after_sb_1p = cpu_to_be32(nc->after_sb_1p); 8048c2ecf20Sopenharmony_ci p->after_sb_2p = cpu_to_be32(nc->after_sb_2p); 8058c2ecf20Sopenharmony_ci p->two_primaries = cpu_to_be32(nc->two_primaries); 8068c2ecf20Sopenharmony_ci cf = 0; 8078c2ecf20Sopenharmony_ci if (nc->discard_my_data) 8088c2ecf20Sopenharmony_ci cf |= CF_DISCARD_MY_DATA; 8098c2ecf20Sopenharmony_ci if (nc->tentative) 8108c2ecf20Sopenharmony_ci cf |= CF_DRY_RUN; 8118c2ecf20Sopenharmony_ci p->conn_flags = cpu_to_be32(cf); 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci if (connection->agreed_pro_version >= 87) 8148c2ecf20Sopenharmony_ci strcpy(p->integrity_alg, nc->integrity_alg); 8158c2ecf20Sopenharmony_ci rcu_read_unlock(); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci return __conn_send_command(connection, sock, cmd, size, NULL, 0); 8188c2ecf20Sopenharmony_ci} 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ciint drbd_send_protocol(struct drbd_connection *connection) 8218c2ecf20Sopenharmony_ci{ 8228c2ecf20Sopenharmony_ci int err; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci mutex_lock(&connection->data.mutex); 8258c2ecf20Sopenharmony_ci err = __drbd_send_protocol(connection, P_PROTOCOL); 8268c2ecf20Sopenharmony_ci mutex_unlock(&connection->data.mutex); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci return err; 8298c2ecf20Sopenharmony_ci} 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_cistatic int _drbd_send_uuids(struct drbd_peer_device *peer_device, u64 uuid_flags) 8328c2ecf20Sopenharmony_ci{ 8338c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 8348c2ecf20Sopenharmony_ci struct drbd_socket *sock; 8358c2ecf20Sopenharmony_ci struct p_uuids *p; 8368c2ecf20Sopenharmony_ci int i; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci if (!get_ldev_if_state(device, D_NEGOTIATING)) 8398c2ecf20Sopenharmony_ci return 0; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci sock = &peer_device->connection->data; 8428c2ecf20Sopenharmony_ci p = drbd_prepare_command(peer_device, sock); 8438c2ecf20Sopenharmony_ci if (!p) { 8448c2ecf20Sopenharmony_ci put_ldev(device); 8458c2ecf20Sopenharmony_ci return -EIO; 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci spin_lock_irq(&device->ldev->md.uuid_lock); 8488c2ecf20Sopenharmony_ci for (i = UI_CURRENT; i < UI_SIZE; i++) 8498c2ecf20Sopenharmony_ci p->uuid[i] = cpu_to_be64(device->ldev->md.uuid[i]); 8508c2ecf20Sopenharmony_ci spin_unlock_irq(&device->ldev->md.uuid_lock); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci device->comm_bm_set = drbd_bm_total_weight(device); 8538c2ecf20Sopenharmony_ci p->uuid[UI_SIZE] = cpu_to_be64(device->comm_bm_set); 8548c2ecf20Sopenharmony_ci rcu_read_lock(); 8558c2ecf20Sopenharmony_ci uuid_flags |= rcu_dereference(peer_device->connection->net_conf)->discard_my_data ? 1 : 0; 8568c2ecf20Sopenharmony_ci rcu_read_unlock(); 8578c2ecf20Sopenharmony_ci uuid_flags |= test_bit(CRASHED_PRIMARY, &device->flags) ? 2 : 0; 8588c2ecf20Sopenharmony_ci uuid_flags |= device->new_state_tmp.disk == D_INCONSISTENT ? 4 : 0; 8598c2ecf20Sopenharmony_ci p->uuid[UI_FLAGS] = cpu_to_be64(uuid_flags); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci put_ldev(device); 8628c2ecf20Sopenharmony_ci return drbd_send_command(peer_device, sock, P_UUIDS, sizeof(*p), NULL, 0); 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ciint drbd_send_uuids(struct drbd_peer_device *peer_device) 8668c2ecf20Sopenharmony_ci{ 8678c2ecf20Sopenharmony_ci return _drbd_send_uuids(peer_device, 0); 8688c2ecf20Sopenharmony_ci} 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ciint drbd_send_uuids_skip_initial_sync(struct drbd_peer_device *peer_device) 8718c2ecf20Sopenharmony_ci{ 8728c2ecf20Sopenharmony_ci return _drbd_send_uuids(peer_device, 8); 8738c2ecf20Sopenharmony_ci} 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_civoid drbd_print_uuids(struct drbd_device *device, const char *text) 8768c2ecf20Sopenharmony_ci{ 8778c2ecf20Sopenharmony_ci if (get_ldev_if_state(device, D_NEGOTIATING)) { 8788c2ecf20Sopenharmony_ci u64 *uuid = device->ldev->md.uuid; 8798c2ecf20Sopenharmony_ci drbd_info(device, "%s %016llX:%016llX:%016llX:%016llX\n", 8808c2ecf20Sopenharmony_ci text, 8818c2ecf20Sopenharmony_ci (unsigned long long)uuid[UI_CURRENT], 8828c2ecf20Sopenharmony_ci (unsigned long long)uuid[UI_BITMAP], 8838c2ecf20Sopenharmony_ci (unsigned long long)uuid[UI_HISTORY_START], 8848c2ecf20Sopenharmony_ci (unsigned long long)uuid[UI_HISTORY_END]); 8858c2ecf20Sopenharmony_ci put_ldev(device); 8868c2ecf20Sopenharmony_ci } else { 8878c2ecf20Sopenharmony_ci drbd_info(device, "%s effective data uuid: %016llX\n", 8888c2ecf20Sopenharmony_ci text, 8898c2ecf20Sopenharmony_ci (unsigned long long)device->ed_uuid); 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci} 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_civoid drbd_gen_and_send_sync_uuid(struct drbd_peer_device *peer_device) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 8968c2ecf20Sopenharmony_ci struct drbd_socket *sock; 8978c2ecf20Sopenharmony_ci struct p_rs_uuid *p; 8988c2ecf20Sopenharmony_ci u64 uuid; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci D_ASSERT(device, device->state.disk == D_UP_TO_DATE); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci uuid = device->ldev->md.uuid[UI_BITMAP]; 9038c2ecf20Sopenharmony_ci if (uuid && uuid != UUID_JUST_CREATED) 9048c2ecf20Sopenharmony_ci uuid = uuid + UUID_NEW_BM_OFFSET; 9058c2ecf20Sopenharmony_ci else 9068c2ecf20Sopenharmony_ci get_random_bytes(&uuid, sizeof(u64)); 9078c2ecf20Sopenharmony_ci drbd_uuid_set(device, UI_BITMAP, uuid); 9088c2ecf20Sopenharmony_ci drbd_print_uuids(device, "updated sync UUID"); 9098c2ecf20Sopenharmony_ci drbd_md_sync(device); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci sock = &peer_device->connection->data; 9128c2ecf20Sopenharmony_ci p = drbd_prepare_command(peer_device, sock); 9138c2ecf20Sopenharmony_ci if (p) { 9148c2ecf20Sopenharmony_ci p->uuid = cpu_to_be64(uuid); 9158c2ecf20Sopenharmony_ci drbd_send_command(peer_device, sock, P_SYNC_UUID, sizeof(*p), NULL, 0); 9168c2ecf20Sopenharmony_ci } 9178c2ecf20Sopenharmony_ci} 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci/* communicated if (agreed_features & DRBD_FF_WSAME) */ 9208c2ecf20Sopenharmony_cistatic void 9218c2ecf20Sopenharmony_ciassign_p_sizes_qlim(struct drbd_device *device, struct p_sizes *p, 9228c2ecf20Sopenharmony_ci struct request_queue *q) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci if (q) { 9258c2ecf20Sopenharmony_ci p->qlim->physical_block_size = cpu_to_be32(queue_physical_block_size(q)); 9268c2ecf20Sopenharmony_ci p->qlim->logical_block_size = cpu_to_be32(queue_logical_block_size(q)); 9278c2ecf20Sopenharmony_ci p->qlim->alignment_offset = cpu_to_be32(queue_alignment_offset(q)); 9288c2ecf20Sopenharmony_ci p->qlim->io_min = cpu_to_be32(queue_io_min(q)); 9298c2ecf20Sopenharmony_ci p->qlim->io_opt = cpu_to_be32(queue_io_opt(q)); 9308c2ecf20Sopenharmony_ci p->qlim->discard_enabled = blk_queue_discard(q); 9318c2ecf20Sopenharmony_ci p->qlim->write_same_capable = !!q->limits.max_write_same_sectors; 9328c2ecf20Sopenharmony_ci } else { 9338c2ecf20Sopenharmony_ci q = device->rq_queue; 9348c2ecf20Sopenharmony_ci p->qlim->physical_block_size = cpu_to_be32(queue_physical_block_size(q)); 9358c2ecf20Sopenharmony_ci p->qlim->logical_block_size = cpu_to_be32(queue_logical_block_size(q)); 9368c2ecf20Sopenharmony_ci p->qlim->alignment_offset = 0; 9378c2ecf20Sopenharmony_ci p->qlim->io_min = cpu_to_be32(queue_io_min(q)); 9388c2ecf20Sopenharmony_ci p->qlim->io_opt = cpu_to_be32(queue_io_opt(q)); 9398c2ecf20Sopenharmony_ci p->qlim->discard_enabled = 0; 9408c2ecf20Sopenharmony_ci p->qlim->write_same_capable = 0; 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci} 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ciint drbd_send_sizes(struct drbd_peer_device *peer_device, int trigger_reply, enum dds_flags flags) 9458c2ecf20Sopenharmony_ci{ 9468c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 9478c2ecf20Sopenharmony_ci struct drbd_socket *sock; 9488c2ecf20Sopenharmony_ci struct p_sizes *p; 9498c2ecf20Sopenharmony_ci sector_t d_size, u_size; 9508c2ecf20Sopenharmony_ci int q_order_type; 9518c2ecf20Sopenharmony_ci unsigned int max_bio_size; 9528c2ecf20Sopenharmony_ci unsigned int packet_size; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci sock = &peer_device->connection->data; 9558c2ecf20Sopenharmony_ci p = drbd_prepare_command(peer_device, sock); 9568c2ecf20Sopenharmony_ci if (!p) 9578c2ecf20Sopenharmony_ci return -EIO; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci packet_size = sizeof(*p); 9608c2ecf20Sopenharmony_ci if (peer_device->connection->agreed_features & DRBD_FF_WSAME) 9618c2ecf20Sopenharmony_ci packet_size += sizeof(p->qlim[0]); 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci memset(p, 0, packet_size); 9648c2ecf20Sopenharmony_ci if (get_ldev_if_state(device, D_NEGOTIATING)) { 9658c2ecf20Sopenharmony_ci struct request_queue *q = bdev_get_queue(device->ldev->backing_bdev); 9668c2ecf20Sopenharmony_ci d_size = drbd_get_max_capacity(device->ldev); 9678c2ecf20Sopenharmony_ci rcu_read_lock(); 9688c2ecf20Sopenharmony_ci u_size = rcu_dereference(device->ldev->disk_conf)->disk_size; 9698c2ecf20Sopenharmony_ci rcu_read_unlock(); 9708c2ecf20Sopenharmony_ci q_order_type = drbd_queue_order_type(device); 9718c2ecf20Sopenharmony_ci max_bio_size = queue_max_hw_sectors(q) << 9; 9728c2ecf20Sopenharmony_ci max_bio_size = min(max_bio_size, DRBD_MAX_BIO_SIZE); 9738c2ecf20Sopenharmony_ci assign_p_sizes_qlim(device, p, q); 9748c2ecf20Sopenharmony_ci put_ldev(device); 9758c2ecf20Sopenharmony_ci } else { 9768c2ecf20Sopenharmony_ci d_size = 0; 9778c2ecf20Sopenharmony_ci u_size = 0; 9788c2ecf20Sopenharmony_ci q_order_type = QUEUE_ORDERED_NONE; 9798c2ecf20Sopenharmony_ci max_bio_size = DRBD_MAX_BIO_SIZE; /* ... multiple BIOs per peer_request */ 9808c2ecf20Sopenharmony_ci assign_p_sizes_qlim(device, p, NULL); 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci if (peer_device->connection->agreed_pro_version <= 94) 9848c2ecf20Sopenharmony_ci max_bio_size = min(max_bio_size, DRBD_MAX_SIZE_H80_PACKET); 9858c2ecf20Sopenharmony_ci else if (peer_device->connection->agreed_pro_version < 100) 9868c2ecf20Sopenharmony_ci max_bio_size = min(max_bio_size, DRBD_MAX_BIO_SIZE_P95); 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci p->d_size = cpu_to_be64(d_size); 9898c2ecf20Sopenharmony_ci p->u_size = cpu_to_be64(u_size); 9908c2ecf20Sopenharmony_ci if (trigger_reply) 9918c2ecf20Sopenharmony_ci p->c_size = 0; 9928c2ecf20Sopenharmony_ci else 9938c2ecf20Sopenharmony_ci p->c_size = cpu_to_be64(get_capacity(device->vdisk)); 9948c2ecf20Sopenharmony_ci p->max_bio_size = cpu_to_be32(max_bio_size); 9958c2ecf20Sopenharmony_ci p->queue_order_type = cpu_to_be16(q_order_type); 9968c2ecf20Sopenharmony_ci p->dds_flags = cpu_to_be16(flags); 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci return drbd_send_command(peer_device, sock, P_SIZES, packet_size, NULL, 0); 9998c2ecf20Sopenharmony_ci} 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci/** 10028c2ecf20Sopenharmony_ci * drbd_send_current_state() - Sends the drbd state to the peer 10038c2ecf20Sopenharmony_ci * @peer_device: DRBD peer device. 10048c2ecf20Sopenharmony_ci */ 10058c2ecf20Sopenharmony_ciint drbd_send_current_state(struct drbd_peer_device *peer_device) 10068c2ecf20Sopenharmony_ci{ 10078c2ecf20Sopenharmony_ci struct drbd_socket *sock; 10088c2ecf20Sopenharmony_ci struct p_state *p; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci sock = &peer_device->connection->data; 10118c2ecf20Sopenharmony_ci p = drbd_prepare_command(peer_device, sock); 10128c2ecf20Sopenharmony_ci if (!p) 10138c2ecf20Sopenharmony_ci return -EIO; 10148c2ecf20Sopenharmony_ci p->state = cpu_to_be32(peer_device->device->state.i); /* Within the send mutex */ 10158c2ecf20Sopenharmony_ci return drbd_send_command(peer_device, sock, P_STATE, sizeof(*p), NULL, 0); 10168c2ecf20Sopenharmony_ci} 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci/** 10198c2ecf20Sopenharmony_ci * drbd_send_state() - After a state change, sends the new state to the peer 10208c2ecf20Sopenharmony_ci * @peer_device: DRBD peer device. 10218c2ecf20Sopenharmony_ci * @state: the state to send, not necessarily the current state. 10228c2ecf20Sopenharmony_ci * 10238c2ecf20Sopenharmony_ci * Each state change queues an "after_state_ch" work, which will eventually 10248c2ecf20Sopenharmony_ci * send the resulting new state to the peer. If more state changes happen 10258c2ecf20Sopenharmony_ci * between queuing and processing of the after_state_ch work, we still 10268c2ecf20Sopenharmony_ci * want to send each intermediary state in the order it occurred. 10278c2ecf20Sopenharmony_ci */ 10288c2ecf20Sopenharmony_ciint drbd_send_state(struct drbd_peer_device *peer_device, union drbd_state state) 10298c2ecf20Sopenharmony_ci{ 10308c2ecf20Sopenharmony_ci struct drbd_socket *sock; 10318c2ecf20Sopenharmony_ci struct p_state *p; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci sock = &peer_device->connection->data; 10348c2ecf20Sopenharmony_ci p = drbd_prepare_command(peer_device, sock); 10358c2ecf20Sopenharmony_ci if (!p) 10368c2ecf20Sopenharmony_ci return -EIO; 10378c2ecf20Sopenharmony_ci p->state = cpu_to_be32(state.i); /* Within the send mutex */ 10388c2ecf20Sopenharmony_ci return drbd_send_command(peer_device, sock, P_STATE, sizeof(*p), NULL, 0); 10398c2ecf20Sopenharmony_ci} 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ciint drbd_send_state_req(struct drbd_peer_device *peer_device, union drbd_state mask, union drbd_state val) 10428c2ecf20Sopenharmony_ci{ 10438c2ecf20Sopenharmony_ci struct drbd_socket *sock; 10448c2ecf20Sopenharmony_ci struct p_req_state *p; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci sock = &peer_device->connection->data; 10478c2ecf20Sopenharmony_ci p = drbd_prepare_command(peer_device, sock); 10488c2ecf20Sopenharmony_ci if (!p) 10498c2ecf20Sopenharmony_ci return -EIO; 10508c2ecf20Sopenharmony_ci p->mask = cpu_to_be32(mask.i); 10518c2ecf20Sopenharmony_ci p->val = cpu_to_be32(val.i); 10528c2ecf20Sopenharmony_ci return drbd_send_command(peer_device, sock, P_STATE_CHG_REQ, sizeof(*p), NULL, 0); 10538c2ecf20Sopenharmony_ci} 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ciint conn_send_state_req(struct drbd_connection *connection, union drbd_state mask, union drbd_state val) 10568c2ecf20Sopenharmony_ci{ 10578c2ecf20Sopenharmony_ci enum drbd_packet cmd; 10588c2ecf20Sopenharmony_ci struct drbd_socket *sock; 10598c2ecf20Sopenharmony_ci struct p_req_state *p; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci cmd = connection->agreed_pro_version < 100 ? P_STATE_CHG_REQ : P_CONN_ST_CHG_REQ; 10628c2ecf20Sopenharmony_ci sock = &connection->data; 10638c2ecf20Sopenharmony_ci p = conn_prepare_command(connection, sock); 10648c2ecf20Sopenharmony_ci if (!p) 10658c2ecf20Sopenharmony_ci return -EIO; 10668c2ecf20Sopenharmony_ci p->mask = cpu_to_be32(mask.i); 10678c2ecf20Sopenharmony_ci p->val = cpu_to_be32(val.i); 10688c2ecf20Sopenharmony_ci return conn_send_command(connection, sock, cmd, sizeof(*p), NULL, 0); 10698c2ecf20Sopenharmony_ci} 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_civoid drbd_send_sr_reply(struct drbd_peer_device *peer_device, enum drbd_state_rv retcode) 10728c2ecf20Sopenharmony_ci{ 10738c2ecf20Sopenharmony_ci struct drbd_socket *sock; 10748c2ecf20Sopenharmony_ci struct p_req_state_reply *p; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci sock = &peer_device->connection->meta; 10778c2ecf20Sopenharmony_ci p = drbd_prepare_command(peer_device, sock); 10788c2ecf20Sopenharmony_ci if (p) { 10798c2ecf20Sopenharmony_ci p->retcode = cpu_to_be32(retcode); 10808c2ecf20Sopenharmony_ci drbd_send_command(peer_device, sock, P_STATE_CHG_REPLY, sizeof(*p), NULL, 0); 10818c2ecf20Sopenharmony_ci } 10828c2ecf20Sopenharmony_ci} 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_civoid conn_send_sr_reply(struct drbd_connection *connection, enum drbd_state_rv retcode) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci struct drbd_socket *sock; 10878c2ecf20Sopenharmony_ci struct p_req_state_reply *p; 10888c2ecf20Sopenharmony_ci enum drbd_packet cmd = connection->agreed_pro_version < 100 ? P_STATE_CHG_REPLY : P_CONN_ST_CHG_REPLY; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci sock = &connection->meta; 10918c2ecf20Sopenharmony_ci p = conn_prepare_command(connection, sock); 10928c2ecf20Sopenharmony_ci if (p) { 10938c2ecf20Sopenharmony_ci p->retcode = cpu_to_be32(retcode); 10948c2ecf20Sopenharmony_ci conn_send_command(connection, sock, cmd, sizeof(*p), NULL, 0); 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci} 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_cistatic void dcbp_set_code(struct p_compressed_bm *p, enum drbd_bitmap_code code) 10998c2ecf20Sopenharmony_ci{ 11008c2ecf20Sopenharmony_ci BUG_ON(code & ~0xf); 11018c2ecf20Sopenharmony_ci p->encoding = (p->encoding & ~0xf) | code; 11028c2ecf20Sopenharmony_ci} 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_cistatic void dcbp_set_start(struct p_compressed_bm *p, int set) 11058c2ecf20Sopenharmony_ci{ 11068c2ecf20Sopenharmony_ci p->encoding = (p->encoding & ~0x80) | (set ? 0x80 : 0); 11078c2ecf20Sopenharmony_ci} 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_cistatic void dcbp_set_pad_bits(struct p_compressed_bm *p, int n) 11108c2ecf20Sopenharmony_ci{ 11118c2ecf20Sopenharmony_ci BUG_ON(n & ~0x7); 11128c2ecf20Sopenharmony_ci p->encoding = (p->encoding & (~0x7 << 4)) | (n << 4); 11138c2ecf20Sopenharmony_ci} 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_cistatic int fill_bitmap_rle_bits(struct drbd_device *device, 11168c2ecf20Sopenharmony_ci struct p_compressed_bm *p, 11178c2ecf20Sopenharmony_ci unsigned int size, 11188c2ecf20Sopenharmony_ci struct bm_xfer_ctx *c) 11198c2ecf20Sopenharmony_ci{ 11208c2ecf20Sopenharmony_ci struct bitstream bs; 11218c2ecf20Sopenharmony_ci unsigned long plain_bits; 11228c2ecf20Sopenharmony_ci unsigned long tmp; 11238c2ecf20Sopenharmony_ci unsigned long rl; 11248c2ecf20Sopenharmony_ci unsigned len; 11258c2ecf20Sopenharmony_ci unsigned toggle; 11268c2ecf20Sopenharmony_ci int bits, use_rle; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci /* may we use this feature? */ 11298c2ecf20Sopenharmony_ci rcu_read_lock(); 11308c2ecf20Sopenharmony_ci use_rle = rcu_dereference(first_peer_device(device)->connection->net_conf)->use_rle; 11318c2ecf20Sopenharmony_ci rcu_read_unlock(); 11328c2ecf20Sopenharmony_ci if (!use_rle || first_peer_device(device)->connection->agreed_pro_version < 90) 11338c2ecf20Sopenharmony_ci return 0; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci if (c->bit_offset >= c->bm_bits) 11368c2ecf20Sopenharmony_ci return 0; /* nothing to do. */ 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci /* use at most thus many bytes */ 11398c2ecf20Sopenharmony_ci bitstream_init(&bs, p->code, size, 0); 11408c2ecf20Sopenharmony_ci memset(p->code, 0, size); 11418c2ecf20Sopenharmony_ci /* plain bits covered in this code string */ 11428c2ecf20Sopenharmony_ci plain_bits = 0; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci /* p->encoding & 0x80 stores whether the first run length is set. 11458c2ecf20Sopenharmony_ci * bit offset is implicit. 11468c2ecf20Sopenharmony_ci * start with toggle == 2 to be able to tell the first iteration */ 11478c2ecf20Sopenharmony_ci toggle = 2; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci /* see how much plain bits we can stuff into one packet 11508c2ecf20Sopenharmony_ci * using RLE and VLI. */ 11518c2ecf20Sopenharmony_ci do { 11528c2ecf20Sopenharmony_ci tmp = (toggle == 0) ? _drbd_bm_find_next_zero(device, c->bit_offset) 11538c2ecf20Sopenharmony_ci : _drbd_bm_find_next(device, c->bit_offset); 11548c2ecf20Sopenharmony_ci if (tmp == -1UL) 11558c2ecf20Sopenharmony_ci tmp = c->bm_bits; 11568c2ecf20Sopenharmony_ci rl = tmp - c->bit_offset; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci if (toggle == 2) { /* first iteration */ 11598c2ecf20Sopenharmony_ci if (rl == 0) { 11608c2ecf20Sopenharmony_ci /* the first checked bit was set, 11618c2ecf20Sopenharmony_ci * store start value, */ 11628c2ecf20Sopenharmony_ci dcbp_set_start(p, 1); 11638c2ecf20Sopenharmony_ci /* but skip encoding of zero run length */ 11648c2ecf20Sopenharmony_ci toggle = !toggle; 11658c2ecf20Sopenharmony_ci continue; 11668c2ecf20Sopenharmony_ci } 11678c2ecf20Sopenharmony_ci dcbp_set_start(p, 0); 11688c2ecf20Sopenharmony_ci } 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci /* paranoia: catch zero runlength. 11718c2ecf20Sopenharmony_ci * can only happen if bitmap is modified while we scan it. */ 11728c2ecf20Sopenharmony_ci if (rl == 0) { 11738c2ecf20Sopenharmony_ci drbd_err(device, "unexpected zero runlength while encoding bitmap " 11748c2ecf20Sopenharmony_ci "t:%u bo:%lu\n", toggle, c->bit_offset); 11758c2ecf20Sopenharmony_ci return -1; 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci bits = vli_encode_bits(&bs, rl); 11798c2ecf20Sopenharmony_ci if (bits == -ENOBUFS) /* buffer full */ 11808c2ecf20Sopenharmony_ci break; 11818c2ecf20Sopenharmony_ci if (bits <= 0) { 11828c2ecf20Sopenharmony_ci drbd_err(device, "error while encoding bitmap: %d\n", bits); 11838c2ecf20Sopenharmony_ci return 0; 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci toggle = !toggle; 11878c2ecf20Sopenharmony_ci plain_bits += rl; 11888c2ecf20Sopenharmony_ci c->bit_offset = tmp; 11898c2ecf20Sopenharmony_ci } while (c->bit_offset < c->bm_bits); 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci len = bs.cur.b - p->code + !!bs.cur.bit; 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci if (plain_bits < (len << 3)) { 11948c2ecf20Sopenharmony_ci /* incompressible with this method. 11958c2ecf20Sopenharmony_ci * we need to rewind both word and bit position. */ 11968c2ecf20Sopenharmony_ci c->bit_offset -= plain_bits; 11978c2ecf20Sopenharmony_ci bm_xfer_ctx_bit_to_word_offset(c); 11988c2ecf20Sopenharmony_ci c->bit_offset = c->word_offset * BITS_PER_LONG; 11998c2ecf20Sopenharmony_ci return 0; 12008c2ecf20Sopenharmony_ci } 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci /* RLE + VLI was able to compress it just fine. 12038c2ecf20Sopenharmony_ci * update c->word_offset. */ 12048c2ecf20Sopenharmony_ci bm_xfer_ctx_bit_to_word_offset(c); 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci /* store pad_bits */ 12078c2ecf20Sopenharmony_ci dcbp_set_pad_bits(p, (8 - bs.cur.bit) & 0x7); 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci return len; 12108c2ecf20Sopenharmony_ci} 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci/** 12138c2ecf20Sopenharmony_ci * send_bitmap_rle_or_plain 12148c2ecf20Sopenharmony_ci * 12158c2ecf20Sopenharmony_ci * Return 0 when done, 1 when another iteration is needed, and a negative error 12168c2ecf20Sopenharmony_ci * code upon failure. 12178c2ecf20Sopenharmony_ci */ 12188c2ecf20Sopenharmony_cistatic int 12198c2ecf20Sopenharmony_cisend_bitmap_rle_or_plain(struct drbd_device *device, struct bm_xfer_ctx *c) 12208c2ecf20Sopenharmony_ci{ 12218c2ecf20Sopenharmony_ci struct drbd_socket *sock = &first_peer_device(device)->connection->data; 12228c2ecf20Sopenharmony_ci unsigned int header_size = drbd_header_size(first_peer_device(device)->connection); 12238c2ecf20Sopenharmony_ci struct p_compressed_bm *p = sock->sbuf + header_size; 12248c2ecf20Sopenharmony_ci int len, err; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci len = fill_bitmap_rle_bits(device, p, 12278c2ecf20Sopenharmony_ci DRBD_SOCKET_BUFFER_SIZE - header_size - sizeof(*p), c); 12288c2ecf20Sopenharmony_ci if (len < 0) 12298c2ecf20Sopenharmony_ci return -EIO; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci if (len) { 12328c2ecf20Sopenharmony_ci dcbp_set_code(p, RLE_VLI_Bits); 12338c2ecf20Sopenharmony_ci err = __send_command(first_peer_device(device)->connection, device->vnr, sock, 12348c2ecf20Sopenharmony_ci P_COMPRESSED_BITMAP, sizeof(*p) + len, 12358c2ecf20Sopenharmony_ci NULL, 0); 12368c2ecf20Sopenharmony_ci c->packets[0]++; 12378c2ecf20Sopenharmony_ci c->bytes[0] += header_size + sizeof(*p) + len; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci if (c->bit_offset >= c->bm_bits) 12408c2ecf20Sopenharmony_ci len = 0; /* DONE */ 12418c2ecf20Sopenharmony_ci } else { 12428c2ecf20Sopenharmony_ci /* was not compressible. 12438c2ecf20Sopenharmony_ci * send a buffer full of plain text bits instead. */ 12448c2ecf20Sopenharmony_ci unsigned int data_size; 12458c2ecf20Sopenharmony_ci unsigned long num_words; 12468c2ecf20Sopenharmony_ci unsigned long *p = sock->sbuf + header_size; 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci data_size = DRBD_SOCKET_BUFFER_SIZE - header_size; 12498c2ecf20Sopenharmony_ci num_words = min_t(size_t, data_size / sizeof(*p), 12508c2ecf20Sopenharmony_ci c->bm_words - c->word_offset); 12518c2ecf20Sopenharmony_ci len = num_words * sizeof(*p); 12528c2ecf20Sopenharmony_ci if (len) 12538c2ecf20Sopenharmony_ci drbd_bm_get_lel(device, c->word_offset, num_words, p); 12548c2ecf20Sopenharmony_ci err = __send_command(first_peer_device(device)->connection, device->vnr, sock, P_BITMAP, len, NULL, 0); 12558c2ecf20Sopenharmony_ci c->word_offset += num_words; 12568c2ecf20Sopenharmony_ci c->bit_offset = c->word_offset * BITS_PER_LONG; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci c->packets[1]++; 12598c2ecf20Sopenharmony_ci c->bytes[1] += header_size + len; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci if (c->bit_offset > c->bm_bits) 12628c2ecf20Sopenharmony_ci c->bit_offset = c->bm_bits; 12638c2ecf20Sopenharmony_ci } 12648c2ecf20Sopenharmony_ci if (!err) { 12658c2ecf20Sopenharmony_ci if (len == 0) { 12668c2ecf20Sopenharmony_ci INFO_bm_xfer_stats(device, "send", c); 12678c2ecf20Sopenharmony_ci return 0; 12688c2ecf20Sopenharmony_ci } else 12698c2ecf20Sopenharmony_ci return 1; 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci return -EIO; 12728c2ecf20Sopenharmony_ci} 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci/* See the comment at receive_bitmap() */ 12758c2ecf20Sopenharmony_cistatic int _drbd_send_bitmap(struct drbd_device *device) 12768c2ecf20Sopenharmony_ci{ 12778c2ecf20Sopenharmony_ci struct bm_xfer_ctx c; 12788c2ecf20Sopenharmony_ci int err; 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci if (!expect(device->bitmap)) 12818c2ecf20Sopenharmony_ci return false; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci if (get_ldev(device)) { 12848c2ecf20Sopenharmony_ci if (drbd_md_test_flag(device->ldev, MDF_FULL_SYNC)) { 12858c2ecf20Sopenharmony_ci drbd_info(device, "Writing the whole bitmap, MDF_FullSync was set.\n"); 12868c2ecf20Sopenharmony_ci drbd_bm_set_all(device); 12878c2ecf20Sopenharmony_ci if (drbd_bm_write(device)) { 12888c2ecf20Sopenharmony_ci /* write_bm did fail! Leave full sync flag set in Meta P_DATA 12898c2ecf20Sopenharmony_ci * but otherwise process as per normal - need to tell other 12908c2ecf20Sopenharmony_ci * side that a full resync is required! */ 12918c2ecf20Sopenharmony_ci drbd_err(device, "Failed to write bitmap to disk!\n"); 12928c2ecf20Sopenharmony_ci } else { 12938c2ecf20Sopenharmony_ci drbd_md_clear_flag(device, MDF_FULL_SYNC); 12948c2ecf20Sopenharmony_ci drbd_md_sync(device); 12958c2ecf20Sopenharmony_ci } 12968c2ecf20Sopenharmony_ci } 12978c2ecf20Sopenharmony_ci put_ldev(device); 12988c2ecf20Sopenharmony_ci } 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci c = (struct bm_xfer_ctx) { 13018c2ecf20Sopenharmony_ci .bm_bits = drbd_bm_bits(device), 13028c2ecf20Sopenharmony_ci .bm_words = drbd_bm_words(device), 13038c2ecf20Sopenharmony_ci }; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci do { 13068c2ecf20Sopenharmony_ci err = send_bitmap_rle_or_plain(device, &c); 13078c2ecf20Sopenharmony_ci } while (err > 0); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci return err == 0; 13108c2ecf20Sopenharmony_ci} 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ciint drbd_send_bitmap(struct drbd_device *device) 13138c2ecf20Sopenharmony_ci{ 13148c2ecf20Sopenharmony_ci struct drbd_socket *sock = &first_peer_device(device)->connection->data; 13158c2ecf20Sopenharmony_ci int err = -1; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci mutex_lock(&sock->mutex); 13188c2ecf20Sopenharmony_ci if (sock->socket) 13198c2ecf20Sopenharmony_ci err = !_drbd_send_bitmap(device); 13208c2ecf20Sopenharmony_ci mutex_unlock(&sock->mutex); 13218c2ecf20Sopenharmony_ci return err; 13228c2ecf20Sopenharmony_ci} 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_civoid drbd_send_b_ack(struct drbd_connection *connection, u32 barrier_nr, u32 set_size) 13258c2ecf20Sopenharmony_ci{ 13268c2ecf20Sopenharmony_ci struct drbd_socket *sock; 13278c2ecf20Sopenharmony_ci struct p_barrier_ack *p; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci if (connection->cstate < C_WF_REPORT_PARAMS) 13308c2ecf20Sopenharmony_ci return; 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci sock = &connection->meta; 13338c2ecf20Sopenharmony_ci p = conn_prepare_command(connection, sock); 13348c2ecf20Sopenharmony_ci if (!p) 13358c2ecf20Sopenharmony_ci return; 13368c2ecf20Sopenharmony_ci p->barrier = barrier_nr; 13378c2ecf20Sopenharmony_ci p->set_size = cpu_to_be32(set_size); 13388c2ecf20Sopenharmony_ci conn_send_command(connection, sock, P_BARRIER_ACK, sizeof(*p), NULL, 0); 13398c2ecf20Sopenharmony_ci} 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci/** 13428c2ecf20Sopenharmony_ci * _drbd_send_ack() - Sends an ack packet 13438c2ecf20Sopenharmony_ci * @device: DRBD device. 13448c2ecf20Sopenharmony_ci * @cmd: Packet command code. 13458c2ecf20Sopenharmony_ci * @sector: sector, needs to be in big endian byte order 13468c2ecf20Sopenharmony_ci * @blksize: size in byte, needs to be in big endian byte order 13478c2ecf20Sopenharmony_ci * @block_id: Id, big endian byte order 13488c2ecf20Sopenharmony_ci */ 13498c2ecf20Sopenharmony_cistatic int _drbd_send_ack(struct drbd_peer_device *peer_device, enum drbd_packet cmd, 13508c2ecf20Sopenharmony_ci u64 sector, u32 blksize, u64 block_id) 13518c2ecf20Sopenharmony_ci{ 13528c2ecf20Sopenharmony_ci struct drbd_socket *sock; 13538c2ecf20Sopenharmony_ci struct p_block_ack *p; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci if (peer_device->device->state.conn < C_CONNECTED) 13568c2ecf20Sopenharmony_ci return -EIO; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci sock = &peer_device->connection->meta; 13598c2ecf20Sopenharmony_ci p = drbd_prepare_command(peer_device, sock); 13608c2ecf20Sopenharmony_ci if (!p) 13618c2ecf20Sopenharmony_ci return -EIO; 13628c2ecf20Sopenharmony_ci p->sector = sector; 13638c2ecf20Sopenharmony_ci p->block_id = block_id; 13648c2ecf20Sopenharmony_ci p->blksize = blksize; 13658c2ecf20Sopenharmony_ci p->seq_num = cpu_to_be32(atomic_inc_return(&peer_device->device->packet_seq)); 13668c2ecf20Sopenharmony_ci return drbd_send_command(peer_device, sock, cmd, sizeof(*p), NULL, 0); 13678c2ecf20Sopenharmony_ci} 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci/* dp->sector and dp->block_id already/still in network byte order, 13708c2ecf20Sopenharmony_ci * data_size is payload size according to dp->head, 13718c2ecf20Sopenharmony_ci * and may need to be corrected for digest size. */ 13728c2ecf20Sopenharmony_civoid drbd_send_ack_dp(struct drbd_peer_device *peer_device, enum drbd_packet cmd, 13738c2ecf20Sopenharmony_ci struct p_data *dp, int data_size) 13748c2ecf20Sopenharmony_ci{ 13758c2ecf20Sopenharmony_ci if (peer_device->connection->peer_integrity_tfm) 13768c2ecf20Sopenharmony_ci data_size -= crypto_shash_digestsize(peer_device->connection->peer_integrity_tfm); 13778c2ecf20Sopenharmony_ci _drbd_send_ack(peer_device, cmd, dp->sector, cpu_to_be32(data_size), 13788c2ecf20Sopenharmony_ci dp->block_id); 13798c2ecf20Sopenharmony_ci} 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_civoid drbd_send_ack_rp(struct drbd_peer_device *peer_device, enum drbd_packet cmd, 13828c2ecf20Sopenharmony_ci struct p_block_req *rp) 13838c2ecf20Sopenharmony_ci{ 13848c2ecf20Sopenharmony_ci _drbd_send_ack(peer_device, cmd, rp->sector, rp->blksize, rp->block_id); 13858c2ecf20Sopenharmony_ci} 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci/** 13888c2ecf20Sopenharmony_ci * drbd_send_ack() - Sends an ack packet 13898c2ecf20Sopenharmony_ci * @device: DRBD device 13908c2ecf20Sopenharmony_ci * @cmd: packet command code 13918c2ecf20Sopenharmony_ci * @peer_req: peer request 13928c2ecf20Sopenharmony_ci */ 13938c2ecf20Sopenharmony_ciint drbd_send_ack(struct drbd_peer_device *peer_device, enum drbd_packet cmd, 13948c2ecf20Sopenharmony_ci struct drbd_peer_request *peer_req) 13958c2ecf20Sopenharmony_ci{ 13968c2ecf20Sopenharmony_ci return _drbd_send_ack(peer_device, cmd, 13978c2ecf20Sopenharmony_ci cpu_to_be64(peer_req->i.sector), 13988c2ecf20Sopenharmony_ci cpu_to_be32(peer_req->i.size), 13998c2ecf20Sopenharmony_ci peer_req->block_id); 14008c2ecf20Sopenharmony_ci} 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci/* This function misuses the block_id field to signal if the blocks 14038c2ecf20Sopenharmony_ci * are is sync or not. */ 14048c2ecf20Sopenharmony_ciint drbd_send_ack_ex(struct drbd_peer_device *peer_device, enum drbd_packet cmd, 14058c2ecf20Sopenharmony_ci sector_t sector, int blksize, u64 block_id) 14068c2ecf20Sopenharmony_ci{ 14078c2ecf20Sopenharmony_ci return _drbd_send_ack(peer_device, cmd, 14088c2ecf20Sopenharmony_ci cpu_to_be64(sector), 14098c2ecf20Sopenharmony_ci cpu_to_be32(blksize), 14108c2ecf20Sopenharmony_ci cpu_to_be64(block_id)); 14118c2ecf20Sopenharmony_ci} 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ciint drbd_send_rs_deallocated(struct drbd_peer_device *peer_device, 14148c2ecf20Sopenharmony_ci struct drbd_peer_request *peer_req) 14158c2ecf20Sopenharmony_ci{ 14168c2ecf20Sopenharmony_ci struct drbd_socket *sock; 14178c2ecf20Sopenharmony_ci struct p_block_desc *p; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci sock = &peer_device->connection->data; 14208c2ecf20Sopenharmony_ci p = drbd_prepare_command(peer_device, sock); 14218c2ecf20Sopenharmony_ci if (!p) 14228c2ecf20Sopenharmony_ci return -EIO; 14238c2ecf20Sopenharmony_ci p->sector = cpu_to_be64(peer_req->i.sector); 14248c2ecf20Sopenharmony_ci p->blksize = cpu_to_be32(peer_req->i.size); 14258c2ecf20Sopenharmony_ci p->pad = 0; 14268c2ecf20Sopenharmony_ci return drbd_send_command(peer_device, sock, P_RS_DEALLOCATED, sizeof(*p), NULL, 0); 14278c2ecf20Sopenharmony_ci} 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ciint drbd_send_drequest(struct drbd_peer_device *peer_device, int cmd, 14308c2ecf20Sopenharmony_ci sector_t sector, int size, u64 block_id) 14318c2ecf20Sopenharmony_ci{ 14328c2ecf20Sopenharmony_ci struct drbd_socket *sock; 14338c2ecf20Sopenharmony_ci struct p_block_req *p; 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci sock = &peer_device->connection->data; 14368c2ecf20Sopenharmony_ci p = drbd_prepare_command(peer_device, sock); 14378c2ecf20Sopenharmony_ci if (!p) 14388c2ecf20Sopenharmony_ci return -EIO; 14398c2ecf20Sopenharmony_ci p->sector = cpu_to_be64(sector); 14408c2ecf20Sopenharmony_ci p->block_id = block_id; 14418c2ecf20Sopenharmony_ci p->blksize = cpu_to_be32(size); 14428c2ecf20Sopenharmony_ci return drbd_send_command(peer_device, sock, cmd, sizeof(*p), NULL, 0); 14438c2ecf20Sopenharmony_ci} 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ciint drbd_send_drequest_csum(struct drbd_peer_device *peer_device, sector_t sector, int size, 14468c2ecf20Sopenharmony_ci void *digest, int digest_size, enum drbd_packet cmd) 14478c2ecf20Sopenharmony_ci{ 14488c2ecf20Sopenharmony_ci struct drbd_socket *sock; 14498c2ecf20Sopenharmony_ci struct p_block_req *p; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci /* FIXME: Put the digest into the preallocated socket buffer. */ 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci sock = &peer_device->connection->data; 14548c2ecf20Sopenharmony_ci p = drbd_prepare_command(peer_device, sock); 14558c2ecf20Sopenharmony_ci if (!p) 14568c2ecf20Sopenharmony_ci return -EIO; 14578c2ecf20Sopenharmony_ci p->sector = cpu_to_be64(sector); 14588c2ecf20Sopenharmony_ci p->block_id = ID_SYNCER /* unused */; 14598c2ecf20Sopenharmony_ci p->blksize = cpu_to_be32(size); 14608c2ecf20Sopenharmony_ci return drbd_send_command(peer_device, sock, cmd, sizeof(*p), digest, digest_size); 14618c2ecf20Sopenharmony_ci} 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ciint drbd_send_ov_request(struct drbd_peer_device *peer_device, sector_t sector, int size) 14648c2ecf20Sopenharmony_ci{ 14658c2ecf20Sopenharmony_ci struct drbd_socket *sock; 14668c2ecf20Sopenharmony_ci struct p_block_req *p; 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci sock = &peer_device->connection->data; 14698c2ecf20Sopenharmony_ci p = drbd_prepare_command(peer_device, sock); 14708c2ecf20Sopenharmony_ci if (!p) 14718c2ecf20Sopenharmony_ci return -EIO; 14728c2ecf20Sopenharmony_ci p->sector = cpu_to_be64(sector); 14738c2ecf20Sopenharmony_ci p->block_id = ID_SYNCER /* unused */; 14748c2ecf20Sopenharmony_ci p->blksize = cpu_to_be32(size); 14758c2ecf20Sopenharmony_ci return drbd_send_command(peer_device, sock, P_OV_REQUEST, sizeof(*p), NULL, 0); 14768c2ecf20Sopenharmony_ci} 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci/* called on sndtimeo 14798c2ecf20Sopenharmony_ci * returns false if we should retry, 14808c2ecf20Sopenharmony_ci * true if we think connection is dead 14818c2ecf20Sopenharmony_ci */ 14828c2ecf20Sopenharmony_cistatic int we_should_drop_the_connection(struct drbd_connection *connection, struct socket *sock) 14838c2ecf20Sopenharmony_ci{ 14848c2ecf20Sopenharmony_ci int drop_it; 14858c2ecf20Sopenharmony_ci /* long elapsed = (long)(jiffies - device->last_received); */ 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci drop_it = connection->meta.socket == sock 14888c2ecf20Sopenharmony_ci || !connection->ack_receiver.task 14898c2ecf20Sopenharmony_ci || get_t_state(&connection->ack_receiver) != RUNNING 14908c2ecf20Sopenharmony_ci || connection->cstate < C_WF_REPORT_PARAMS; 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci if (drop_it) 14938c2ecf20Sopenharmony_ci return true; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci drop_it = !--connection->ko_count; 14968c2ecf20Sopenharmony_ci if (!drop_it) { 14978c2ecf20Sopenharmony_ci drbd_err(connection, "[%s/%d] sock_sendmsg time expired, ko = %u\n", 14988c2ecf20Sopenharmony_ci current->comm, current->pid, connection->ko_count); 14998c2ecf20Sopenharmony_ci request_ping(connection); 15008c2ecf20Sopenharmony_ci } 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci return drop_it; /* && (device->state == R_PRIMARY) */; 15038c2ecf20Sopenharmony_ci} 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_cistatic void drbd_update_congested(struct drbd_connection *connection) 15068c2ecf20Sopenharmony_ci{ 15078c2ecf20Sopenharmony_ci struct sock *sk = connection->data.socket->sk; 15088c2ecf20Sopenharmony_ci if (sk->sk_wmem_queued > sk->sk_sndbuf * 4 / 5) 15098c2ecf20Sopenharmony_ci set_bit(NET_CONGESTED, &connection->flags); 15108c2ecf20Sopenharmony_ci} 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci/* The idea of sendpage seems to be to put some kind of reference 15138c2ecf20Sopenharmony_ci * to the page into the skb, and to hand it over to the NIC. In 15148c2ecf20Sopenharmony_ci * this process get_page() gets called. 15158c2ecf20Sopenharmony_ci * 15168c2ecf20Sopenharmony_ci * As soon as the page was really sent over the network put_page() 15178c2ecf20Sopenharmony_ci * gets called by some part of the network layer. [ NIC driver? ] 15188c2ecf20Sopenharmony_ci * 15198c2ecf20Sopenharmony_ci * [ get_page() / put_page() increment/decrement the count. If count 15208c2ecf20Sopenharmony_ci * reaches 0 the page will be freed. ] 15218c2ecf20Sopenharmony_ci * 15228c2ecf20Sopenharmony_ci * This works nicely with pages from FSs. 15238c2ecf20Sopenharmony_ci * But this means that in protocol A we might signal IO completion too early! 15248c2ecf20Sopenharmony_ci * 15258c2ecf20Sopenharmony_ci * In order not to corrupt data during a resync we must make sure 15268c2ecf20Sopenharmony_ci * that we do not reuse our own buffer pages (EEs) to early, therefore 15278c2ecf20Sopenharmony_ci * we have the net_ee list. 15288c2ecf20Sopenharmony_ci * 15298c2ecf20Sopenharmony_ci * XFS seems to have problems, still, it submits pages with page_count == 0! 15308c2ecf20Sopenharmony_ci * As a workaround, we disable sendpage on pages 15318c2ecf20Sopenharmony_ci * with page_count == 0 or PageSlab. 15328c2ecf20Sopenharmony_ci */ 15338c2ecf20Sopenharmony_cistatic int _drbd_no_send_page(struct drbd_peer_device *peer_device, struct page *page, 15348c2ecf20Sopenharmony_ci int offset, size_t size, unsigned msg_flags) 15358c2ecf20Sopenharmony_ci{ 15368c2ecf20Sopenharmony_ci struct socket *socket; 15378c2ecf20Sopenharmony_ci void *addr; 15388c2ecf20Sopenharmony_ci int err; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci socket = peer_device->connection->data.socket; 15418c2ecf20Sopenharmony_ci addr = kmap(page) + offset; 15428c2ecf20Sopenharmony_ci err = drbd_send_all(peer_device->connection, socket, addr, size, msg_flags); 15438c2ecf20Sopenharmony_ci kunmap(page); 15448c2ecf20Sopenharmony_ci if (!err) 15458c2ecf20Sopenharmony_ci peer_device->device->send_cnt += size >> 9; 15468c2ecf20Sopenharmony_ci return err; 15478c2ecf20Sopenharmony_ci} 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_cistatic int _drbd_send_page(struct drbd_peer_device *peer_device, struct page *page, 15508c2ecf20Sopenharmony_ci int offset, size_t size, unsigned msg_flags) 15518c2ecf20Sopenharmony_ci{ 15528c2ecf20Sopenharmony_ci struct socket *socket = peer_device->connection->data.socket; 15538c2ecf20Sopenharmony_ci int len = size; 15548c2ecf20Sopenharmony_ci int err = -EIO; 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci /* e.g. XFS meta- & log-data is in slab pages, which have a 15578c2ecf20Sopenharmony_ci * page_count of 0 and/or have PageSlab() set. 15588c2ecf20Sopenharmony_ci * we cannot use send_page for those, as that does get_page(); 15598c2ecf20Sopenharmony_ci * put_page(); and would cause either a VM_BUG directly, or 15608c2ecf20Sopenharmony_ci * __page_cache_release a page that would actually still be referenced 15618c2ecf20Sopenharmony_ci * by someone, leading to some obscure delayed Oops somewhere else. */ 15628c2ecf20Sopenharmony_ci if (drbd_disable_sendpage || !sendpage_ok(page)) 15638c2ecf20Sopenharmony_ci return _drbd_no_send_page(peer_device, page, offset, size, msg_flags); 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci msg_flags |= MSG_NOSIGNAL; 15668c2ecf20Sopenharmony_ci drbd_update_congested(peer_device->connection); 15678c2ecf20Sopenharmony_ci do { 15688c2ecf20Sopenharmony_ci int sent; 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci sent = socket->ops->sendpage(socket, page, offset, len, msg_flags); 15718c2ecf20Sopenharmony_ci if (sent <= 0) { 15728c2ecf20Sopenharmony_ci if (sent == -EAGAIN) { 15738c2ecf20Sopenharmony_ci if (we_should_drop_the_connection(peer_device->connection, socket)) 15748c2ecf20Sopenharmony_ci break; 15758c2ecf20Sopenharmony_ci continue; 15768c2ecf20Sopenharmony_ci } 15778c2ecf20Sopenharmony_ci drbd_warn(peer_device->device, "%s: size=%d len=%d sent=%d\n", 15788c2ecf20Sopenharmony_ci __func__, (int)size, len, sent); 15798c2ecf20Sopenharmony_ci if (sent < 0) 15808c2ecf20Sopenharmony_ci err = sent; 15818c2ecf20Sopenharmony_ci break; 15828c2ecf20Sopenharmony_ci } 15838c2ecf20Sopenharmony_ci len -= sent; 15848c2ecf20Sopenharmony_ci offset += sent; 15858c2ecf20Sopenharmony_ci } while (len > 0 /* THINK && device->cstate >= C_CONNECTED*/); 15868c2ecf20Sopenharmony_ci clear_bit(NET_CONGESTED, &peer_device->connection->flags); 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci if (len == 0) { 15898c2ecf20Sopenharmony_ci err = 0; 15908c2ecf20Sopenharmony_ci peer_device->device->send_cnt += size >> 9; 15918c2ecf20Sopenharmony_ci } 15928c2ecf20Sopenharmony_ci return err; 15938c2ecf20Sopenharmony_ci} 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_cistatic int _drbd_send_bio(struct drbd_peer_device *peer_device, struct bio *bio) 15968c2ecf20Sopenharmony_ci{ 15978c2ecf20Sopenharmony_ci struct bio_vec bvec; 15988c2ecf20Sopenharmony_ci struct bvec_iter iter; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci /* hint all but last page with MSG_MORE */ 16018c2ecf20Sopenharmony_ci bio_for_each_segment(bvec, bio, iter) { 16028c2ecf20Sopenharmony_ci int err; 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci err = _drbd_no_send_page(peer_device, bvec.bv_page, 16058c2ecf20Sopenharmony_ci bvec.bv_offset, bvec.bv_len, 16068c2ecf20Sopenharmony_ci bio_iter_last(bvec, iter) 16078c2ecf20Sopenharmony_ci ? 0 : MSG_MORE); 16088c2ecf20Sopenharmony_ci if (err) 16098c2ecf20Sopenharmony_ci return err; 16108c2ecf20Sopenharmony_ci /* REQ_OP_WRITE_SAME has only one segment */ 16118c2ecf20Sopenharmony_ci if (bio_op(bio) == REQ_OP_WRITE_SAME) 16128c2ecf20Sopenharmony_ci break; 16138c2ecf20Sopenharmony_ci } 16148c2ecf20Sopenharmony_ci return 0; 16158c2ecf20Sopenharmony_ci} 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_cistatic int _drbd_send_zc_bio(struct drbd_peer_device *peer_device, struct bio *bio) 16188c2ecf20Sopenharmony_ci{ 16198c2ecf20Sopenharmony_ci struct bio_vec bvec; 16208c2ecf20Sopenharmony_ci struct bvec_iter iter; 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci /* hint all but last page with MSG_MORE */ 16238c2ecf20Sopenharmony_ci bio_for_each_segment(bvec, bio, iter) { 16248c2ecf20Sopenharmony_ci int err; 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci err = _drbd_send_page(peer_device, bvec.bv_page, 16278c2ecf20Sopenharmony_ci bvec.bv_offset, bvec.bv_len, 16288c2ecf20Sopenharmony_ci bio_iter_last(bvec, iter) ? 0 : MSG_MORE); 16298c2ecf20Sopenharmony_ci if (err) 16308c2ecf20Sopenharmony_ci return err; 16318c2ecf20Sopenharmony_ci /* REQ_OP_WRITE_SAME has only one segment */ 16328c2ecf20Sopenharmony_ci if (bio_op(bio) == REQ_OP_WRITE_SAME) 16338c2ecf20Sopenharmony_ci break; 16348c2ecf20Sopenharmony_ci } 16358c2ecf20Sopenharmony_ci return 0; 16368c2ecf20Sopenharmony_ci} 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_cistatic int _drbd_send_zc_ee(struct drbd_peer_device *peer_device, 16398c2ecf20Sopenharmony_ci struct drbd_peer_request *peer_req) 16408c2ecf20Sopenharmony_ci{ 16418c2ecf20Sopenharmony_ci struct page *page = peer_req->pages; 16428c2ecf20Sopenharmony_ci unsigned len = peer_req->i.size; 16438c2ecf20Sopenharmony_ci int err; 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci /* hint all but last page with MSG_MORE */ 16468c2ecf20Sopenharmony_ci page_chain_for_each(page) { 16478c2ecf20Sopenharmony_ci unsigned l = min_t(unsigned, len, PAGE_SIZE); 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci err = _drbd_send_page(peer_device, page, 0, l, 16508c2ecf20Sopenharmony_ci page_chain_next(page) ? MSG_MORE : 0); 16518c2ecf20Sopenharmony_ci if (err) 16528c2ecf20Sopenharmony_ci return err; 16538c2ecf20Sopenharmony_ci len -= l; 16548c2ecf20Sopenharmony_ci } 16558c2ecf20Sopenharmony_ci return 0; 16568c2ecf20Sopenharmony_ci} 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_cistatic u32 bio_flags_to_wire(struct drbd_connection *connection, 16598c2ecf20Sopenharmony_ci struct bio *bio) 16608c2ecf20Sopenharmony_ci{ 16618c2ecf20Sopenharmony_ci if (connection->agreed_pro_version >= 95) 16628c2ecf20Sopenharmony_ci return (bio->bi_opf & REQ_SYNC ? DP_RW_SYNC : 0) | 16638c2ecf20Sopenharmony_ci (bio->bi_opf & REQ_FUA ? DP_FUA : 0) | 16648c2ecf20Sopenharmony_ci (bio->bi_opf & REQ_PREFLUSH ? DP_FLUSH : 0) | 16658c2ecf20Sopenharmony_ci (bio_op(bio) == REQ_OP_WRITE_SAME ? DP_WSAME : 0) | 16668c2ecf20Sopenharmony_ci (bio_op(bio) == REQ_OP_DISCARD ? DP_DISCARD : 0) | 16678c2ecf20Sopenharmony_ci (bio_op(bio) == REQ_OP_WRITE_ZEROES ? 16688c2ecf20Sopenharmony_ci ((connection->agreed_features & DRBD_FF_WZEROES) ? 16698c2ecf20Sopenharmony_ci (DP_ZEROES |(!(bio->bi_opf & REQ_NOUNMAP) ? DP_DISCARD : 0)) 16708c2ecf20Sopenharmony_ci : DP_DISCARD) 16718c2ecf20Sopenharmony_ci : 0); 16728c2ecf20Sopenharmony_ci else 16738c2ecf20Sopenharmony_ci return bio->bi_opf & REQ_SYNC ? DP_RW_SYNC : 0; 16748c2ecf20Sopenharmony_ci} 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci/* Used to send write or TRIM aka REQ_OP_DISCARD requests 16778c2ecf20Sopenharmony_ci * R_PRIMARY -> Peer (P_DATA, P_TRIM) 16788c2ecf20Sopenharmony_ci */ 16798c2ecf20Sopenharmony_ciint drbd_send_dblock(struct drbd_peer_device *peer_device, struct drbd_request *req) 16808c2ecf20Sopenharmony_ci{ 16818c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 16828c2ecf20Sopenharmony_ci struct drbd_socket *sock; 16838c2ecf20Sopenharmony_ci struct p_data *p; 16848c2ecf20Sopenharmony_ci struct p_wsame *wsame = NULL; 16858c2ecf20Sopenharmony_ci void *digest_out; 16868c2ecf20Sopenharmony_ci unsigned int dp_flags = 0; 16878c2ecf20Sopenharmony_ci int digest_size; 16888c2ecf20Sopenharmony_ci int err; 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci sock = &peer_device->connection->data; 16918c2ecf20Sopenharmony_ci p = drbd_prepare_command(peer_device, sock); 16928c2ecf20Sopenharmony_ci digest_size = peer_device->connection->integrity_tfm ? 16938c2ecf20Sopenharmony_ci crypto_shash_digestsize(peer_device->connection->integrity_tfm) : 0; 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci if (!p) 16968c2ecf20Sopenharmony_ci return -EIO; 16978c2ecf20Sopenharmony_ci p->sector = cpu_to_be64(req->i.sector); 16988c2ecf20Sopenharmony_ci p->block_id = (unsigned long)req; 16998c2ecf20Sopenharmony_ci p->seq_num = cpu_to_be32(atomic_inc_return(&device->packet_seq)); 17008c2ecf20Sopenharmony_ci dp_flags = bio_flags_to_wire(peer_device->connection, req->master_bio); 17018c2ecf20Sopenharmony_ci if (device->state.conn >= C_SYNC_SOURCE && 17028c2ecf20Sopenharmony_ci device->state.conn <= C_PAUSED_SYNC_T) 17038c2ecf20Sopenharmony_ci dp_flags |= DP_MAY_SET_IN_SYNC; 17048c2ecf20Sopenharmony_ci if (peer_device->connection->agreed_pro_version >= 100) { 17058c2ecf20Sopenharmony_ci if (req->rq_state & RQ_EXP_RECEIVE_ACK) 17068c2ecf20Sopenharmony_ci dp_flags |= DP_SEND_RECEIVE_ACK; 17078c2ecf20Sopenharmony_ci /* During resync, request an explicit write ack, 17088c2ecf20Sopenharmony_ci * even in protocol != C */ 17098c2ecf20Sopenharmony_ci if (req->rq_state & RQ_EXP_WRITE_ACK 17108c2ecf20Sopenharmony_ci || (dp_flags & DP_MAY_SET_IN_SYNC)) 17118c2ecf20Sopenharmony_ci dp_flags |= DP_SEND_WRITE_ACK; 17128c2ecf20Sopenharmony_ci } 17138c2ecf20Sopenharmony_ci p->dp_flags = cpu_to_be32(dp_flags); 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci if (dp_flags & (DP_DISCARD|DP_ZEROES)) { 17168c2ecf20Sopenharmony_ci enum drbd_packet cmd = (dp_flags & DP_ZEROES) ? P_ZEROES : P_TRIM; 17178c2ecf20Sopenharmony_ci struct p_trim *t = (struct p_trim*)p; 17188c2ecf20Sopenharmony_ci t->size = cpu_to_be32(req->i.size); 17198c2ecf20Sopenharmony_ci err = __send_command(peer_device->connection, device->vnr, sock, cmd, sizeof(*t), NULL, 0); 17208c2ecf20Sopenharmony_ci goto out; 17218c2ecf20Sopenharmony_ci } 17228c2ecf20Sopenharmony_ci if (dp_flags & DP_WSAME) { 17238c2ecf20Sopenharmony_ci /* this will only work if DRBD_FF_WSAME is set AND the 17248c2ecf20Sopenharmony_ci * handshake agreed that all nodes and backend devices are 17258c2ecf20Sopenharmony_ci * WRITE_SAME capable and agree on logical_block_size */ 17268c2ecf20Sopenharmony_ci wsame = (struct p_wsame*)p; 17278c2ecf20Sopenharmony_ci digest_out = wsame + 1; 17288c2ecf20Sopenharmony_ci wsame->size = cpu_to_be32(req->i.size); 17298c2ecf20Sopenharmony_ci } else 17308c2ecf20Sopenharmony_ci digest_out = p + 1; 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci /* our digest is still only over the payload. 17338c2ecf20Sopenharmony_ci * TRIM does not carry any payload. */ 17348c2ecf20Sopenharmony_ci if (digest_size) 17358c2ecf20Sopenharmony_ci drbd_csum_bio(peer_device->connection->integrity_tfm, req->master_bio, digest_out); 17368c2ecf20Sopenharmony_ci if (wsame) { 17378c2ecf20Sopenharmony_ci err = 17388c2ecf20Sopenharmony_ci __send_command(peer_device->connection, device->vnr, sock, P_WSAME, 17398c2ecf20Sopenharmony_ci sizeof(*wsame) + digest_size, NULL, 17408c2ecf20Sopenharmony_ci bio_iovec(req->master_bio).bv_len); 17418c2ecf20Sopenharmony_ci } else 17428c2ecf20Sopenharmony_ci err = 17438c2ecf20Sopenharmony_ci __send_command(peer_device->connection, device->vnr, sock, P_DATA, 17448c2ecf20Sopenharmony_ci sizeof(*p) + digest_size, NULL, req->i.size); 17458c2ecf20Sopenharmony_ci if (!err) { 17468c2ecf20Sopenharmony_ci /* For protocol A, we have to memcpy the payload into 17478c2ecf20Sopenharmony_ci * socket buffers, as we may complete right away 17488c2ecf20Sopenharmony_ci * as soon as we handed it over to tcp, at which point the data 17498c2ecf20Sopenharmony_ci * pages may become invalid. 17508c2ecf20Sopenharmony_ci * 17518c2ecf20Sopenharmony_ci * For data-integrity enabled, we copy it as well, so we can be 17528c2ecf20Sopenharmony_ci * sure that even if the bio pages may still be modified, it 17538c2ecf20Sopenharmony_ci * won't change the data on the wire, thus if the digest checks 17548c2ecf20Sopenharmony_ci * out ok after sending on this side, but does not fit on the 17558c2ecf20Sopenharmony_ci * receiving side, we sure have detected corruption elsewhere. 17568c2ecf20Sopenharmony_ci */ 17578c2ecf20Sopenharmony_ci if (!(req->rq_state & (RQ_EXP_RECEIVE_ACK | RQ_EXP_WRITE_ACK)) || digest_size) 17588c2ecf20Sopenharmony_ci err = _drbd_send_bio(peer_device, req->master_bio); 17598c2ecf20Sopenharmony_ci else 17608c2ecf20Sopenharmony_ci err = _drbd_send_zc_bio(peer_device, req->master_bio); 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci /* double check digest, sometimes buffers have been modified in flight. */ 17638c2ecf20Sopenharmony_ci if (digest_size > 0 && digest_size <= 64) { 17648c2ecf20Sopenharmony_ci /* 64 byte, 512 bit, is the largest digest size 17658c2ecf20Sopenharmony_ci * currently supported in kernel crypto. */ 17668c2ecf20Sopenharmony_ci unsigned char digest[64]; 17678c2ecf20Sopenharmony_ci drbd_csum_bio(peer_device->connection->integrity_tfm, req->master_bio, digest); 17688c2ecf20Sopenharmony_ci if (memcmp(p + 1, digest, digest_size)) { 17698c2ecf20Sopenharmony_ci drbd_warn(device, 17708c2ecf20Sopenharmony_ci "Digest mismatch, buffer modified by upper layers during write: %llus +%u\n", 17718c2ecf20Sopenharmony_ci (unsigned long long)req->i.sector, req->i.size); 17728c2ecf20Sopenharmony_ci } 17738c2ecf20Sopenharmony_ci } /* else if (digest_size > 64) { 17748c2ecf20Sopenharmony_ci ... Be noisy about digest too large ... 17758c2ecf20Sopenharmony_ci } */ 17768c2ecf20Sopenharmony_ci } 17778c2ecf20Sopenharmony_ciout: 17788c2ecf20Sopenharmony_ci mutex_unlock(&sock->mutex); /* locked by drbd_prepare_command() */ 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci return err; 17818c2ecf20Sopenharmony_ci} 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci/* answer packet, used to send data back for read requests: 17848c2ecf20Sopenharmony_ci * Peer -> (diskless) R_PRIMARY (P_DATA_REPLY) 17858c2ecf20Sopenharmony_ci * C_SYNC_SOURCE -> C_SYNC_TARGET (P_RS_DATA_REPLY) 17868c2ecf20Sopenharmony_ci */ 17878c2ecf20Sopenharmony_ciint drbd_send_block(struct drbd_peer_device *peer_device, enum drbd_packet cmd, 17888c2ecf20Sopenharmony_ci struct drbd_peer_request *peer_req) 17898c2ecf20Sopenharmony_ci{ 17908c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 17918c2ecf20Sopenharmony_ci struct drbd_socket *sock; 17928c2ecf20Sopenharmony_ci struct p_data *p; 17938c2ecf20Sopenharmony_ci int err; 17948c2ecf20Sopenharmony_ci int digest_size; 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci sock = &peer_device->connection->data; 17978c2ecf20Sopenharmony_ci p = drbd_prepare_command(peer_device, sock); 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci digest_size = peer_device->connection->integrity_tfm ? 18008c2ecf20Sopenharmony_ci crypto_shash_digestsize(peer_device->connection->integrity_tfm) : 0; 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci if (!p) 18038c2ecf20Sopenharmony_ci return -EIO; 18048c2ecf20Sopenharmony_ci p->sector = cpu_to_be64(peer_req->i.sector); 18058c2ecf20Sopenharmony_ci p->block_id = peer_req->block_id; 18068c2ecf20Sopenharmony_ci p->seq_num = 0; /* unused */ 18078c2ecf20Sopenharmony_ci p->dp_flags = 0; 18088c2ecf20Sopenharmony_ci if (digest_size) 18098c2ecf20Sopenharmony_ci drbd_csum_ee(peer_device->connection->integrity_tfm, peer_req, p + 1); 18108c2ecf20Sopenharmony_ci err = __send_command(peer_device->connection, device->vnr, sock, cmd, sizeof(*p) + digest_size, NULL, peer_req->i.size); 18118c2ecf20Sopenharmony_ci if (!err) 18128c2ecf20Sopenharmony_ci err = _drbd_send_zc_ee(peer_device, peer_req); 18138c2ecf20Sopenharmony_ci mutex_unlock(&sock->mutex); /* locked by drbd_prepare_command() */ 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci return err; 18168c2ecf20Sopenharmony_ci} 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ciint drbd_send_out_of_sync(struct drbd_peer_device *peer_device, struct drbd_request *req) 18198c2ecf20Sopenharmony_ci{ 18208c2ecf20Sopenharmony_ci struct drbd_socket *sock; 18218c2ecf20Sopenharmony_ci struct p_block_desc *p; 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci sock = &peer_device->connection->data; 18248c2ecf20Sopenharmony_ci p = drbd_prepare_command(peer_device, sock); 18258c2ecf20Sopenharmony_ci if (!p) 18268c2ecf20Sopenharmony_ci return -EIO; 18278c2ecf20Sopenharmony_ci p->sector = cpu_to_be64(req->i.sector); 18288c2ecf20Sopenharmony_ci p->blksize = cpu_to_be32(req->i.size); 18298c2ecf20Sopenharmony_ci return drbd_send_command(peer_device, sock, P_OUT_OF_SYNC, sizeof(*p), NULL, 0); 18308c2ecf20Sopenharmony_ci} 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci/* 18338c2ecf20Sopenharmony_ci drbd_send distinguishes two cases: 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci Packets sent via the data socket "sock" 18368c2ecf20Sopenharmony_ci and packets sent via the meta data socket "msock" 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci sock msock 18398c2ecf20Sopenharmony_ci -----------------+-------------------------+------------------------------ 18408c2ecf20Sopenharmony_ci timeout conf.timeout / 2 conf.timeout / 2 18418c2ecf20Sopenharmony_ci timeout action send a ping via msock Abort communication 18428c2ecf20Sopenharmony_ci and close all sockets 18438c2ecf20Sopenharmony_ci*/ 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci/* 18468c2ecf20Sopenharmony_ci * you must have down()ed the appropriate [m]sock_mutex elsewhere! 18478c2ecf20Sopenharmony_ci */ 18488c2ecf20Sopenharmony_ciint drbd_send(struct drbd_connection *connection, struct socket *sock, 18498c2ecf20Sopenharmony_ci void *buf, size_t size, unsigned msg_flags) 18508c2ecf20Sopenharmony_ci{ 18518c2ecf20Sopenharmony_ci struct kvec iov = {.iov_base = buf, .iov_len = size}; 18528c2ecf20Sopenharmony_ci struct msghdr msg = {.msg_flags = msg_flags | MSG_NOSIGNAL}; 18538c2ecf20Sopenharmony_ci int rv, sent = 0; 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci if (!sock) 18568c2ecf20Sopenharmony_ci return -EBADR; 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci /* THINK if (signal_pending) return ... ? */ 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci iov_iter_kvec(&msg.msg_iter, WRITE, &iov, 1, size); 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci if (sock == connection->data.socket) { 18638c2ecf20Sopenharmony_ci rcu_read_lock(); 18648c2ecf20Sopenharmony_ci connection->ko_count = rcu_dereference(connection->net_conf)->ko_count; 18658c2ecf20Sopenharmony_ci rcu_read_unlock(); 18668c2ecf20Sopenharmony_ci drbd_update_congested(connection); 18678c2ecf20Sopenharmony_ci } 18688c2ecf20Sopenharmony_ci do { 18698c2ecf20Sopenharmony_ci rv = sock_sendmsg(sock, &msg); 18708c2ecf20Sopenharmony_ci if (rv == -EAGAIN) { 18718c2ecf20Sopenharmony_ci if (we_should_drop_the_connection(connection, sock)) 18728c2ecf20Sopenharmony_ci break; 18738c2ecf20Sopenharmony_ci else 18748c2ecf20Sopenharmony_ci continue; 18758c2ecf20Sopenharmony_ci } 18768c2ecf20Sopenharmony_ci if (rv == -EINTR) { 18778c2ecf20Sopenharmony_ci flush_signals(current); 18788c2ecf20Sopenharmony_ci rv = 0; 18798c2ecf20Sopenharmony_ci } 18808c2ecf20Sopenharmony_ci if (rv < 0) 18818c2ecf20Sopenharmony_ci break; 18828c2ecf20Sopenharmony_ci sent += rv; 18838c2ecf20Sopenharmony_ci } while (sent < size); 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci if (sock == connection->data.socket) 18868c2ecf20Sopenharmony_ci clear_bit(NET_CONGESTED, &connection->flags); 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci if (rv <= 0) { 18898c2ecf20Sopenharmony_ci if (rv != -EAGAIN) { 18908c2ecf20Sopenharmony_ci drbd_err(connection, "%s_sendmsg returned %d\n", 18918c2ecf20Sopenharmony_ci sock == connection->meta.socket ? "msock" : "sock", 18928c2ecf20Sopenharmony_ci rv); 18938c2ecf20Sopenharmony_ci conn_request_state(connection, NS(conn, C_BROKEN_PIPE), CS_HARD); 18948c2ecf20Sopenharmony_ci } else 18958c2ecf20Sopenharmony_ci conn_request_state(connection, NS(conn, C_TIMEOUT), CS_HARD); 18968c2ecf20Sopenharmony_ci } 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_ci return sent; 18998c2ecf20Sopenharmony_ci} 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci/** 19028c2ecf20Sopenharmony_ci * drbd_send_all - Send an entire buffer 19038c2ecf20Sopenharmony_ci * 19048c2ecf20Sopenharmony_ci * Returns 0 upon success and a negative error value otherwise. 19058c2ecf20Sopenharmony_ci */ 19068c2ecf20Sopenharmony_ciint drbd_send_all(struct drbd_connection *connection, struct socket *sock, void *buffer, 19078c2ecf20Sopenharmony_ci size_t size, unsigned msg_flags) 19088c2ecf20Sopenharmony_ci{ 19098c2ecf20Sopenharmony_ci int err; 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci err = drbd_send(connection, sock, buffer, size, msg_flags); 19128c2ecf20Sopenharmony_ci if (err < 0) 19138c2ecf20Sopenharmony_ci return err; 19148c2ecf20Sopenharmony_ci if (err != size) 19158c2ecf20Sopenharmony_ci return -EIO; 19168c2ecf20Sopenharmony_ci return 0; 19178c2ecf20Sopenharmony_ci} 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_cistatic int drbd_open(struct block_device *bdev, fmode_t mode) 19208c2ecf20Sopenharmony_ci{ 19218c2ecf20Sopenharmony_ci struct drbd_device *device = bdev->bd_disk->private_data; 19228c2ecf20Sopenharmony_ci unsigned long flags; 19238c2ecf20Sopenharmony_ci int rv = 0; 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci mutex_lock(&drbd_main_mutex); 19268c2ecf20Sopenharmony_ci spin_lock_irqsave(&device->resource->req_lock, flags); 19278c2ecf20Sopenharmony_ci /* to have a stable device->state.role 19288c2ecf20Sopenharmony_ci * and no race with updating open_cnt */ 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci if (device->state.role != R_PRIMARY) { 19318c2ecf20Sopenharmony_ci if (mode & FMODE_WRITE) 19328c2ecf20Sopenharmony_ci rv = -EROFS; 19338c2ecf20Sopenharmony_ci else if (!drbd_allow_oos) 19348c2ecf20Sopenharmony_ci rv = -EMEDIUMTYPE; 19358c2ecf20Sopenharmony_ci } 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci if (!rv) 19388c2ecf20Sopenharmony_ci device->open_cnt++; 19398c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&device->resource->req_lock, flags); 19408c2ecf20Sopenharmony_ci mutex_unlock(&drbd_main_mutex); 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci return rv; 19438c2ecf20Sopenharmony_ci} 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_cistatic void drbd_release(struct gendisk *gd, fmode_t mode) 19468c2ecf20Sopenharmony_ci{ 19478c2ecf20Sopenharmony_ci struct drbd_device *device = gd->private_data; 19488c2ecf20Sopenharmony_ci mutex_lock(&drbd_main_mutex); 19498c2ecf20Sopenharmony_ci device->open_cnt--; 19508c2ecf20Sopenharmony_ci mutex_unlock(&drbd_main_mutex); 19518c2ecf20Sopenharmony_ci} 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci/* need to hold resource->req_lock */ 19548c2ecf20Sopenharmony_civoid drbd_queue_unplug(struct drbd_device *device) 19558c2ecf20Sopenharmony_ci{ 19568c2ecf20Sopenharmony_ci if (device->state.pdsk >= D_INCONSISTENT && device->state.conn >= C_CONNECTED) { 19578c2ecf20Sopenharmony_ci D_ASSERT(device, device->state.role == R_PRIMARY); 19588c2ecf20Sopenharmony_ci if (test_and_clear_bit(UNPLUG_REMOTE, &device->flags)) { 19598c2ecf20Sopenharmony_ci drbd_queue_work_if_unqueued( 19608c2ecf20Sopenharmony_ci &first_peer_device(device)->connection->sender_work, 19618c2ecf20Sopenharmony_ci &device->unplug_work); 19628c2ecf20Sopenharmony_ci } 19638c2ecf20Sopenharmony_ci } 19648c2ecf20Sopenharmony_ci} 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_cistatic void drbd_set_defaults(struct drbd_device *device) 19678c2ecf20Sopenharmony_ci{ 19688c2ecf20Sopenharmony_ci /* Beware! The actual layout differs 19698c2ecf20Sopenharmony_ci * between big endian and little endian */ 19708c2ecf20Sopenharmony_ci device->state = (union drbd_dev_state) { 19718c2ecf20Sopenharmony_ci { .role = R_SECONDARY, 19728c2ecf20Sopenharmony_ci .peer = R_UNKNOWN, 19738c2ecf20Sopenharmony_ci .conn = C_STANDALONE, 19748c2ecf20Sopenharmony_ci .disk = D_DISKLESS, 19758c2ecf20Sopenharmony_ci .pdsk = D_UNKNOWN, 19768c2ecf20Sopenharmony_ci } }; 19778c2ecf20Sopenharmony_ci} 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_civoid drbd_init_set_defaults(struct drbd_device *device) 19808c2ecf20Sopenharmony_ci{ 19818c2ecf20Sopenharmony_ci /* the memset(,0,) did most of this. 19828c2ecf20Sopenharmony_ci * note: only assignments, no allocation in here */ 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci drbd_set_defaults(device); 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci atomic_set(&device->ap_bio_cnt, 0); 19878c2ecf20Sopenharmony_ci atomic_set(&device->ap_actlog_cnt, 0); 19888c2ecf20Sopenharmony_ci atomic_set(&device->ap_pending_cnt, 0); 19898c2ecf20Sopenharmony_ci atomic_set(&device->rs_pending_cnt, 0); 19908c2ecf20Sopenharmony_ci atomic_set(&device->unacked_cnt, 0); 19918c2ecf20Sopenharmony_ci atomic_set(&device->local_cnt, 0); 19928c2ecf20Sopenharmony_ci atomic_set(&device->pp_in_use_by_net, 0); 19938c2ecf20Sopenharmony_ci atomic_set(&device->rs_sect_in, 0); 19948c2ecf20Sopenharmony_ci atomic_set(&device->rs_sect_ev, 0); 19958c2ecf20Sopenharmony_ci atomic_set(&device->ap_in_flight, 0); 19968c2ecf20Sopenharmony_ci atomic_set(&device->md_io.in_use, 0); 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci mutex_init(&device->own_state_mutex); 19998c2ecf20Sopenharmony_ci device->state_mutex = &device->own_state_mutex; 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_ci spin_lock_init(&device->al_lock); 20028c2ecf20Sopenharmony_ci spin_lock_init(&device->peer_seq_lock); 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->active_ee); 20058c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->sync_ee); 20068c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->done_ee); 20078c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->read_ee); 20088c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->net_ee); 20098c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->resync_reads); 20108c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->resync_work.list); 20118c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->unplug_work.list); 20128c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->bm_io_work.w.list); 20138c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->pending_master_completion[0]); 20148c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->pending_master_completion[1]); 20158c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->pending_completion[0]); 20168c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->pending_completion[1]); 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci device->resync_work.cb = w_resync_timer; 20198c2ecf20Sopenharmony_ci device->unplug_work.cb = w_send_write_hint; 20208c2ecf20Sopenharmony_ci device->bm_io_work.w.cb = w_bitmap_io; 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci timer_setup(&device->resync_timer, resync_timer_fn, 0); 20238c2ecf20Sopenharmony_ci timer_setup(&device->md_sync_timer, md_sync_timer_fn, 0); 20248c2ecf20Sopenharmony_ci timer_setup(&device->start_resync_timer, start_resync_timer_fn, 0); 20258c2ecf20Sopenharmony_ci timer_setup(&device->request_timer, request_timer_fn, 0); 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci init_waitqueue_head(&device->misc_wait); 20288c2ecf20Sopenharmony_ci init_waitqueue_head(&device->state_wait); 20298c2ecf20Sopenharmony_ci init_waitqueue_head(&device->ee_wait); 20308c2ecf20Sopenharmony_ci init_waitqueue_head(&device->al_wait); 20318c2ecf20Sopenharmony_ci init_waitqueue_head(&device->seq_wait); 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci device->resync_wenr = LC_FREE; 20348c2ecf20Sopenharmony_ci device->peer_max_bio_size = DRBD_MAX_BIO_SIZE_SAFE; 20358c2ecf20Sopenharmony_ci device->local_max_bio_size = DRBD_MAX_BIO_SIZE_SAFE; 20368c2ecf20Sopenharmony_ci} 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_civoid drbd_set_my_capacity(struct drbd_device *device, sector_t size) 20398c2ecf20Sopenharmony_ci{ 20408c2ecf20Sopenharmony_ci char ppb[10]; 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci set_capacity(device->vdisk, size); 20438c2ecf20Sopenharmony_ci revalidate_disk_size(device->vdisk, false); 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci drbd_info(device, "size = %s (%llu KB)\n", 20468c2ecf20Sopenharmony_ci ppsize(ppb, size>>1), (unsigned long long)size>>1); 20478c2ecf20Sopenharmony_ci} 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_civoid drbd_device_cleanup(struct drbd_device *device) 20508c2ecf20Sopenharmony_ci{ 20518c2ecf20Sopenharmony_ci int i; 20528c2ecf20Sopenharmony_ci if (first_peer_device(device)->connection->receiver.t_state != NONE) 20538c2ecf20Sopenharmony_ci drbd_err(device, "ASSERT FAILED: receiver t_state == %d expected 0.\n", 20548c2ecf20Sopenharmony_ci first_peer_device(device)->connection->receiver.t_state); 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci device->al_writ_cnt = 20578c2ecf20Sopenharmony_ci device->bm_writ_cnt = 20588c2ecf20Sopenharmony_ci device->read_cnt = 20598c2ecf20Sopenharmony_ci device->recv_cnt = 20608c2ecf20Sopenharmony_ci device->send_cnt = 20618c2ecf20Sopenharmony_ci device->writ_cnt = 20628c2ecf20Sopenharmony_ci device->p_size = 20638c2ecf20Sopenharmony_ci device->rs_start = 20648c2ecf20Sopenharmony_ci device->rs_total = 20658c2ecf20Sopenharmony_ci device->rs_failed = 0; 20668c2ecf20Sopenharmony_ci device->rs_last_events = 0; 20678c2ecf20Sopenharmony_ci device->rs_last_sect_ev = 0; 20688c2ecf20Sopenharmony_ci for (i = 0; i < DRBD_SYNC_MARKS; i++) { 20698c2ecf20Sopenharmony_ci device->rs_mark_left[i] = 0; 20708c2ecf20Sopenharmony_ci device->rs_mark_time[i] = 0; 20718c2ecf20Sopenharmony_ci } 20728c2ecf20Sopenharmony_ci D_ASSERT(device, first_peer_device(device)->connection->net_conf == NULL); 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci set_capacity(device->vdisk, 0); 20758c2ecf20Sopenharmony_ci revalidate_disk_size(device->vdisk, false); 20768c2ecf20Sopenharmony_ci if (device->bitmap) { 20778c2ecf20Sopenharmony_ci /* maybe never allocated. */ 20788c2ecf20Sopenharmony_ci drbd_bm_resize(device, 0, 1); 20798c2ecf20Sopenharmony_ci drbd_bm_cleanup(device); 20808c2ecf20Sopenharmony_ci } 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci drbd_backing_dev_free(device, device->ldev); 20838c2ecf20Sopenharmony_ci device->ldev = NULL; 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci clear_bit(AL_SUSPENDED, &device->flags); 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci D_ASSERT(device, list_empty(&device->active_ee)); 20888c2ecf20Sopenharmony_ci D_ASSERT(device, list_empty(&device->sync_ee)); 20898c2ecf20Sopenharmony_ci D_ASSERT(device, list_empty(&device->done_ee)); 20908c2ecf20Sopenharmony_ci D_ASSERT(device, list_empty(&device->read_ee)); 20918c2ecf20Sopenharmony_ci D_ASSERT(device, list_empty(&device->net_ee)); 20928c2ecf20Sopenharmony_ci D_ASSERT(device, list_empty(&device->resync_reads)); 20938c2ecf20Sopenharmony_ci D_ASSERT(device, list_empty(&first_peer_device(device)->connection->sender_work.q)); 20948c2ecf20Sopenharmony_ci D_ASSERT(device, list_empty(&device->resync_work.list)); 20958c2ecf20Sopenharmony_ci D_ASSERT(device, list_empty(&device->unplug_work.list)); 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci drbd_set_defaults(device); 20988c2ecf20Sopenharmony_ci} 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_cistatic void drbd_destroy_mempools(void) 21028c2ecf20Sopenharmony_ci{ 21038c2ecf20Sopenharmony_ci struct page *page; 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci while (drbd_pp_pool) { 21068c2ecf20Sopenharmony_ci page = drbd_pp_pool; 21078c2ecf20Sopenharmony_ci drbd_pp_pool = (struct page *)page_private(page); 21088c2ecf20Sopenharmony_ci __free_page(page); 21098c2ecf20Sopenharmony_ci drbd_pp_vacant--; 21108c2ecf20Sopenharmony_ci } 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci /* D_ASSERT(device, atomic_read(&drbd_pp_vacant)==0); */ 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci bioset_exit(&drbd_io_bio_set); 21158c2ecf20Sopenharmony_ci bioset_exit(&drbd_md_io_bio_set); 21168c2ecf20Sopenharmony_ci mempool_exit(&drbd_md_io_page_pool); 21178c2ecf20Sopenharmony_ci mempool_exit(&drbd_ee_mempool); 21188c2ecf20Sopenharmony_ci mempool_exit(&drbd_request_mempool); 21198c2ecf20Sopenharmony_ci kmem_cache_destroy(drbd_ee_cache); 21208c2ecf20Sopenharmony_ci kmem_cache_destroy(drbd_request_cache); 21218c2ecf20Sopenharmony_ci kmem_cache_destroy(drbd_bm_ext_cache); 21228c2ecf20Sopenharmony_ci kmem_cache_destroy(drbd_al_ext_cache); 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci drbd_ee_cache = NULL; 21258c2ecf20Sopenharmony_ci drbd_request_cache = NULL; 21268c2ecf20Sopenharmony_ci drbd_bm_ext_cache = NULL; 21278c2ecf20Sopenharmony_ci drbd_al_ext_cache = NULL; 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci return; 21308c2ecf20Sopenharmony_ci} 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_cistatic int drbd_create_mempools(void) 21338c2ecf20Sopenharmony_ci{ 21348c2ecf20Sopenharmony_ci struct page *page; 21358c2ecf20Sopenharmony_ci const int number = (DRBD_MAX_BIO_SIZE/PAGE_SIZE) * drbd_minor_count; 21368c2ecf20Sopenharmony_ci int i, ret; 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci /* caches */ 21398c2ecf20Sopenharmony_ci drbd_request_cache = kmem_cache_create( 21408c2ecf20Sopenharmony_ci "drbd_req", sizeof(struct drbd_request), 0, 0, NULL); 21418c2ecf20Sopenharmony_ci if (drbd_request_cache == NULL) 21428c2ecf20Sopenharmony_ci goto Enomem; 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci drbd_ee_cache = kmem_cache_create( 21458c2ecf20Sopenharmony_ci "drbd_ee", sizeof(struct drbd_peer_request), 0, 0, NULL); 21468c2ecf20Sopenharmony_ci if (drbd_ee_cache == NULL) 21478c2ecf20Sopenharmony_ci goto Enomem; 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_ci drbd_bm_ext_cache = kmem_cache_create( 21508c2ecf20Sopenharmony_ci "drbd_bm", sizeof(struct bm_extent), 0, 0, NULL); 21518c2ecf20Sopenharmony_ci if (drbd_bm_ext_cache == NULL) 21528c2ecf20Sopenharmony_ci goto Enomem; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci drbd_al_ext_cache = kmem_cache_create( 21558c2ecf20Sopenharmony_ci "drbd_al", sizeof(struct lc_element), 0, 0, NULL); 21568c2ecf20Sopenharmony_ci if (drbd_al_ext_cache == NULL) 21578c2ecf20Sopenharmony_ci goto Enomem; 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci /* mempools */ 21608c2ecf20Sopenharmony_ci ret = bioset_init(&drbd_io_bio_set, BIO_POOL_SIZE, 0, 0); 21618c2ecf20Sopenharmony_ci if (ret) 21628c2ecf20Sopenharmony_ci goto Enomem; 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci ret = bioset_init(&drbd_md_io_bio_set, DRBD_MIN_POOL_PAGES, 0, 21658c2ecf20Sopenharmony_ci BIOSET_NEED_BVECS); 21668c2ecf20Sopenharmony_ci if (ret) 21678c2ecf20Sopenharmony_ci goto Enomem; 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci ret = mempool_init_page_pool(&drbd_md_io_page_pool, DRBD_MIN_POOL_PAGES, 0); 21708c2ecf20Sopenharmony_ci if (ret) 21718c2ecf20Sopenharmony_ci goto Enomem; 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci ret = mempool_init_slab_pool(&drbd_request_mempool, number, 21748c2ecf20Sopenharmony_ci drbd_request_cache); 21758c2ecf20Sopenharmony_ci if (ret) 21768c2ecf20Sopenharmony_ci goto Enomem; 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci ret = mempool_init_slab_pool(&drbd_ee_mempool, number, drbd_ee_cache); 21798c2ecf20Sopenharmony_ci if (ret) 21808c2ecf20Sopenharmony_ci goto Enomem; 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci /* drbd's page pool */ 21838c2ecf20Sopenharmony_ci spin_lock_init(&drbd_pp_lock); 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci for (i = 0; i < number; i++) { 21868c2ecf20Sopenharmony_ci page = alloc_page(GFP_HIGHUSER); 21878c2ecf20Sopenharmony_ci if (!page) 21888c2ecf20Sopenharmony_ci goto Enomem; 21898c2ecf20Sopenharmony_ci set_page_private(page, (unsigned long)drbd_pp_pool); 21908c2ecf20Sopenharmony_ci drbd_pp_pool = page; 21918c2ecf20Sopenharmony_ci } 21928c2ecf20Sopenharmony_ci drbd_pp_vacant = number; 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_ci return 0; 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_ciEnomem: 21978c2ecf20Sopenharmony_ci drbd_destroy_mempools(); /* in case we allocated some */ 21988c2ecf20Sopenharmony_ci return -ENOMEM; 21998c2ecf20Sopenharmony_ci} 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_cistatic void drbd_release_all_peer_reqs(struct drbd_device *device) 22028c2ecf20Sopenharmony_ci{ 22038c2ecf20Sopenharmony_ci int rr; 22048c2ecf20Sopenharmony_ci 22058c2ecf20Sopenharmony_ci rr = drbd_free_peer_reqs(device, &device->active_ee); 22068c2ecf20Sopenharmony_ci if (rr) 22078c2ecf20Sopenharmony_ci drbd_err(device, "%d EEs in active list found!\n", rr); 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci rr = drbd_free_peer_reqs(device, &device->sync_ee); 22108c2ecf20Sopenharmony_ci if (rr) 22118c2ecf20Sopenharmony_ci drbd_err(device, "%d EEs in sync list found!\n", rr); 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_ci rr = drbd_free_peer_reqs(device, &device->read_ee); 22148c2ecf20Sopenharmony_ci if (rr) 22158c2ecf20Sopenharmony_ci drbd_err(device, "%d EEs in read list found!\n", rr); 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci rr = drbd_free_peer_reqs(device, &device->done_ee); 22188c2ecf20Sopenharmony_ci if (rr) 22198c2ecf20Sopenharmony_ci drbd_err(device, "%d EEs in done list found!\n", rr); 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci rr = drbd_free_peer_reqs(device, &device->net_ee); 22228c2ecf20Sopenharmony_ci if (rr) 22238c2ecf20Sopenharmony_ci drbd_err(device, "%d EEs in net list found!\n", rr); 22248c2ecf20Sopenharmony_ci} 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci/* caution. no locking. */ 22278c2ecf20Sopenharmony_civoid drbd_destroy_device(struct kref *kref) 22288c2ecf20Sopenharmony_ci{ 22298c2ecf20Sopenharmony_ci struct drbd_device *device = container_of(kref, struct drbd_device, kref); 22308c2ecf20Sopenharmony_ci struct drbd_resource *resource = device->resource; 22318c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device, *tmp_peer_device; 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_ci del_timer_sync(&device->request_timer); 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_ci /* paranoia asserts */ 22368c2ecf20Sopenharmony_ci D_ASSERT(device, device->open_cnt == 0); 22378c2ecf20Sopenharmony_ci /* end paranoia asserts */ 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci /* cleanup stuff that may have been allocated during 22408c2ecf20Sopenharmony_ci * device (re-)configuration or state changes */ 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci drbd_backing_dev_free(device, device->ldev); 22438c2ecf20Sopenharmony_ci device->ldev = NULL; 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci drbd_release_all_peer_reqs(device); 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci lc_destroy(device->act_log); 22488c2ecf20Sopenharmony_ci lc_destroy(device->resync); 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_ci kfree(device->p_uuid); 22518c2ecf20Sopenharmony_ci /* device->p_uuid = NULL; */ 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_ci if (device->bitmap) /* should no longer be there. */ 22548c2ecf20Sopenharmony_ci drbd_bm_cleanup(device); 22558c2ecf20Sopenharmony_ci __free_page(device->md_io.page); 22568c2ecf20Sopenharmony_ci put_disk(device->vdisk); 22578c2ecf20Sopenharmony_ci blk_cleanup_queue(device->rq_queue); 22588c2ecf20Sopenharmony_ci kfree(device->rs_plan_s); 22598c2ecf20Sopenharmony_ci 22608c2ecf20Sopenharmony_ci /* not for_each_connection(connection, resource): 22618c2ecf20Sopenharmony_ci * those may have been cleaned up and disassociated already. 22628c2ecf20Sopenharmony_ci */ 22638c2ecf20Sopenharmony_ci for_each_peer_device_safe(peer_device, tmp_peer_device, device) { 22648c2ecf20Sopenharmony_ci kref_put(&peer_device->connection->kref, drbd_destroy_connection); 22658c2ecf20Sopenharmony_ci kfree(peer_device); 22668c2ecf20Sopenharmony_ci } 22678c2ecf20Sopenharmony_ci memset(device, 0xfd, sizeof(*device)); 22688c2ecf20Sopenharmony_ci kfree(device); 22698c2ecf20Sopenharmony_ci kref_put(&resource->kref, drbd_destroy_resource); 22708c2ecf20Sopenharmony_ci} 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci/* One global retry thread, if we need to push back some bio and have it 22738c2ecf20Sopenharmony_ci * reinserted through our make request function. 22748c2ecf20Sopenharmony_ci */ 22758c2ecf20Sopenharmony_cistatic struct retry_worker { 22768c2ecf20Sopenharmony_ci struct workqueue_struct *wq; 22778c2ecf20Sopenharmony_ci struct work_struct worker; 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci spinlock_t lock; 22808c2ecf20Sopenharmony_ci struct list_head writes; 22818c2ecf20Sopenharmony_ci} retry; 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_cistatic void do_retry(struct work_struct *ws) 22848c2ecf20Sopenharmony_ci{ 22858c2ecf20Sopenharmony_ci struct retry_worker *retry = container_of(ws, struct retry_worker, worker); 22868c2ecf20Sopenharmony_ci LIST_HEAD(writes); 22878c2ecf20Sopenharmony_ci struct drbd_request *req, *tmp; 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci spin_lock_irq(&retry->lock); 22908c2ecf20Sopenharmony_ci list_splice_init(&retry->writes, &writes); 22918c2ecf20Sopenharmony_ci spin_unlock_irq(&retry->lock); 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_ci list_for_each_entry_safe(req, tmp, &writes, tl_requests) { 22948c2ecf20Sopenharmony_ci struct drbd_device *device = req->device; 22958c2ecf20Sopenharmony_ci struct bio *bio = req->master_bio; 22968c2ecf20Sopenharmony_ci unsigned long start_jif = req->start_jif; 22978c2ecf20Sopenharmony_ci bool expected; 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci expected = 23008c2ecf20Sopenharmony_ci expect(atomic_read(&req->completion_ref) == 0) && 23018c2ecf20Sopenharmony_ci expect(req->rq_state & RQ_POSTPONED) && 23028c2ecf20Sopenharmony_ci expect((req->rq_state & RQ_LOCAL_PENDING) == 0 || 23038c2ecf20Sopenharmony_ci (req->rq_state & RQ_LOCAL_ABORTED) != 0); 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci if (!expected) 23068c2ecf20Sopenharmony_ci drbd_err(device, "req=%p completion_ref=%d rq_state=%x\n", 23078c2ecf20Sopenharmony_ci req, atomic_read(&req->completion_ref), 23088c2ecf20Sopenharmony_ci req->rq_state); 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci /* We still need to put one kref associated with the 23118c2ecf20Sopenharmony_ci * "completion_ref" going zero in the code path that queued it 23128c2ecf20Sopenharmony_ci * here. The request object may still be referenced by a 23138c2ecf20Sopenharmony_ci * frozen local req->private_bio, in case we force-detached. 23148c2ecf20Sopenharmony_ci */ 23158c2ecf20Sopenharmony_ci kref_put(&req->kref, drbd_req_destroy); 23168c2ecf20Sopenharmony_ci 23178c2ecf20Sopenharmony_ci /* A single suspended or otherwise blocking device may stall 23188c2ecf20Sopenharmony_ci * all others as well. Fortunately, this code path is to 23198c2ecf20Sopenharmony_ci * recover from a situation that "should not happen": 23208c2ecf20Sopenharmony_ci * concurrent writes in multi-primary setup. 23218c2ecf20Sopenharmony_ci * In a "normal" lifecycle, this workqueue is supposed to be 23228c2ecf20Sopenharmony_ci * destroyed without ever doing anything. 23238c2ecf20Sopenharmony_ci * If it turns out to be an issue anyways, we can do per 23248c2ecf20Sopenharmony_ci * resource (replication group) or per device (minor) retry 23258c2ecf20Sopenharmony_ci * workqueues instead. 23268c2ecf20Sopenharmony_ci */ 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_ci /* We are not just doing submit_bio_noacct(), 23298c2ecf20Sopenharmony_ci * as we want to keep the start_time information. */ 23308c2ecf20Sopenharmony_ci inc_ap_bio(device); 23318c2ecf20Sopenharmony_ci __drbd_make_request(device, bio, start_jif); 23328c2ecf20Sopenharmony_ci } 23338c2ecf20Sopenharmony_ci} 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_ci/* called via drbd_req_put_completion_ref(), 23368c2ecf20Sopenharmony_ci * holds resource->req_lock */ 23378c2ecf20Sopenharmony_civoid drbd_restart_request(struct drbd_request *req) 23388c2ecf20Sopenharmony_ci{ 23398c2ecf20Sopenharmony_ci unsigned long flags; 23408c2ecf20Sopenharmony_ci spin_lock_irqsave(&retry.lock, flags); 23418c2ecf20Sopenharmony_ci list_move_tail(&req->tl_requests, &retry.writes); 23428c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&retry.lock, flags); 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci /* Drop the extra reference that would otherwise 23458c2ecf20Sopenharmony_ci * have been dropped by complete_master_bio. 23468c2ecf20Sopenharmony_ci * do_retry() needs to grab a new one. */ 23478c2ecf20Sopenharmony_ci dec_ap_bio(req->device); 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci queue_work(retry.wq, &retry.worker); 23508c2ecf20Sopenharmony_ci} 23518c2ecf20Sopenharmony_ci 23528c2ecf20Sopenharmony_civoid drbd_destroy_resource(struct kref *kref) 23538c2ecf20Sopenharmony_ci{ 23548c2ecf20Sopenharmony_ci struct drbd_resource *resource = 23558c2ecf20Sopenharmony_ci container_of(kref, struct drbd_resource, kref); 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci idr_destroy(&resource->devices); 23588c2ecf20Sopenharmony_ci free_cpumask_var(resource->cpu_mask); 23598c2ecf20Sopenharmony_ci kfree(resource->name); 23608c2ecf20Sopenharmony_ci memset(resource, 0xf2, sizeof(*resource)); 23618c2ecf20Sopenharmony_ci kfree(resource); 23628c2ecf20Sopenharmony_ci} 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_civoid drbd_free_resource(struct drbd_resource *resource) 23658c2ecf20Sopenharmony_ci{ 23668c2ecf20Sopenharmony_ci struct drbd_connection *connection, *tmp; 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci for_each_connection_safe(connection, tmp, resource) { 23698c2ecf20Sopenharmony_ci list_del(&connection->connections); 23708c2ecf20Sopenharmony_ci drbd_debugfs_connection_cleanup(connection); 23718c2ecf20Sopenharmony_ci kref_put(&connection->kref, drbd_destroy_connection); 23728c2ecf20Sopenharmony_ci } 23738c2ecf20Sopenharmony_ci drbd_debugfs_resource_cleanup(resource); 23748c2ecf20Sopenharmony_ci kref_put(&resource->kref, drbd_destroy_resource); 23758c2ecf20Sopenharmony_ci} 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_cistatic void drbd_cleanup(void) 23788c2ecf20Sopenharmony_ci{ 23798c2ecf20Sopenharmony_ci unsigned int i; 23808c2ecf20Sopenharmony_ci struct drbd_device *device; 23818c2ecf20Sopenharmony_ci struct drbd_resource *resource, *tmp; 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci /* first remove proc, 23848c2ecf20Sopenharmony_ci * drbdsetup uses it's presence to detect 23858c2ecf20Sopenharmony_ci * whether DRBD is loaded. 23868c2ecf20Sopenharmony_ci * If we would get stuck in proc removal, 23878c2ecf20Sopenharmony_ci * but have netlink already deregistered, 23888c2ecf20Sopenharmony_ci * some drbdsetup commands may wait forever 23898c2ecf20Sopenharmony_ci * for an answer. 23908c2ecf20Sopenharmony_ci */ 23918c2ecf20Sopenharmony_ci if (drbd_proc) 23928c2ecf20Sopenharmony_ci remove_proc_entry("drbd", NULL); 23938c2ecf20Sopenharmony_ci 23948c2ecf20Sopenharmony_ci if (retry.wq) 23958c2ecf20Sopenharmony_ci destroy_workqueue(retry.wq); 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci drbd_genl_unregister(); 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci idr_for_each_entry(&drbd_devices, device, i) 24008c2ecf20Sopenharmony_ci drbd_delete_device(device); 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci /* not _rcu since, no other updater anymore. Genl already unregistered */ 24038c2ecf20Sopenharmony_ci for_each_resource_safe(resource, tmp, &drbd_resources) { 24048c2ecf20Sopenharmony_ci list_del(&resource->resources); 24058c2ecf20Sopenharmony_ci drbd_free_resource(resource); 24068c2ecf20Sopenharmony_ci } 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci drbd_debugfs_cleanup(); 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci drbd_destroy_mempools(); 24118c2ecf20Sopenharmony_ci unregister_blkdev(DRBD_MAJOR, "drbd"); 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci idr_destroy(&drbd_devices); 24148c2ecf20Sopenharmony_ci 24158c2ecf20Sopenharmony_ci pr_info("module cleanup done.\n"); 24168c2ecf20Sopenharmony_ci} 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_cistatic void drbd_init_workqueue(struct drbd_work_queue* wq) 24198c2ecf20Sopenharmony_ci{ 24208c2ecf20Sopenharmony_ci spin_lock_init(&wq->q_lock); 24218c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&wq->q); 24228c2ecf20Sopenharmony_ci init_waitqueue_head(&wq->q_wait); 24238c2ecf20Sopenharmony_ci} 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_cistruct completion_work { 24268c2ecf20Sopenharmony_ci struct drbd_work w; 24278c2ecf20Sopenharmony_ci struct completion done; 24288c2ecf20Sopenharmony_ci}; 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_cistatic int w_complete(struct drbd_work *w, int cancel) 24318c2ecf20Sopenharmony_ci{ 24328c2ecf20Sopenharmony_ci struct completion_work *completion_work = 24338c2ecf20Sopenharmony_ci container_of(w, struct completion_work, w); 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_ci complete(&completion_work->done); 24368c2ecf20Sopenharmony_ci return 0; 24378c2ecf20Sopenharmony_ci} 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_civoid drbd_flush_workqueue(struct drbd_work_queue *work_queue) 24408c2ecf20Sopenharmony_ci{ 24418c2ecf20Sopenharmony_ci struct completion_work completion_work; 24428c2ecf20Sopenharmony_ci 24438c2ecf20Sopenharmony_ci completion_work.w.cb = w_complete; 24448c2ecf20Sopenharmony_ci init_completion(&completion_work.done); 24458c2ecf20Sopenharmony_ci drbd_queue_work(work_queue, &completion_work.w); 24468c2ecf20Sopenharmony_ci wait_for_completion(&completion_work.done); 24478c2ecf20Sopenharmony_ci} 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_cistruct drbd_resource *drbd_find_resource(const char *name) 24508c2ecf20Sopenharmony_ci{ 24518c2ecf20Sopenharmony_ci struct drbd_resource *resource; 24528c2ecf20Sopenharmony_ci 24538c2ecf20Sopenharmony_ci if (!name || !name[0]) 24548c2ecf20Sopenharmony_ci return NULL; 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci rcu_read_lock(); 24578c2ecf20Sopenharmony_ci for_each_resource_rcu(resource, &drbd_resources) { 24588c2ecf20Sopenharmony_ci if (!strcmp(resource->name, name)) { 24598c2ecf20Sopenharmony_ci kref_get(&resource->kref); 24608c2ecf20Sopenharmony_ci goto found; 24618c2ecf20Sopenharmony_ci } 24628c2ecf20Sopenharmony_ci } 24638c2ecf20Sopenharmony_ci resource = NULL; 24648c2ecf20Sopenharmony_cifound: 24658c2ecf20Sopenharmony_ci rcu_read_unlock(); 24668c2ecf20Sopenharmony_ci return resource; 24678c2ecf20Sopenharmony_ci} 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_cistruct drbd_connection *conn_get_by_addrs(void *my_addr, int my_addr_len, 24708c2ecf20Sopenharmony_ci void *peer_addr, int peer_addr_len) 24718c2ecf20Sopenharmony_ci{ 24728c2ecf20Sopenharmony_ci struct drbd_resource *resource; 24738c2ecf20Sopenharmony_ci struct drbd_connection *connection; 24748c2ecf20Sopenharmony_ci 24758c2ecf20Sopenharmony_ci rcu_read_lock(); 24768c2ecf20Sopenharmony_ci for_each_resource_rcu(resource, &drbd_resources) { 24778c2ecf20Sopenharmony_ci for_each_connection_rcu(connection, resource) { 24788c2ecf20Sopenharmony_ci if (connection->my_addr_len == my_addr_len && 24798c2ecf20Sopenharmony_ci connection->peer_addr_len == peer_addr_len && 24808c2ecf20Sopenharmony_ci !memcmp(&connection->my_addr, my_addr, my_addr_len) && 24818c2ecf20Sopenharmony_ci !memcmp(&connection->peer_addr, peer_addr, peer_addr_len)) { 24828c2ecf20Sopenharmony_ci kref_get(&connection->kref); 24838c2ecf20Sopenharmony_ci goto found; 24848c2ecf20Sopenharmony_ci } 24858c2ecf20Sopenharmony_ci } 24868c2ecf20Sopenharmony_ci } 24878c2ecf20Sopenharmony_ci connection = NULL; 24888c2ecf20Sopenharmony_cifound: 24898c2ecf20Sopenharmony_ci rcu_read_unlock(); 24908c2ecf20Sopenharmony_ci return connection; 24918c2ecf20Sopenharmony_ci} 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_cistatic int drbd_alloc_socket(struct drbd_socket *socket) 24948c2ecf20Sopenharmony_ci{ 24958c2ecf20Sopenharmony_ci socket->rbuf = (void *) __get_free_page(GFP_KERNEL); 24968c2ecf20Sopenharmony_ci if (!socket->rbuf) 24978c2ecf20Sopenharmony_ci return -ENOMEM; 24988c2ecf20Sopenharmony_ci socket->sbuf = (void *) __get_free_page(GFP_KERNEL); 24998c2ecf20Sopenharmony_ci if (!socket->sbuf) 25008c2ecf20Sopenharmony_ci return -ENOMEM; 25018c2ecf20Sopenharmony_ci return 0; 25028c2ecf20Sopenharmony_ci} 25038c2ecf20Sopenharmony_ci 25048c2ecf20Sopenharmony_cistatic void drbd_free_socket(struct drbd_socket *socket) 25058c2ecf20Sopenharmony_ci{ 25068c2ecf20Sopenharmony_ci free_page((unsigned long) socket->sbuf); 25078c2ecf20Sopenharmony_ci free_page((unsigned long) socket->rbuf); 25088c2ecf20Sopenharmony_ci} 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_civoid conn_free_crypto(struct drbd_connection *connection) 25118c2ecf20Sopenharmony_ci{ 25128c2ecf20Sopenharmony_ci drbd_free_sock(connection); 25138c2ecf20Sopenharmony_ci 25148c2ecf20Sopenharmony_ci crypto_free_shash(connection->csums_tfm); 25158c2ecf20Sopenharmony_ci crypto_free_shash(connection->verify_tfm); 25168c2ecf20Sopenharmony_ci crypto_free_shash(connection->cram_hmac_tfm); 25178c2ecf20Sopenharmony_ci crypto_free_shash(connection->integrity_tfm); 25188c2ecf20Sopenharmony_ci crypto_free_shash(connection->peer_integrity_tfm); 25198c2ecf20Sopenharmony_ci kfree(connection->int_dig_in); 25208c2ecf20Sopenharmony_ci kfree(connection->int_dig_vv); 25218c2ecf20Sopenharmony_ci 25228c2ecf20Sopenharmony_ci connection->csums_tfm = NULL; 25238c2ecf20Sopenharmony_ci connection->verify_tfm = NULL; 25248c2ecf20Sopenharmony_ci connection->cram_hmac_tfm = NULL; 25258c2ecf20Sopenharmony_ci connection->integrity_tfm = NULL; 25268c2ecf20Sopenharmony_ci connection->peer_integrity_tfm = NULL; 25278c2ecf20Sopenharmony_ci connection->int_dig_in = NULL; 25288c2ecf20Sopenharmony_ci connection->int_dig_vv = NULL; 25298c2ecf20Sopenharmony_ci} 25308c2ecf20Sopenharmony_ci 25318c2ecf20Sopenharmony_ciint set_resource_options(struct drbd_resource *resource, struct res_opts *res_opts) 25328c2ecf20Sopenharmony_ci{ 25338c2ecf20Sopenharmony_ci struct drbd_connection *connection; 25348c2ecf20Sopenharmony_ci cpumask_var_t new_cpu_mask; 25358c2ecf20Sopenharmony_ci int err; 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_ci if (!zalloc_cpumask_var(&new_cpu_mask, GFP_KERNEL)) 25388c2ecf20Sopenharmony_ci return -ENOMEM; 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci /* silently ignore cpu mask on UP kernel */ 25418c2ecf20Sopenharmony_ci if (nr_cpu_ids > 1 && res_opts->cpu_mask[0] != 0) { 25428c2ecf20Sopenharmony_ci err = bitmap_parse(res_opts->cpu_mask, DRBD_CPU_MASK_SIZE, 25438c2ecf20Sopenharmony_ci cpumask_bits(new_cpu_mask), nr_cpu_ids); 25448c2ecf20Sopenharmony_ci if (err == -EOVERFLOW) { 25458c2ecf20Sopenharmony_ci /* So what. mask it out. */ 25468c2ecf20Sopenharmony_ci cpumask_var_t tmp_cpu_mask; 25478c2ecf20Sopenharmony_ci if (zalloc_cpumask_var(&tmp_cpu_mask, GFP_KERNEL)) { 25488c2ecf20Sopenharmony_ci cpumask_setall(tmp_cpu_mask); 25498c2ecf20Sopenharmony_ci cpumask_and(new_cpu_mask, new_cpu_mask, tmp_cpu_mask); 25508c2ecf20Sopenharmony_ci drbd_warn(resource, "Overflow in bitmap_parse(%.12s%s), truncating to %u bits\n", 25518c2ecf20Sopenharmony_ci res_opts->cpu_mask, 25528c2ecf20Sopenharmony_ci strlen(res_opts->cpu_mask) > 12 ? "..." : "", 25538c2ecf20Sopenharmony_ci nr_cpu_ids); 25548c2ecf20Sopenharmony_ci free_cpumask_var(tmp_cpu_mask); 25558c2ecf20Sopenharmony_ci err = 0; 25568c2ecf20Sopenharmony_ci } 25578c2ecf20Sopenharmony_ci } 25588c2ecf20Sopenharmony_ci if (err) { 25598c2ecf20Sopenharmony_ci drbd_warn(resource, "bitmap_parse() failed with %d\n", err); 25608c2ecf20Sopenharmony_ci /* retcode = ERR_CPU_MASK_PARSE; */ 25618c2ecf20Sopenharmony_ci goto fail; 25628c2ecf20Sopenharmony_ci } 25638c2ecf20Sopenharmony_ci } 25648c2ecf20Sopenharmony_ci resource->res_opts = *res_opts; 25658c2ecf20Sopenharmony_ci if (cpumask_empty(new_cpu_mask)) 25668c2ecf20Sopenharmony_ci drbd_calc_cpu_mask(&new_cpu_mask); 25678c2ecf20Sopenharmony_ci if (!cpumask_equal(resource->cpu_mask, new_cpu_mask)) { 25688c2ecf20Sopenharmony_ci cpumask_copy(resource->cpu_mask, new_cpu_mask); 25698c2ecf20Sopenharmony_ci for_each_connection_rcu(connection, resource) { 25708c2ecf20Sopenharmony_ci connection->receiver.reset_cpu_mask = 1; 25718c2ecf20Sopenharmony_ci connection->ack_receiver.reset_cpu_mask = 1; 25728c2ecf20Sopenharmony_ci connection->worker.reset_cpu_mask = 1; 25738c2ecf20Sopenharmony_ci } 25748c2ecf20Sopenharmony_ci } 25758c2ecf20Sopenharmony_ci err = 0; 25768c2ecf20Sopenharmony_ci 25778c2ecf20Sopenharmony_cifail: 25788c2ecf20Sopenharmony_ci free_cpumask_var(new_cpu_mask); 25798c2ecf20Sopenharmony_ci return err; 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci} 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_cistruct drbd_resource *drbd_create_resource(const char *name) 25848c2ecf20Sopenharmony_ci{ 25858c2ecf20Sopenharmony_ci struct drbd_resource *resource; 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci resource = kzalloc(sizeof(struct drbd_resource), GFP_KERNEL); 25888c2ecf20Sopenharmony_ci if (!resource) 25898c2ecf20Sopenharmony_ci goto fail; 25908c2ecf20Sopenharmony_ci resource->name = kstrdup(name, GFP_KERNEL); 25918c2ecf20Sopenharmony_ci if (!resource->name) 25928c2ecf20Sopenharmony_ci goto fail_free_resource; 25938c2ecf20Sopenharmony_ci if (!zalloc_cpumask_var(&resource->cpu_mask, GFP_KERNEL)) 25948c2ecf20Sopenharmony_ci goto fail_free_name; 25958c2ecf20Sopenharmony_ci kref_init(&resource->kref); 25968c2ecf20Sopenharmony_ci idr_init(&resource->devices); 25978c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&resource->connections); 25988c2ecf20Sopenharmony_ci resource->write_ordering = WO_BDEV_FLUSH; 25998c2ecf20Sopenharmony_ci list_add_tail_rcu(&resource->resources, &drbd_resources); 26008c2ecf20Sopenharmony_ci mutex_init(&resource->conf_update); 26018c2ecf20Sopenharmony_ci mutex_init(&resource->adm_mutex); 26028c2ecf20Sopenharmony_ci spin_lock_init(&resource->req_lock); 26038c2ecf20Sopenharmony_ci drbd_debugfs_resource_add(resource); 26048c2ecf20Sopenharmony_ci return resource; 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_cifail_free_name: 26078c2ecf20Sopenharmony_ci kfree(resource->name); 26088c2ecf20Sopenharmony_cifail_free_resource: 26098c2ecf20Sopenharmony_ci kfree(resource); 26108c2ecf20Sopenharmony_cifail: 26118c2ecf20Sopenharmony_ci return NULL; 26128c2ecf20Sopenharmony_ci} 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci/* caller must be under adm_mutex */ 26158c2ecf20Sopenharmony_cistruct drbd_connection *conn_create(const char *name, struct res_opts *res_opts) 26168c2ecf20Sopenharmony_ci{ 26178c2ecf20Sopenharmony_ci struct drbd_resource *resource; 26188c2ecf20Sopenharmony_ci struct drbd_connection *connection; 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_ci connection = kzalloc(sizeof(struct drbd_connection), GFP_KERNEL); 26218c2ecf20Sopenharmony_ci if (!connection) 26228c2ecf20Sopenharmony_ci return NULL; 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci if (drbd_alloc_socket(&connection->data)) 26258c2ecf20Sopenharmony_ci goto fail; 26268c2ecf20Sopenharmony_ci if (drbd_alloc_socket(&connection->meta)) 26278c2ecf20Sopenharmony_ci goto fail; 26288c2ecf20Sopenharmony_ci 26298c2ecf20Sopenharmony_ci connection->current_epoch = kzalloc(sizeof(struct drbd_epoch), GFP_KERNEL); 26308c2ecf20Sopenharmony_ci if (!connection->current_epoch) 26318c2ecf20Sopenharmony_ci goto fail; 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&connection->transfer_log); 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&connection->current_epoch->list); 26368c2ecf20Sopenharmony_ci connection->epochs = 1; 26378c2ecf20Sopenharmony_ci spin_lock_init(&connection->epoch_lock); 26388c2ecf20Sopenharmony_ci 26398c2ecf20Sopenharmony_ci connection->send.seen_any_write_yet = false; 26408c2ecf20Sopenharmony_ci connection->send.current_epoch_nr = 0; 26418c2ecf20Sopenharmony_ci connection->send.current_epoch_writes = 0; 26428c2ecf20Sopenharmony_ci 26438c2ecf20Sopenharmony_ci resource = drbd_create_resource(name); 26448c2ecf20Sopenharmony_ci if (!resource) 26458c2ecf20Sopenharmony_ci goto fail; 26468c2ecf20Sopenharmony_ci 26478c2ecf20Sopenharmony_ci connection->cstate = C_STANDALONE; 26488c2ecf20Sopenharmony_ci mutex_init(&connection->cstate_mutex); 26498c2ecf20Sopenharmony_ci init_waitqueue_head(&connection->ping_wait); 26508c2ecf20Sopenharmony_ci idr_init(&connection->peer_devices); 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci drbd_init_workqueue(&connection->sender_work); 26538c2ecf20Sopenharmony_ci mutex_init(&connection->data.mutex); 26548c2ecf20Sopenharmony_ci mutex_init(&connection->meta.mutex); 26558c2ecf20Sopenharmony_ci 26568c2ecf20Sopenharmony_ci drbd_thread_init(resource, &connection->receiver, drbd_receiver, "receiver"); 26578c2ecf20Sopenharmony_ci connection->receiver.connection = connection; 26588c2ecf20Sopenharmony_ci drbd_thread_init(resource, &connection->worker, drbd_worker, "worker"); 26598c2ecf20Sopenharmony_ci connection->worker.connection = connection; 26608c2ecf20Sopenharmony_ci drbd_thread_init(resource, &connection->ack_receiver, drbd_ack_receiver, "ack_recv"); 26618c2ecf20Sopenharmony_ci connection->ack_receiver.connection = connection; 26628c2ecf20Sopenharmony_ci 26638c2ecf20Sopenharmony_ci kref_init(&connection->kref); 26648c2ecf20Sopenharmony_ci 26658c2ecf20Sopenharmony_ci connection->resource = resource; 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_ci if (set_resource_options(resource, res_opts)) 26688c2ecf20Sopenharmony_ci goto fail_resource; 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci kref_get(&resource->kref); 26718c2ecf20Sopenharmony_ci list_add_tail_rcu(&connection->connections, &resource->connections); 26728c2ecf20Sopenharmony_ci drbd_debugfs_connection_add(connection); 26738c2ecf20Sopenharmony_ci return connection; 26748c2ecf20Sopenharmony_ci 26758c2ecf20Sopenharmony_cifail_resource: 26768c2ecf20Sopenharmony_ci list_del(&resource->resources); 26778c2ecf20Sopenharmony_ci drbd_free_resource(resource); 26788c2ecf20Sopenharmony_cifail: 26798c2ecf20Sopenharmony_ci kfree(connection->current_epoch); 26808c2ecf20Sopenharmony_ci drbd_free_socket(&connection->meta); 26818c2ecf20Sopenharmony_ci drbd_free_socket(&connection->data); 26828c2ecf20Sopenharmony_ci kfree(connection); 26838c2ecf20Sopenharmony_ci return NULL; 26848c2ecf20Sopenharmony_ci} 26858c2ecf20Sopenharmony_ci 26868c2ecf20Sopenharmony_civoid drbd_destroy_connection(struct kref *kref) 26878c2ecf20Sopenharmony_ci{ 26888c2ecf20Sopenharmony_ci struct drbd_connection *connection = container_of(kref, struct drbd_connection, kref); 26898c2ecf20Sopenharmony_ci struct drbd_resource *resource = connection->resource; 26908c2ecf20Sopenharmony_ci 26918c2ecf20Sopenharmony_ci if (atomic_read(&connection->current_epoch->epoch_size) != 0) 26928c2ecf20Sopenharmony_ci drbd_err(connection, "epoch_size:%d\n", atomic_read(&connection->current_epoch->epoch_size)); 26938c2ecf20Sopenharmony_ci kfree(connection->current_epoch); 26948c2ecf20Sopenharmony_ci 26958c2ecf20Sopenharmony_ci idr_destroy(&connection->peer_devices); 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci drbd_free_socket(&connection->meta); 26988c2ecf20Sopenharmony_ci drbd_free_socket(&connection->data); 26998c2ecf20Sopenharmony_ci kfree(connection->int_dig_in); 27008c2ecf20Sopenharmony_ci kfree(connection->int_dig_vv); 27018c2ecf20Sopenharmony_ci memset(connection, 0xfc, sizeof(*connection)); 27028c2ecf20Sopenharmony_ci kfree(connection); 27038c2ecf20Sopenharmony_ci kref_put(&resource->kref, drbd_destroy_resource); 27048c2ecf20Sopenharmony_ci} 27058c2ecf20Sopenharmony_ci 27068c2ecf20Sopenharmony_cistatic int init_submitter(struct drbd_device *device) 27078c2ecf20Sopenharmony_ci{ 27088c2ecf20Sopenharmony_ci /* opencoded create_singlethread_workqueue(), 27098c2ecf20Sopenharmony_ci * to be able to say "drbd%d", ..., minor */ 27108c2ecf20Sopenharmony_ci device->submit.wq = 27118c2ecf20Sopenharmony_ci alloc_ordered_workqueue("drbd%u_submit", WQ_MEM_RECLAIM, device->minor); 27128c2ecf20Sopenharmony_ci if (!device->submit.wq) 27138c2ecf20Sopenharmony_ci return -ENOMEM; 27148c2ecf20Sopenharmony_ci 27158c2ecf20Sopenharmony_ci INIT_WORK(&device->submit.worker, do_submit); 27168c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->submit.writes); 27178c2ecf20Sopenharmony_ci return 0; 27188c2ecf20Sopenharmony_ci} 27198c2ecf20Sopenharmony_ci 27208c2ecf20Sopenharmony_cienum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsigned int minor) 27218c2ecf20Sopenharmony_ci{ 27228c2ecf20Sopenharmony_ci struct drbd_resource *resource = adm_ctx->resource; 27238c2ecf20Sopenharmony_ci struct drbd_connection *connection, *n; 27248c2ecf20Sopenharmony_ci struct drbd_device *device; 27258c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device, *tmp_peer_device; 27268c2ecf20Sopenharmony_ci struct gendisk *disk; 27278c2ecf20Sopenharmony_ci struct request_queue *q; 27288c2ecf20Sopenharmony_ci int id; 27298c2ecf20Sopenharmony_ci int vnr = adm_ctx->volume; 27308c2ecf20Sopenharmony_ci enum drbd_ret_code err = ERR_NOMEM; 27318c2ecf20Sopenharmony_ci 27328c2ecf20Sopenharmony_ci device = minor_to_device(minor); 27338c2ecf20Sopenharmony_ci if (device) 27348c2ecf20Sopenharmony_ci return ERR_MINOR_OR_VOLUME_EXISTS; 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci /* GFP_KERNEL, we are outside of all write-out paths */ 27378c2ecf20Sopenharmony_ci device = kzalloc(sizeof(struct drbd_device), GFP_KERNEL); 27388c2ecf20Sopenharmony_ci if (!device) 27398c2ecf20Sopenharmony_ci return ERR_NOMEM; 27408c2ecf20Sopenharmony_ci kref_init(&device->kref); 27418c2ecf20Sopenharmony_ci 27428c2ecf20Sopenharmony_ci kref_get(&resource->kref); 27438c2ecf20Sopenharmony_ci device->resource = resource; 27448c2ecf20Sopenharmony_ci device->minor = minor; 27458c2ecf20Sopenharmony_ci device->vnr = vnr; 27468c2ecf20Sopenharmony_ci 27478c2ecf20Sopenharmony_ci drbd_init_set_defaults(device); 27488c2ecf20Sopenharmony_ci 27498c2ecf20Sopenharmony_ci q = blk_alloc_queue(NUMA_NO_NODE); 27508c2ecf20Sopenharmony_ci if (!q) 27518c2ecf20Sopenharmony_ci goto out_no_q; 27528c2ecf20Sopenharmony_ci device->rq_queue = q; 27538c2ecf20Sopenharmony_ci 27548c2ecf20Sopenharmony_ci disk = alloc_disk(1); 27558c2ecf20Sopenharmony_ci if (!disk) 27568c2ecf20Sopenharmony_ci goto out_no_disk; 27578c2ecf20Sopenharmony_ci device->vdisk = disk; 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_ci set_disk_ro(disk, true); 27608c2ecf20Sopenharmony_ci 27618c2ecf20Sopenharmony_ci disk->queue = q; 27628c2ecf20Sopenharmony_ci disk->major = DRBD_MAJOR; 27638c2ecf20Sopenharmony_ci disk->first_minor = minor; 27648c2ecf20Sopenharmony_ci disk->fops = &drbd_ops; 27658c2ecf20Sopenharmony_ci sprintf(disk->disk_name, "drbd%d", minor); 27668c2ecf20Sopenharmony_ci disk->private_data = device; 27678c2ecf20Sopenharmony_ci 27688c2ecf20Sopenharmony_ci blk_queue_write_cache(q, true, true); 27698c2ecf20Sopenharmony_ci /* Setting the max_hw_sectors to an odd value of 8kibyte here 27708c2ecf20Sopenharmony_ci This triggers a max_bio_size message upon first attach or connect */ 27718c2ecf20Sopenharmony_ci blk_queue_max_hw_sectors(q, DRBD_MAX_BIO_SIZE_SAFE >> 8); 27728c2ecf20Sopenharmony_ci 27738c2ecf20Sopenharmony_ci device->md_io.page = alloc_page(GFP_KERNEL); 27748c2ecf20Sopenharmony_ci if (!device->md_io.page) 27758c2ecf20Sopenharmony_ci goto out_no_io_page; 27768c2ecf20Sopenharmony_ci 27778c2ecf20Sopenharmony_ci if (drbd_bm_init(device)) 27788c2ecf20Sopenharmony_ci goto out_no_bitmap; 27798c2ecf20Sopenharmony_ci device->read_requests = RB_ROOT; 27808c2ecf20Sopenharmony_ci device->write_requests = RB_ROOT; 27818c2ecf20Sopenharmony_ci 27828c2ecf20Sopenharmony_ci id = idr_alloc(&drbd_devices, device, minor, minor + 1, GFP_KERNEL); 27838c2ecf20Sopenharmony_ci if (id < 0) { 27848c2ecf20Sopenharmony_ci if (id == -ENOSPC) 27858c2ecf20Sopenharmony_ci err = ERR_MINOR_OR_VOLUME_EXISTS; 27868c2ecf20Sopenharmony_ci goto out_no_minor_idr; 27878c2ecf20Sopenharmony_ci } 27888c2ecf20Sopenharmony_ci kref_get(&device->kref); 27898c2ecf20Sopenharmony_ci 27908c2ecf20Sopenharmony_ci id = idr_alloc(&resource->devices, device, vnr, vnr + 1, GFP_KERNEL); 27918c2ecf20Sopenharmony_ci if (id < 0) { 27928c2ecf20Sopenharmony_ci if (id == -ENOSPC) 27938c2ecf20Sopenharmony_ci err = ERR_MINOR_OR_VOLUME_EXISTS; 27948c2ecf20Sopenharmony_ci goto out_idr_remove_minor; 27958c2ecf20Sopenharmony_ci } 27968c2ecf20Sopenharmony_ci kref_get(&device->kref); 27978c2ecf20Sopenharmony_ci 27988c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->peer_devices); 27998c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device->pending_bitmap_io); 28008c2ecf20Sopenharmony_ci for_each_connection(connection, resource) { 28018c2ecf20Sopenharmony_ci peer_device = kzalloc(sizeof(struct drbd_peer_device), GFP_KERNEL); 28028c2ecf20Sopenharmony_ci if (!peer_device) 28038c2ecf20Sopenharmony_ci goto out_idr_remove_from_resource; 28048c2ecf20Sopenharmony_ci peer_device->connection = connection; 28058c2ecf20Sopenharmony_ci peer_device->device = device; 28068c2ecf20Sopenharmony_ci 28078c2ecf20Sopenharmony_ci list_add(&peer_device->peer_devices, &device->peer_devices); 28088c2ecf20Sopenharmony_ci kref_get(&device->kref); 28098c2ecf20Sopenharmony_ci 28108c2ecf20Sopenharmony_ci id = idr_alloc(&connection->peer_devices, peer_device, vnr, vnr + 1, GFP_KERNEL); 28118c2ecf20Sopenharmony_ci if (id < 0) { 28128c2ecf20Sopenharmony_ci if (id == -ENOSPC) 28138c2ecf20Sopenharmony_ci err = ERR_INVALID_REQUEST; 28148c2ecf20Sopenharmony_ci goto out_idr_remove_from_resource; 28158c2ecf20Sopenharmony_ci } 28168c2ecf20Sopenharmony_ci kref_get(&connection->kref); 28178c2ecf20Sopenharmony_ci INIT_WORK(&peer_device->send_acks_work, drbd_send_acks_wf); 28188c2ecf20Sopenharmony_ci } 28198c2ecf20Sopenharmony_ci 28208c2ecf20Sopenharmony_ci if (init_submitter(device)) { 28218c2ecf20Sopenharmony_ci err = ERR_NOMEM; 28228c2ecf20Sopenharmony_ci goto out_idr_remove_from_resource; 28238c2ecf20Sopenharmony_ci } 28248c2ecf20Sopenharmony_ci 28258c2ecf20Sopenharmony_ci add_disk(disk); 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_ci /* inherit the connection state */ 28288c2ecf20Sopenharmony_ci device->state.conn = first_connection(resource)->cstate; 28298c2ecf20Sopenharmony_ci if (device->state.conn == C_WF_REPORT_PARAMS) { 28308c2ecf20Sopenharmony_ci for_each_peer_device(peer_device, device) 28318c2ecf20Sopenharmony_ci drbd_connected(peer_device); 28328c2ecf20Sopenharmony_ci } 28338c2ecf20Sopenharmony_ci /* move to create_peer_device() */ 28348c2ecf20Sopenharmony_ci for_each_peer_device(peer_device, device) 28358c2ecf20Sopenharmony_ci drbd_debugfs_peer_device_add(peer_device); 28368c2ecf20Sopenharmony_ci drbd_debugfs_device_add(device); 28378c2ecf20Sopenharmony_ci return NO_ERROR; 28388c2ecf20Sopenharmony_ci 28398c2ecf20Sopenharmony_ciout_idr_remove_from_resource: 28408c2ecf20Sopenharmony_ci for_each_connection_safe(connection, n, resource) { 28418c2ecf20Sopenharmony_ci peer_device = idr_remove(&connection->peer_devices, vnr); 28428c2ecf20Sopenharmony_ci if (peer_device) 28438c2ecf20Sopenharmony_ci kref_put(&connection->kref, drbd_destroy_connection); 28448c2ecf20Sopenharmony_ci } 28458c2ecf20Sopenharmony_ci for_each_peer_device_safe(peer_device, tmp_peer_device, device) { 28468c2ecf20Sopenharmony_ci list_del(&peer_device->peer_devices); 28478c2ecf20Sopenharmony_ci kfree(peer_device); 28488c2ecf20Sopenharmony_ci } 28498c2ecf20Sopenharmony_ci idr_remove(&resource->devices, vnr); 28508c2ecf20Sopenharmony_ciout_idr_remove_minor: 28518c2ecf20Sopenharmony_ci idr_remove(&drbd_devices, minor); 28528c2ecf20Sopenharmony_ci synchronize_rcu(); 28538c2ecf20Sopenharmony_ciout_no_minor_idr: 28548c2ecf20Sopenharmony_ci drbd_bm_cleanup(device); 28558c2ecf20Sopenharmony_ciout_no_bitmap: 28568c2ecf20Sopenharmony_ci __free_page(device->md_io.page); 28578c2ecf20Sopenharmony_ciout_no_io_page: 28588c2ecf20Sopenharmony_ci put_disk(disk); 28598c2ecf20Sopenharmony_ciout_no_disk: 28608c2ecf20Sopenharmony_ci blk_cleanup_queue(q); 28618c2ecf20Sopenharmony_ciout_no_q: 28628c2ecf20Sopenharmony_ci kref_put(&resource->kref, drbd_destroy_resource); 28638c2ecf20Sopenharmony_ci kfree(device); 28648c2ecf20Sopenharmony_ci return err; 28658c2ecf20Sopenharmony_ci} 28668c2ecf20Sopenharmony_ci 28678c2ecf20Sopenharmony_civoid drbd_delete_device(struct drbd_device *device) 28688c2ecf20Sopenharmony_ci{ 28698c2ecf20Sopenharmony_ci struct drbd_resource *resource = device->resource; 28708c2ecf20Sopenharmony_ci struct drbd_connection *connection; 28718c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 28728c2ecf20Sopenharmony_ci 28738c2ecf20Sopenharmony_ci /* move to free_peer_device() */ 28748c2ecf20Sopenharmony_ci for_each_peer_device(peer_device, device) 28758c2ecf20Sopenharmony_ci drbd_debugfs_peer_device_cleanup(peer_device); 28768c2ecf20Sopenharmony_ci drbd_debugfs_device_cleanup(device); 28778c2ecf20Sopenharmony_ci for_each_connection(connection, resource) { 28788c2ecf20Sopenharmony_ci idr_remove(&connection->peer_devices, device->vnr); 28798c2ecf20Sopenharmony_ci kref_put(&device->kref, drbd_destroy_device); 28808c2ecf20Sopenharmony_ci } 28818c2ecf20Sopenharmony_ci idr_remove(&resource->devices, device->vnr); 28828c2ecf20Sopenharmony_ci kref_put(&device->kref, drbd_destroy_device); 28838c2ecf20Sopenharmony_ci idr_remove(&drbd_devices, device_to_minor(device)); 28848c2ecf20Sopenharmony_ci kref_put(&device->kref, drbd_destroy_device); 28858c2ecf20Sopenharmony_ci del_gendisk(device->vdisk); 28868c2ecf20Sopenharmony_ci synchronize_rcu(); 28878c2ecf20Sopenharmony_ci kref_put(&device->kref, drbd_destroy_device); 28888c2ecf20Sopenharmony_ci} 28898c2ecf20Sopenharmony_ci 28908c2ecf20Sopenharmony_cistatic int __init drbd_init(void) 28918c2ecf20Sopenharmony_ci{ 28928c2ecf20Sopenharmony_ci int err; 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_ci if (drbd_minor_count < DRBD_MINOR_COUNT_MIN || drbd_minor_count > DRBD_MINOR_COUNT_MAX) { 28958c2ecf20Sopenharmony_ci pr_err("invalid minor_count (%d)\n", drbd_minor_count); 28968c2ecf20Sopenharmony_ci#ifdef MODULE 28978c2ecf20Sopenharmony_ci return -EINVAL; 28988c2ecf20Sopenharmony_ci#else 28998c2ecf20Sopenharmony_ci drbd_minor_count = DRBD_MINOR_COUNT_DEF; 29008c2ecf20Sopenharmony_ci#endif 29018c2ecf20Sopenharmony_ci } 29028c2ecf20Sopenharmony_ci 29038c2ecf20Sopenharmony_ci err = register_blkdev(DRBD_MAJOR, "drbd"); 29048c2ecf20Sopenharmony_ci if (err) { 29058c2ecf20Sopenharmony_ci pr_err("unable to register block device major %d\n", 29068c2ecf20Sopenharmony_ci DRBD_MAJOR); 29078c2ecf20Sopenharmony_ci return err; 29088c2ecf20Sopenharmony_ci } 29098c2ecf20Sopenharmony_ci 29108c2ecf20Sopenharmony_ci /* 29118c2ecf20Sopenharmony_ci * allocate all necessary structs 29128c2ecf20Sopenharmony_ci */ 29138c2ecf20Sopenharmony_ci init_waitqueue_head(&drbd_pp_wait); 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_ci drbd_proc = NULL; /* play safe for drbd_cleanup */ 29168c2ecf20Sopenharmony_ci idr_init(&drbd_devices); 29178c2ecf20Sopenharmony_ci 29188c2ecf20Sopenharmony_ci mutex_init(&resources_mutex); 29198c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&drbd_resources); 29208c2ecf20Sopenharmony_ci 29218c2ecf20Sopenharmony_ci err = drbd_genl_register(); 29228c2ecf20Sopenharmony_ci if (err) { 29238c2ecf20Sopenharmony_ci pr_err("unable to register generic netlink family\n"); 29248c2ecf20Sopenharmony_ci goto fail; 29258c2ecf20Sopenharmony_ci } 29268c2ecf20Sopenharmony_ci 29278c2ecf20Sopenharmony_ci err = drbd_create_mempools(); 29288c2ecf20Sopenharmony_ci if (err) 29298c2ecf20Sopenharmony_ci goto fail; 29308c2ecf20Sopenharmony_ci 29318c2ecf20Sopenharmony_ci err = -ENOMEM; 29328c2ecf20Sopenharmony_ci drbd_proc = proc_create_single("drbd", S_IFREG | 0444 , NULL, drbd_seq_show); 29338c2ecf20Sopenharmony_ci if (!drbd_proc) { 29348c2ecf20Sopenharmony_ci pr_err("unable to register proc file\n"); 29358c2ecf20Sopenharmony_ci goto fail; 29368c2ecf20Sopenharmony_ci } 29378c2ecf20Sopenharmony_ci 29388c2ecf20Sopenharmony_ci retry.wq = create_singlethread_workqueue("drbd-reissue"); 29398c2ecf20Sopenharmony_ci if (!retry.wq) { 29408c2ecf20Sopenharmony_ci pr_err("unable to create retry workqueue\n"); 29418c2ecf20Sopenharmony_ci goto fail; 29428c2ecf20Sopenharmony_ci } 29438c2ecf20Sopenharmony_ci INIT_WORK(&retry.worker, do_retry); 29448c2ecf20Sopenharmony_ci spin_lock_init(&retry.lock); 29458c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&retry.writes); 29468c2ecf20Sopenharmony_ci 29478c2ecf20Sopenharmony_ci drbd_debugfs_init(); 29488c2ecf20Sopenharmony_ci 29498c2ecf20Sopenharmony_ci pr_info("initialized. " 29508c2ecf20Sopenharmony_ci "Version: " REL_VERSION " (api:%d/proto:%d-%d)\n", 29518c2ecf20Sopenharmony_ci API_VERSION, PRO_VERSION_MIN, PRO_VERSION_MAX); 29528c2ecf20Sopenharmony_ci pr_info("%s\n", drbd_buildtag()); 29538c2ecf20Sopenharmony_ci pr_info("registered as block device major %d\n", DRBD_MAJOR); 29548c2ecf20Sopenharmony_ci return 0; /* Success! */ 29558c2ecf20Sopenharmony_ci 29568c2ecf20Sopenharmony_cifail: 29578c2ecf20Sopenharmony_ci drbd_cleanup(); 29588c2ecf20Sopenharmony_ci if (err == -ENOMEM) 29598c2ecf20Sopenharmony_ci pr_err("ran out of memory\n"); 29608c2ecf20Sopenharmony_ci else 29618c2ecf20Sopenharmony_ci pr_err("initialization failure\n"); 29628c2ecf20Sopenharmony_ci return err; 29638c2ecf20Sopenharmony_ci} 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_cistatic void drbd_free_one_sock(struct drbd_socket *ds) 29668c2ecf20Sopenharmony_ci{ 29678c2ecf20Sopenharmony_ci struct socket *s; 29688c2ecf20Sopenharmony_ci mutex_lock(&ds->mutex); 29698c2ecf20Sopenharmony_ci s = ds->socket; 29708c2ecf20Sopenharmony_ci ds->socket = NULL; 29718c2ecf20Sopenharmony_ci mutex_unlock(&ds->mutex); 29728c2ecf20Sopenharmony_ci if (s) { 29738c2ecf20Sopenharmony_ci /* so debugfs does not need to mutex_lock() */ 29748c2ecf20Sopenharmony_ci synchronize_rcu(); 29758c2ecf20Sopenharmony_ci kernel_sock_shutdown(s, SHUT_RDWR); 29768c2ecf20Sopenharmony_ci sock_release(s); 29778c2ecf20Sopenharmony_ci } 29788c2ecf20Sopenharmony_ci} 29798c2ecf20Sopenharmony_ci 29808c2ecf20Sopenharmony_civoid drbd_free_sock(struct drbd_connection *connection) 29818c2ecf20Sopenharmony_ci{ 29828c2ecf20Sopenharmony_ci if (connection->data.socket) 29838c2ecf20Sopenharmony_ci drbd_free_one_sock(&connection->data); 29848c2ecf20Sopenharmony_ci if (connection->meta.socket) 29858c2ecf20Sopenharmony_ci drbd_free_one_sock(&connection->meta); 29868c2ecf20Sopenharmony_ci} 29878c2ecf20Sopenharmony_ci 29888c2ecf20Sopenharmony_ci/* meta data management */ 29898c2ecf20Sopenharmony_ci 29908c2ecf20Sopenharmony_civoid conn_md_sync(struct drbd_connection *connection) 29918c2ecf20Sopenharmony_ci{ 29928c2ecf20Sopenharmony_ci struct drbd_peer_device *peer_device; 29938c2ecf20Sopenharmony_ci int vnr; 29948c2ecf20Sopenharmony_ci 29958c2ecf20Sopenharmony_ci rcu_read_lock(); 29968c2ecf20Sopenharmony_ci idr_for_each_entry(&connection->peer_devices, peer_device, vnr) { 29978c2ecf20Sopenharmony_ci struct drbd_device *device = peer_device->device; 29988c2ecf20Sopenharmony_ci 29998c2ecf20Sopenharmony_ci kref_get(&device->kref); 30008c2ecf20Sopenharmony_ci rcu_read_unlock(); 30018c2ecf20Sopenharmony_ci drbd_md_sync(device); 30028c2ecf20Sopenharmony_ci kref_put(&device->kref, drbd_destroy_device); 30038c2ecf20Sopenharmony_ci rcu_read_lock(); 30048c2ecf20Sopenharmony_ci } 30058c2ecf20Sopenharmony_ci rcu_read_unlock(); 30068c2ecf20Sopenharmony_ci} 30078c2ecf20Sopenharmony_ci 30088c2ecf20Sopenharmony_ci/* aligned 4kByte */ 30098c2ecf20Sopenharmony_cistruct meta_data_on_disk { 30108c2ecf20Sopenharmony_ci u64 la_size_sect; /* last agreed size. */ 30118c2ecf20Sopenharmony_ci u64 uuid[UI_SIZE]; /* UUIDs. */ 30128c2ecf20Sopenharmony_ci u64 device_uuid; 30138c2ecf20Sopenharmony_ci u64 reserved_u64_1; 30148c2ecf20Sopenharmony_ci u32 flags; /* MDF */ 30158c2ecf20Sopenharmony_ci u32 magic; 30168c2ecf20Sopenharmony_ci u32 md_size_sect; 30178c2ecf20Sopenharmony_ci u32 al_offset; /* offset to this block */ 30188c2ecf20Sopenharmony_ci u32 al_nr_extents; /* important for restoring the AL (userspace) */ 30198c2ecf20Sopenharmony_ci /* `-- act_log->nr_elements <-- ldev->dc.al_extents */ 30208c2ecf20Sopenharmony_ci u32 bm_offset; /* offset to the bitmap, from here */ 30218c2ecf20Sopenharmony_ci u32 bm_bytes_per_bit; /* BM_BLOCK_SIZE */ 30228c2ecf20Sopenharmony_ci u32 la_peer_max_bio_size; /* last peer max_bio_size */ 30238c2ecf20Sopenharmony_ci 30248c2ecf20Sopenharmony_ci /* see al_tr_number_to_on_disk_sector() */ 30258c2ecf20Sopenharmony_ci u32 al_stripes; 30268c2ecf20Sopenharmony_ci u32 al_stripe_size_4k; 30278c2ecf20Sopenharmony_ci 30288c2ecf20Sopenharmony_ci u8 reserved_u8[4096 - (7*8 + 10*4)]; 30298c2ecf20Sopenharmony_ci} __packed; 30308c2ecf20Sopenharmony_ci 30318c2ecf20Sopenharmony_ci 30328c2ecf20Sopenharmony_ci 30338c2ecf20Sopenharmony_civoid drbd_md_write(struct drbd_device *device, void *b) 30348c2ecf20Sopenharmony_ci{ 30358c2ecf20Sopenharmony_ci struct meta_data_on_disk *buffer = b; 30368c2ecf20Sopenharmony_ci sector_t sector; 30378c2ecf20Sopenharmony_ci int i; 30388c2ecf20Sopenharmony_ci 30398c2ecf20Sopenharmony_ci memset(buffer, 0, sizeof(*buffer)); 30408c2ecf20Sopenharmony_ci 30418c2ecf20Sopenharmony_ci buffer->la_size_sect = cpu_to_be64(get_capacity(device->vdisk)); 30428c2ecf20Sopenharmony_ci for (i = UI_CURRENT; i < UI_SIZE; i++) 30438c2ecf20Sopenharmony_ci buffer->uuid[i] = cpu_to_be64(device->ldev->md.uuid[i]); 30448c2ecf20Sopenharmony_ci buffer->flags = cpu_to_be32(device->ldev->md.flags); 30458c2ecf20Sopenharmony_ci buffer->magic = cpu_to_be32(DRBD_MD_MAGIC_84_UNCLEAN); 30468c2ecf20Sopenharmony_ci 30478c2ecf20Sopenharmony_ci buffer->md_size_sect = cpu_to_be32(device->ldev->md.md_size_sect); 30488c2ecf20Sopenharmony_ci buffer->al_offset = cpu_to_be32(device->ldev->md.al_offset); 30498c2ecf20Sopenharmony_ci buffer->al_nr_extents = cpu_to_be32(device->act_log->nr_elements); 30508c2ecf20Sopenharmony_ci buffer->bm_bytes_per_bit = cpu_to_be32(BM_BLOCK_SIZE); 30518c2ecf20Sopenharmony_ci buffer->device_uuid = cpu_to_be64(device->ldev->md.device_uuid); 30528c2ecf20Sopenharmony_ci 30538c2ecf20Sopenharmony_ci buffer->bm_offset = cpu_to_be32(device->ldev->md.bm_offset); 30548c2ecf20Sopenharmony_ci buffer->la_peer_max_bio_size = cpu_to_be32(device->peer_max_bio_size); 30558c2ecf20Sopenharmony_ci 30568c2ecf20Sopenharmony_ci buffer->al_stripes = cpu_to_be32(device->ldev->md.al_stripes); 30578c2ecf20Sopenharmony_ci buffer->al_stripe_size_4k = cpu_to_be32(device->ldev->md.al_stripe_size_4k); 30588c2ecf20Sopenharmony_ci 30598c2ecf20Sopenharmony_ci D_ASSERT(device, drbd_md_ss(device->ldev) == device->ldev->md.md_offset); 30608c2ecf20Sopenharmony_ci sector = device->ldev->md.md_offset; 30618c2ecf20Sopenharmony_ci 30628c2ecf20Sopenharmony_ci if (drbd_md_sync_page_io(device, device->ldev, sector, REQ_OP_WRITE)) { 30638c2ecf20Sopenharmony_ci /* this was a try anyways ... */ 30648c2ecf20Sopenharmony_ci drbd_err(device, "meta data update failed!\n"); 30658c2ecf20Sopenharmony_ci drbd_chk_io_error(device, 1, DRBD_META_IO_ERROR); 30668c2ecf20Sopenharmony_ci } 30678c2ecf20Sopenharmony_ci} 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci/** 30708c2ecf20Sopenharmony_ci * drbd_md_sync() - Writes the meta data super block if the MD_DIRTY flag bit is set 30718c2ecf20Sopenharmony_ci * @device: DRBD device. 30728c2ecf20Sopenharmony_ci */ 30738c2ecf20Sopenharmony_civoid drbd_md_sync(struct drbd_device *device) 30748c2ecf20Sopenharmony_ci{ 30758c2ecf20Sopenharmony_ci struct meta_data_on_disk *buffer; 30768c2ecf20Sopenharmony_ci 30778c2ecf20Sopenharmony_ci /* Don't accidentally change the DRBD meta data layout. */ 30788c2ecf20Sopenharmony_ci BUILD_BUG_ON(UI_SIZE != 4); 30798c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct meta_data_on_disk) != 4096); 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_ci del_timer(&device->md_sync_timer); 30828c2ecf20Sopenharmony_ci /* timer may be rearmed by drbd_md_mark_dirty() now. */ 30838c2ecf20Sopenharmony_ci if (!test_and_clear_bit(MD_DIRTY, &device->flags)) 30848c2ecf20Sopenharmony_ci return; 30858c2ecf20Sopenharmony_ci 30868c2ecf20Sopenharmony_ci /* We use here D_FAILED and not D_ATTACHING because we try to write 30878c2ecf20Sopenharmony_ci * metadata even if we detach due to a disk failure! */ 30888c2ecf20Sopenharmony_ci if (!get_ldev_if_state(device, D_FAILED)) 30898c2ecf20Sopenharmony_ci return; 30908c2ecf20Sopenharmony_ci 30918c2ecf20Sopenharmony_ci buffer = drbd_md_get_buffer(device, __func__); 30928c2ecf20Sopenharmony_ci if (!buffer) 30938c2ecf20Sopenharmony_ci goto out; 30948c2ecf20Sopenharmony_ci 30958c2ecf20Sopenharmony_ci drbd_md_write(device, buffer); 30968c2ecf20Sopenharmony_ci 30978c2ecf20Sopenharmony_ci /* Update device->ldev->md.la_size_sect, 30988c2ecf20Sopenharmony_ci * since we updated it on metadata. */ 30998c2ecf20Sopenharmony_ci device->ldev->md.la_size_sect = get_capacity(device->vdisk); 31008c2ecf20Sopenharmony_ci 31018c2ecf20Sopenharmony_ci drbd_md_put_buffer(device); 31028c2ecf20Sopenharmony_ciout: 31038c2ecf20Sopenharmony_ci put_ldev(device); 31048c2ecf20Sopenharmony_ci} 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_cistatic int check_activity_log_stripe_size(struct drbd_device *device, 31078c2ecf20Sopenharmony_ci struct meta_data_on_disk *on_disk, 31088c2ecf20Sopenharmony_ci struct drbd_md *in_core) 31098c2ecf20Sopenharmony_ci{ 31108c2ecf20Sopenharmony_ci u32 al_stripes = be32_to_cpu(on_disk->al_stripes); 31118c2ecf20Sopenharmony_ci u32 al_stripe_size_4k = be32_to_cpu(on_disk->al_stripe_size_4k); 31128c2ecf20Sopenharmony_ci u64 al_size_4k; 31138c2ecf20Sopenharmony_ci 31148c2ecf20Sopenharmony_ci /* both not set: default to old fixed size activity log */ 31158c2ecf20Sopenharmony_ci if (al_stripes == 0 && al_stripe_size_4k == 0) { 31168c2ecf20Sopenharmony_ci al_stripes = 1; 31178c2ecf20Sopenharmony_ci al_stripe_size_4k = MD_32kB_SECT/8; 31188c2ecf20Sopenharmony_ci } 31198c2ecf20Sopenharmony_ci 31208c2ecf20Sopenharmony_ci /* some paranoia plausibility checks */ 31218c2ecf20Sopenharmony_ci 31228c2ecf20Sopenharmony_ci /* we need both values to be set */ 31238c2ecf20Sopenharmony_ci if (al_stripes == 0 || al_stripe_size_4k == 0) 31248c2ecf20Sopenharmony_ci goto err; 31258c2ecf20Sopenharmony_ci 31268c2ecf20Sopenharmony_ci al_size_4k = (u64)al_stripes * al_stripe_size_4k; 31278c2ecf20Sopenharmony_ci 31288c2ecf20Sopenharmony_ci /* Upper limit of activity log area, to avoid potential overflow 31298c2ecf20Sopenharmony_ci * problems in al_tr_number_to_on_disk_sector(). As right now, more 31308c2ecf20Sopenharmony_ci * than 72 * 4k blocks total only increases the amount of history, 31318c2ecf20Sopenharmony_ci * limiting this arbitrarily to 16 GB is not a real limitation ;-) */ 31328c2ecf20Sopenharmony_ci if (al_size_4k > (16 * 1024 * 1024/4)) 31338c2ecf20Sopenharmony_ci goto err; 31348c2ecf20Sopenharmony_ci 31358c2ecf20Sopenharmony_ci /* Lower limit: we need at least 8 transaction slots (32kB) 31368c2ecf20Sopenharmony_ci * to not break existing setups */ 31378c2ecf20Sopenharmony_ci if (al_size_4k < MD_32kB_SECT/8) 31388c2ecf20Sopenharmony_ci goto err; 31398c2ecf20Sopenharmony_ci 31408c2ecf20Sopenharmony_ci in_core->al_stripe_size_4k = al_stripe_size_4k; 31418c2ecf20Sopenharmony_ci in_core->al_stripes = al_stripes; 31428c2ecf20Sopenharmony_ci in_core->al_size_4k = al_size_4k; 31438c2ecf20Sopenharmony_ci 31448c2ecf20Sopenharmony_ci return 0; 31458c2ecf20Sopenharmony_cierr: 31468c2ecf20Sopenharmony_ci drbd_err(device, "invalid activity log striping: al_stripes=%u, al_stripe_size_4k=%u\n", 31478c2ecf20Sopenharmony_ci al_stripes, al_stripe_size_4k); 31488c2ecf20Sopenharmony_ci return -EINVAL; 31498c2ecf20Sopenharmony_ci} 31508c2ecf20Sopenharmony_ci 31518c2ecf20Sopenharmony_cistatic int check_offsets_and_sizes(struct drbd_device *device, struct drbd_backing_dev *bdev) 31528c2ecf20Sopenharmony_ci{ 31538c2ecf20Sopenharmony_ci sector_t capacity = drbd_get_capacity(bdev->md_bdev); 31548c2ecf20Sopenharmony_ci struct drbd_md *in_core = &bdev->md; 31558c2ecf20Sopenharmony_ci s32 on_disk_al_sect; 31568c2ecf20Sopenharmony_ci s32 on_disk_bm_sect; 31578c2ecf20Sopenharmony_ci 31588c2ecf20Sopenharmony_ci /* The on-disk size of the activity log, calculated from offsets, and 31598c2ecf20Sopenharmony_ci * the size of the activity log calculated from the stripe settings, 31608c2ecf20Sopenharmony_ci * should match. 31618c2ecf20Sopenharmony_ci * Though we could relax this a bit: it is ok, if the striped activity log 31628c2ecf20Sopenharmony_ci * fits in the available on-disk activity log size. 31638c2ecf20Sopenharmony_ci * Right now, that would break how resize is implemented. 31648c2ecf20Sopenharmony_ci * TODO: make drbd_determine_dev_size() (and the drbdmeta tool) aware 31658c2ecf20Sopenharmony_ci * of possible unused padding space in the on disk layout. */ 31668c2ecf20Sopenharmony_ci if (in_core->al_offset < 0) { 31678c2ecf20Sopenharmony_ci if (in_core->bm_offset > in_core->al_offset) 31688c2ecf20Sopenharmony_ci goto err; 31698c2ecf20Sopenharmony_ci on_disk_al_sect = -in_core->al_offset; 31708c2ecf20Sopenharmony_ci on_disk_bm_sect = in_core->al_offset - in_core->bm_offset; 31718c2ecf20Sopenharmony_ci } else { 31728c2ecf20Sopenharmony_ci if (in_core->al_offset != MD_4kB_SECT) 31738c2ecf20Sopenharmony_ci goto err; 31748c2ecf20Sopenharmony_ci if (in_core->bm_offset < in_core->al_offset + in_core->al_size_4k * MD_4kB_SECT) 31758c2ecf20Sopenharmony_ci goto err; 31768c2ecf20Sopenharmony_ci 31778c2ecf20Sopenharmony_ci on_disk_al_sect = in_core->bm_offset - MD_4kB_SECT; 31788c2ecf20Sopenharmony_ci on_disk_bm_sect = in_core->md_size_sect - in_core->bm_offset; 31798c2ecf20Sopenharmony_ci } 31808c2ecf20Sopenharmony_ci 31818c2ecf20Sopenharmony_ci /* old fixed size meta data is exactly that: fixed. */ 31828c2ecf20Sopenharmony_ci if (in_core->meta_dev_idx >= 0) { 31838c2ecf20Sopenharmony_ci if (in_core->md_size_sect != MD_128MB_SECT 31848c2ecf20Sopenharmony_ci || in_core->al_offset != MD_4kB_SECT 31858c2ecf20Sopenharmony_ci || in_core->bm_offset != MD_4kB_SECT + MD_32kB_SECT 31868c2ecf20Sopenharmony_ci || in_core->al_stripes != 1 31878c2ecf20Sopenharmony_ci || in_core->al_stripe_size_4k != MD_32kB_SECT/8) 31888c2ecf20Sopenharmony_ci goto err; 31898c2ecf20Sopenharmony_ci } 31908c2ecf20Sopenharmony_ci 31918c2ecf20Sopenharmony_ci if (capacity < in_core->md_size_sect) 31928c2ecf20Sopenharmony_ci goto err; 31938c2ecf20Sopenharmony_ci if (capacity - in_core->md_size_sect < drbd_md_first_sector(bdev)) 31948c2ecf20Sopenharmony_ci goto err; 31958c2ecf20Sopenharmony_ci 31968c2ecf20Sopenharmony_ci /* should be aligned, and at least 32k */ 31978c2ecf20Sopenharmony_ci if ((on_disk_al_sect & 7) || (on_disk_al_sect < MD_32kB_SECT)) 31988c2ecf20Sopenharmony_ci goto err; 31998c2ecf20Sopenharmony_ci 32008c2ecf20Sopenharmony_ci /* should fit (for now: exactly) into the available on-disk space; 32018c2ecf20Sopenharmony_ci * overflow prevention is in check_activity_log_stripe_size() above. */ 32028c2ecf20Sopenharmony_ci if (on_disk_al_sect != in_core->al_size_4k * MD_4kB_SECT) 32038c2ecf20Sopenharmony_ci goto err; 32048c2ecf20Sopenharmony_ci 32058c2ecf20Sopenharmony_ci /* again, should be aligned */ 32068c2ecf20Sopenharmony_ci if (in_core->bm_offset & 7) 32078c2ecf20Sopenharmony_ci goto err; 32088c2ecf20Sopenharmony_ci 32098c2ecf20Sopenharmony_ci /* FIXME check for device grow with flex external meta data? */ 32108c2ecf20Sopenharmony_ci 32118c2ecf20Sopenharmony_ci /* can the available bitmap space cover the last agreed device size? */ 32128c2ecf20Sopenharmony_ci if (on_disk_bm_sect < (in_core->la_size_sect+7)/MD_4kB_SECT/8/512) 32138c2ecf20Sopenharmony_ci goto err; 32148c2ecf20Sopenharmony_ci 32158c2ecf20Sopenharmony_ci return 0; 32168c2ecf20Sopenharmony_ci 32178c2ecf20Sopenharmony_cierr: 32188c2ecf20Sopenharmony_ci drbd_err(device, "meta data offsets don't make sense: idx=%d " 32198c2ecf20Sopenharmony_ci "al_s=%u, al_sz4k=%u, al_offset=%d, bm_offset=%d, " 32208c2ecf20Sopenharmony_ci "md_size_sect=%u, la_size=%llu, md_capacity=%llu\n", 32218c2ecf20Sopenharmony_ci in_core->meta_dev_idx, 32228c2ecf20Sopenharmony_ci in_core->al_stripes, in_core->al_stripe_size_4k, 32238c2ecf20Sopenharmony_ci in_core->al_offset, in_core->bm_offset, in_core->md_size_sect, 32248c2ecf20Sopenharmony_ci (unsigned long long)in_core->la_size_sect, 32258c2ecf20Sopenharmony_ci (unsigned long long)capacity); 32268c2ecf20Sopenharmony_ci 32278c2ecf20Sopenharmony_ci return -EINVAL; 32288c2ecf20Sopenharmony_ci} 32298c2ecf20Sopenharmony_ci 32308c2ecf20Sopenharmony_ci 32318c2ecf20Sopenharmony_ci/** 32328c2ecf20Sopenharmony_ci * drbd_md_read() - Reads in the meta data super block 32338c2ecf20Sopenharmony_ci * @device: DRBD device. 32348c2ecf20Sopenharmony_ci * @bdev: Device from which the meta data should be read in. 32358c2ecf20Sopenharmony_ci * 32368c2ecf20Sopenharmony_ci * Return NO_ERROR on success, and an enum drbd_ret_code in case 32378c2ecf20Sopenharmony_ci * something goes wrong. 32388c2ecf20Sopenharmony_ci * 32398c2ecf20Sopenharmony_ci * Called exactly once during drbd_adm_attach(), while still being D_DISKLESS, 32408c2ecf20Sopenharmony_ci * even before @bdev is assigned to @device->ldev. 32418c2ecf20Sopenharmony_ci */ 32428c2ecf20Sopenharmony_ciint drbd_md_read(struct drbd_device *device, struct drbd_backing_dev *bdev) 32438c2ecf20Sopenharmony_ci{ 32448c2ecf20Sopenharmony_ci struct meta_data_on_disk *buffer; 32458c2ecf20Sopenharmony_ci u32 magic, flags; 32468c2ecf20Sopenharmony_ci int i, rv = NO_ERROR; 32478c2ecf20Sopenharmony_ci 32488c2ecf20Sopenharmony_ci if (device->state.disk != D_DISKLESS) 32498c2ecf20Sopenharmony_ci return ERR_DISK_CONFIGURED; 32508c2ecf20Sopenharmony_ci 32518c2ecf20Sopenharmony_ci buffer = drbd_md_get_buffer(device, __func__); 32528c2ecf20Sopenharmony_ci if (!buffer) 32538c2ecf20Sopenharmony_ci return ERR_NOMEM; 32548c2ecf20Sopenharmony_ci 32558c2ecf20Sopenharmony_ci /* First, figure out where our meta data superblock is located, 32568c2ecf20Sopenharmony_ci * and read it. */ 32578c2ecf20Sopenharmony_ci bdev->md.meta_dev_idx = bdev->disk_conf->meta_dev_idx; 32588c2ecf20Sopenharmony_ci bdev->md.md_offset = drbd_md_ss(bdev); 32598c2ecf20Sopenharmony_ci /* Even for (flexible or indexed) external meta data, 32608c2ecf20Sopenharmony_ci * initially restrict us to the 4k superblock for now. 32618c2ecf20Sopenharmony_ci * Affects the paranoia out-of-range access check in drbd_md_sync_page_io(). */ 32628c2ecf20Sopenharmony_ci bdev->md.md_size_sect = 8; 32638c2ecf20Sopenharmony_ci 32648c2ecf20Sopenharmony_ci if (drbd_md_sync_page_io(device, bdev, bdev->md.md_offset, 32658c2ecf20Sopenharmony_ci REQ_OP_READ)) { 32668c2ecf20Sopenharmony_ci /* NOTE: can't do normal error processing here as this is 32678c2ecf20Sopenharmony_ci called BEFORE disk is attached */ 32688c2ecf20Sopenharmony_ci drbd_err(device, "Error while reading metadata.\n"); 32698c2ecf20Sopenharmony_ci rv = ERR_IO_MD_DISK; 32708c2ecf20Sopenharmony_ci goto err; 32718c2ecf20Sopenharmony_ci } 32728c2ecf20Sopenharmony_ci 32738c2ecf20Sopenharmony_ci magic = be32_to_cpu(buffer->magic); 32748c2ecf20Sopenharmony_ci flags = be32_to_cpu(buffer->flags); 32758c2ecf20Sopenharmony_ci if (magic == DRBD_MD_MAGIC_84_UNCLEAN || 32768c2ecf20Sopenharmony_ci (magic == DRBD_MD_MAGIC_08 && !(flags & MDF_AL_CLEAN))) { 32778c2ecf20Sopenharmony_ci /* btw: that's Activity Log clean, not "all" clean. */ 32788c2ecf20Sopenharmony_ci drbd_err(device, "Found unclean meta data. Did you \"drbdadm apply-al\"?\n"); 32798c2ecf20Sopenharmony_ci rv = ERR_MD_UNCLEAN; 32808c2ecf20Sopenharmony_ci goto err; 32818c2ecf20Sopenharmony_ci } 32828c2ecf20Sopenharmony_ci 32838c2ecf20Sopenharmony_ci rv = ERR_MD_INVALID; 32848c2ecf20Sopenharmony_ci if (magic != DRBD_MD_MAGIC_08) { 32858c2ecf20Sopenharmony_ci if (magic == DRBD_MD_MAGIC_07) 32868c2ecf20Sopenharmony_ci drbd_err(device, "Found old (0.7) meta data magic. Did you \"drbdadm create-md\"?\n"); 32878c2ecf20Sopenharmony_ci else 32888c2ecf20Sopenharmony_ci drbd_err(device, "Meta data magic not found. Did you \"drbdadm create-md\"?\n"); 32898c2ecf20Sopenharmony_ci goto err; 32908c2ecf20Sopenharmony_ci } 32918c2ecf20Sopenharmony_ci 32928c2ecf20Sopenharmony_ci if (be32_to_cpu(buffer->bm_bytes_per_bit) != BM_BLOCK_SIZE) { 32938c2ecf20Sopenharmony_ci drbd_err(device, "unexpected bm_bytes_per_bit: %u (expected %u)\n", 32948c2ecf20Sopenharmony_ci be32_to_cpu(buffer->bm_bytes_per_bit), BM_BLOCK_SIZE); 32958c2ecf20Sopenharmony_ci goto err; 32968c2ecf20Sopenharmony_ci } 32978c2ecf20Sopenharmony_ci 32988c2ecf20Sopenharmony_ci 32998c2ecf20Sopenharmony_ci /* convert to in_core endian */ 33008c2ecf20Sopenharmony_ci bdev->md.la_size_sect = be64_to_cpu(buffer->la_size_sect); 33018c2ecf20Sopenharmony_ci for (i = UI_CURRENT; i < UI_SIZE; i++) 33028c2ecf20Sopenharmony_ci bdev->md.uuid[i] = be64_to_cpu(buffer->uuid[i]); 33038c2ecf20Sopenharmony_ci bdev->md.flags = be32_to_cpu(buffer->flags); 33048c2ecf20Sopenharmony_ci bdev->md.device_uuid = be64_to_cpu(buffer->device_uuid); 33058c2ecf20Sopenharmony_ci 33068c2ecf20Sopenharmony_ci bdev->md.md_size_sect = be32_to_cpu(buffer->md_size_sect); 33078c2ecf20Sopenharmony_ci bdev->md.al_offset = be32_to_cpu(buffer->al_offset); 33088c2ecf20Sopenharmony_ci bdev->md.bm_offset = be32_to_cpu(buffer->bm_offset); 33098c2ecf20Sopenharmony_ci 33108c2ecf20Sopenharmony_ci if (check_activity_log_stripe_size(device, buffer, &bdev->md)) 33118c2ecf20Sopenharmony_ci goto err; 33128c2ecf20Sopenharmony_ci if (check_offsets_and_sizes(device, bdev)) 33138c2ecf20Sopenharmony_ci goto err; 33148c2ecf20Sopenharmony_ci 33158c2ecf20Sopenharmony_ci if (be32_to_cpu(buffer->bm_offset) != bdev->md.bm_offset) { 33168c2ecf20Sopenharmony_ci drbd_err(device, "unexpected bm_offset: %d (expected %d)\n", 33178c2ecf20Sopenharmony_ci be32_to_cpu(buffer->bm_offset), bdev->md.bm_offset); 33188c2ecf20Sopenharmony_ci goto err; 33198c2ecf20Sopenharmony_ci } 33208c2ecf20Sopenharmony_ci if (be32_to_cpu(buffer->md_size_sect) != bdev->md.md_size_sect) { 33218c2ecf20Sopenharmony_ci drbd_err(device, "unexpected md_size: %u (expected %u)\n", 33228c2ecf20Sopenharmony_ci be32_to_cpu(buffer->md_size_sect), bdev->md.md_size_sect); 33238c2ecf20Sopenharmony_ci goto err; 33248c2ecf20Sopenharmony_ci } 33258c2ecf20Sopenharmony_ci 33268c2ecf20Sopenharmony_ci rv = NO_ERROR; 33278c2ecf20Sopenharmony_ci 33288c2ecf20Sopenharmony_ci spin_lock_irq(&device->resource->req_lock); 33298c2ecf20Sopenharmony_ci if (device->state.conn < C_CONNECTED) { 33308c2ecf20Sopenharmony_ci unsigned int peer; 33318c2ecf20Sopenharmony_ci peer = be32_to_cpu(buffer->la_peer_max_bio_size); 33328c2ecf20Sopenharmony_ci peer = max(peer, DRBD_MAX_BIO_SIZE_SAFE); 33338c2ecf20Sopenharmony_ci device->peer_max_bio_size = peer; 33348c2ecf20Sopenharmony_ci } 33358c2ecf20Sopenharmony_ci spin_unlock_irq(&device->resource->req_lock); 33368c2ecf20Sopenharmony_ci 33378c2ecf20Sopenharmony_ci err: 33388c2ecf20Sopenharmony_ci drbd_md_put_buffer(device); 33398c2ecf20Sopenharmony_ci 33408c2ecf20Sopenharmony_ci return rv; 33418c2ecf20Sopenharmony_ci} 33428c2ecf20Sopenharmony_ci 33438c2ecf20Sopenharmony_ci/** 33448c2ecf20Sopenharmony_ci * drbd_md_mark_dirty() - Mark meta data super block as dirty 33458c2ecf20Sopenharmony_ci * @device: DRBD device. 33468c2ecf20Sopenharmony_ci * 33478c2ecf20Sopenharmony_ci * Call this function if you change anything that should be written to 33488c2ecf20Sopenharmony_ci * the meta-data super block. This function sets MD_DIRTY, and starts a 33498c2ecf20Sopenharmony_ci * timer that ensures that within five seconds you have to call drbd_md_sync(). 33508c2ecf20Sopenharmony_ci */ 33518c2ecf20Sopenharmony_civoid drbd_md_mark_dirty(struct drbd_device *device) 33528c2ecf20Sopenharmony_ci{ 33538c2ecf20Sopenharmony_ci if (!test_and_set_bit(MD_DIRTY, &device->flags)) 33548c2ecf20Sopenharmony_ci mod_timer(&device->md_sync_timer, jiffies + 5*HZ); 33558c2ecf20Sopenharmony_ci} 33568c2ecf20Sopenharmony_ci 33578c2ecf20Sopenharmony_civoid drbd_uuid_move_history(struct drbd_device *device) __must_hold(local) 33588c2ecf20Sopenharmony_ci{ 33598c2ecf20Sopenharmony_ci int i; 33608c2ecf20Sopenharmony_ci 33618c2ecf20Sopenharmony_ci for (i = UI_HISTORY_START; i < UI_HISTORY_END; i++) 33628c2ecf20Sopenharmony_ci device->ldev->md.uuid[i+1] = device->ldev->md.uuid[i]; 33638c2ecf20Sopenharmony_ci} 33648c2ecf20Sopenharmony_ci 33658c2ecf20Sopenharmony_civoid __drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(local) 33668c2ecf20Sopenharmony_ci{ 33678c2ecf20Sopenharmony_ci if (idx == UI_CURRENT) { 33688c2ecf20Sopenharmony_ci if (device->state.role == R_PRIMARY) 33698c2ecf20Sopenharmony_ci val |= 1; 33708c2ecf20Sopenharmony_ci else 33718c2ecf20Sopenharmony_ci val &= ~((u64)1); 33728c2ecf20Sopenharmony_ci 33738c2ecf20Sopenharmony_ci drbd_set_ed_uuid(device, val); 33748c2ecf20Sopenharmony_ci } 33758c2ecf20Sopenharmony_ci 33768c2ecf20Sopenharmony_ci device->ldev->md.uuid[idx] = val; 33778c2ecf20Sopenharmony_ci drbd_md_mark_dirty(device); 33788c2ecf20Sopenharmony_ci} 33798c2ecf20Sopenharmony_ci 33808c2ecf20Sopenharmony_civoid _drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(local) 33818c2ecf20Sopenharmony_ci{ 33828c2ecf20Sopenharmony_ci unsigned long flags; 33838c2ecf20Sopenharmony_ci spin_lock_irqsave(&device->ldev->md.uuid_lock, flags); 33848c2ecf20Sopenharmony_ci __drbd_uuid_set(device, idx, val); 33858c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&device->ldev->md.uuid_lock, flags); 33868c2ecf20Sopenharmony_ci} 33878c2ecf20Sopenharmony_ci 33888c2ecf20Sopenharmony_civoid drbd_uuid_set(struct drbd_device *device, int idx, u64 val) __must_hold(local) 33898c2ecf20Sopenharmony_ci{ 33908c2ecf20Sopenharmony_ci unsigned long flags; 33918c2ecf20Sopenharmony_ci spin_lock_irqsave(&device->ldev->md.uuid_lock, flags); 33928c2ecf20Sopenharmony_ci if (device->ldev->md.uuid[idx]) { 33938c2ecf20Sopenharmony_ci drbd_uuid_move_history(device); 33948c2ecf20Sopenharmony_ci device->ldev->md.uuid[UI_HISTORY_START] = device->ldev->md.uuid[idx]; 33958c2ecf20Sopenharmony_ci } 33968c2ecf20Sopenharmony_ci __drbd_uuid_set(device, idx, val); 33978c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&device->ldev->md.uuid_lock, flags); 33988c2ecf20Sopenharmony_ci} 33998c2ecf20Sopenharmony_ci 34008c2ecf20Sopenharmony_ci/** 34018c2ecf20Sopenharmony_ci * drbd_uuid_new_current() - Creates a new current UUID 34028c2ecf20Sopenharmony_ci * @device: DRBD device. 34038c2ecf20Sopenharmony_ci * 34048c2ecf20Sopenharmony_ci * Creates a new current UUID, and rotates the old current UUID into 34058c2ecf20Sopenharmony_ci * the bitmap slot. Causes an incremental resync upon next connect. 34068c2ecf20Sopenharmony_ci */ 34078c2ecf20Sopenharmony_civoid drbd_uuid_new_current(struct drbd_device *device) __must_hold(local) 34088c2ecf20Sopenharmony_ci{ 34098c2ecf20Sopenharmony_ci u64 val; 34108c2ecf20Sopenharmony_ci unsigned long long bm_uuid; 34118c2ecf20Sopenharmony_ci 34128c2ecf20Sopenharmony_ci get_random_bytes(&val, sizeof(u64)); 34138c2ecf20Sopenharmony_ci 34148c2ecf20Sopenharmony_ci spin_lock_irq(&device->ldev->md.uuid_lock); 34158c2ecf20Sopenharmony_ci bm_uuid = device->ldev->md.uuid[UI_BITMAP]; 34168c2ecf20Sopenharmony_ci 34178c2ecf20Sopenharmony_ci if (bm_uuid) 34188c2ecf20Sopenharmony_ci drbd_warn(device, "bm UUID was already set: %llX\n", bm_uuid); 34198c2ecf20Sopenharmony_ci 34208c2ecf20Sopenharmony_ci device->ldev->md.uuid[UI_BITMAP] = device->ldev->md.uuid[UI_CURRENT]; 34218c2ecf20Sopenharmony_ci __drbd_uuid_set(device, UI_CURRENT, val); 34228c2ecf20Sopenharmony_ci spin_unlock_irq(&device->ldev->md.uuid_lock); 34238c2ecf20Sopenharmony_ci 34248c2ecf20Sopenharmony_ci drbd_print_uuids(device, "new current UUID"); 34258c2ecf20Sopenharmony_ci /* get it to stable storage _now_ */ 34268c2ecf20Sopenharmony_ci drbd_md_sync(device); 34278c2ecf20Sopenharmony_ci} 34288c2ecf20Sopenharmony_ci 34298c2ecf20Sopenharmony_civoid drbd_uuid_set_bm(struct drbd_device *device, u64 val) __must_hold(local) 34308c2ecf20Sopenharmony_ci{ 34318c2ecf20Sopenharmony_ci unsigned long flags; 34328c2ecf20Sopenharmony_ci if (device->ldev->md.uuid[UI_BITMAP] == 0 && val == 0) 34338c2ecf20Sopenharmony_ci return; 34348c2ecf20Sopenharmony_ci 34358c2ecf20Sopenharmony_ci spin_lock_irqsave(&device->ldev->md.uuid_lock, flags); 34368c2ecf20Sopenharmony_ci if (val == 0) { 34378c2ecf20Sopenharmony_ci drbd_uuid_move_history(device); 34388c2ecf20Sopenharmony_ci device->ldev->md.uuid[UI_HISTORY_START] = device->ldev->md.uuid[UI_BITMAP]; 34398c2ecf20Sopenharmony_ci device->ldev->md.uuid[UI_BITMAP] = 0; 34408c2ecf20Sopenharmony_ci } else { 34418c2ecf20Sopenharmony_ci unsigned long long bm_uuid = device->ldev->md.uuid[UI_BITMAP]; 34428c2ecf20Sopenharmony_ci if (bm_uuid) 34438c2ecf20Sopenharmony_ci drbd_warn(device, "bm UUID was already set: %llX\n", bm_uuid); 34448c2ecf20Sopenharmony_ci 34458c2ecf20Sopenharmony_ci device->ldev->md.uuid[UI_BITMAP] = val & ~((u64)1); 34468c2ecf20Sopenharmony_ci } 34478c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&device->ldev->md.uuid_lock, flags); 34488c2ecf20Sopenharmony_ci 34498c2ecf20Sopenharmony_ci drbd_md_mark_dirty(device); 34508c2ecf20Sopenharmony_ci} 34518c2ecf20Sopenharmony_ci 34528c2ecf20Sopenharmony_ci/** 34538c2ecf20Sopenharmony_ci * drbd_bmio_set_n_write() - io_fn for drbd_queue_bitmap_io() or drbd_bitmap_io() 34548c2ecf20Sopenharmony_ci * @device: DRBD device. 34558c2ecf20Sopenharmony_ci * 34568c2ecf20Sopenharmony_ci * Sets all bits in the bitmap and writes the whole bitmap to stable storage. 34578c2ecf20Sopenharmony_ci */ 34588c2ecf20Sopenharmony_ciint drbd_bmio_set_n_write(struct drbd_device *device) __must_hold(local) 34598c2ecf20Sopenharmony_ci{ 34608c2ecf20Sopenharmony_ci int rv = -EIO; 34618c2ecf20Sopenharmony_ci 34628c2ecf20Sopenharmony_ci drbd_md_set_flag(device, MDF_FULL_SYNC); 34638c2ecf20Sopenharmony_ci drbd_md_sync(device); 34648c2ecf20Sopenharmony_ci drbd_bm_set_all(device); 34658c2ecf20Sopenharmony_ci 34668c2ecf20Sopenharmony_ci rv = drbd_bm_write(device); 34678c2ecf20Sopenharmony_ci 34688c2ecf20Sopenharmony_ci if (!rv) { 34698c2ecf20Sopenharmony_ci drbd_md_clear_flag(device, MDF_FULL_SYNC); 34708c2ecf20Sopenharmony_ci drbd_md_sync(device); 34718c2ecf20Sopenharmony_ci } 34728c2ecf20Sopenharmony_ci 34738c2ecf20Sopenharmony_ci return rv; 34748c2ecf20Sopenharmony_ci} 34758c2ecf20Sopenharmony_ci 34768c2ecf20Sopenharmony_ci/** 34778c2ecf20Sopenharmony_ci * drbd_bmio_clear_n_write() - io_fn for drbd_queue_bitmap_io() or drbd_bitmap_io() 34788c2ecf20Sopenharmony_ci * @device: DRBD device. 34798c2ecf20Sopenharmony_ci * 34808c2ecf20Sopenharmony_ci * Clears all bits in the bitmap and writes the whole bitmap to stable storage. 34818c2ecf20Sopenharmony_ci */ 34828c2ecf20Sopenharmony_ciint drbd_bmio_clear_n_write(struct drbd_device *device) __must_hold(local) 34838c2ecf20Sopenharmony_ci{ 34848c2ecf20Sopenharmony_ci drbd_resume_al(device); 34858c2ecf20Sopenharmony_ci drbd_bm_clear_all(device); 34868c2ecf20Sopenharmony_ci return drbd_bm_write(device); 34878c2ecf20Sopenharmony_ci} 34888c2ecf20Sopenharmony_ci 34898c2ecf20Sopenharmony_cistatic int w_bitmap_io(struct drbd_work *w, int unused) 34908c2ecf20Sopenharmony_ci{ 34918c2ecf20Sopenharmony_ci struct drbd_device *device = 34928c2ecf20Sopenharmony_ci container_of(w, struct drbd_device, bm_io_work.w); 34938c2ecf20Sopenharmony_ci struct bm_io_work *work = &device->bm_io_work; 34948c2ecf20Sopenharmony_ci int rv = -EIO; 34958c2ecf20Sopenharmony_ci 34968c2ecf20Sopenharmony_ci if (work->flags != BM_LOCKED_CHANGE_ALLOWED) { 34978c2ecf20Sopenharmony_ci int cnt = atomic_read(&device->ap_bio_cnt); 34988c2ecf20Sopenharmony_ci if (cnt) 34998c2ecf20Sopenharmony_ci drbd_err(device, "FIXME: ap_bio_cnt %d, expected 0; queued for '%s'\n", 35008c2ecf20Sopenharmony_ci cnt, work->why); 35018c2ecf20Sopenharmony_ci } 35028c2ecf20Sopenharmony_ci 35038c2ecf20Sopenharmony_ci if (get_ldev(device)) { 35048c2ecf20Sopenharmony_ci drbd_bm_lock(device, work->why, work->flags); 35058c2ecf20Sopenharmony_ci rv = work->io_fn(device); 35068c2ecf20Sopenharmony_ci drbd_bm_unlock(device); 35078c2ecf20Sopenharmony_ci put_ldev(device); 35088c2ecf20Sopenharmony_ci } 35098c2ecf20Sopenharmony_ci 35108c2ecf20Sopenharmony_ci clear_bit_unlock(BITMAP_IO, &device->flags); 35118c2ecf20Sopenharmony_ci wake_up(&device->misc_wait); 35128c2ecf20Sopenharmony_ci 35138c2ecf20Sopenharmony_ci if (work->done) 35148c2ecf20Sopenharmony_ci work->done(device, rv); 35158c2ecf20Sopenharmony_ci 35168c2ecf20Sopenharmony_ci clear_bit(BITMAP_IO_QUEUED, &device->flags); 35178c2ecf20Sopenharmony_ci work->why = NULL; 35188c2ecf20Sopenharmony_ci work->flags = 0; 35198c2ecf20Sopenharmony_ci 35208c2ecf20Sopenharmony_ci return 0; 35218c2ecf20Sopenharmony_ci} 35228c2ecf20Sopenharmony_ci 35238c2ecf20Sopenharmony_ci/** 35248c2ecf20Sopenharmony_ci * drbd_queue_bitmap_io() - Queues an IO operation on the whole bitmap 35258c2ecf20Sopenharmony_ci * @device: DRBD device. 35268c2ecf20Sopenharmony_ci * @io_fn: IO callback to be called when bitmap IO is possible 35278c2ecf20Sopenharmony_ci * @done: callback to be called after the bitmap IO was performed 35288c2ecf20Sopenharmony_ci * @why: Descriptive text of the reason for doing the IO 35298c2ecf20Sopenharmony_ci * 35308c2ecf20Sopenharmony_ci * While IO on the bitmap happens we freeze application IO thus we ensure 35318c2ecf20Sopenharmony_ci * that drbd_set_out_of_sync() can not be called. This function MAY ONLY be 35328c2ecf20Sopenharmony_ci * called from worker context. It MUST NOT be used while a previous such 35338c2ecf20Sopenharmony_ci * work is still pending! 35348c2ecf20Sopenharmony_ci * 35358c2ecf20Sopenharmony_ci * Its worker function encloses the call of io_fn() by get_ldev() and 35368c2ecf20Sopenharmony_ci * put_ldev(). 35378c2ecf20Sopenharmony_ci */ 35388c2ecf20Sopenharmony_civoid drbd_queue_bitmap_io(struct drbd_device *device, 35398c2ecf20Sopenharmony_ci int (*io_fn)(struct drbd_device *), 35408c2ecf20Sopenharmony_ci void (*done)(struct drbd_device *, int), 35418c2ecf20Sopenharmony_ci char *why, enum bm_flag flags) 35428c2ecf20Sopenharmony_ci{ 35438c2ecf20Sopenharmony_ci D_ASSERT(device, current == first_peer_device(device)->connection->worker.task); 35448c2ecf20Sopenharmony_ci 35458c2ecf20Sopenharmony_ci D_ASSERT(device, !test_bit(BITMAP_IO_QUEUED, &device->flags)); 35468c2ecf20Sopenharmony_ci D_ASSERT(device, !test_bit(BITMAP_IO, &device->flags)); 35478c2ecf20Sopenharmony_ci D_ASSERT(device, list_empty(&device->bm_io_work.w.list)); 35488c2ecf20Sopenharmony_ci if (device->bm_io_work.why) 35498c2ecf20Sopenharmony_ci drbd_err(device, "FIXME going to queue '%s' but '%s' still pending?\n", 35508c2ecf20Sopenharmony_ci why, device->bm_io_work.why); 35518c2ecf20Sopenharmony_ci 35528c2ecf20Sopenharmony_ci device->bm_io_work.io_fn = io_fn; 35538c2ecf20Sopenharmony_ci device->bm_io_work.done = done; 35548c2ecf20Sopenharmony_ci device->bm_io_work.why = why; 35558c2ecf20Sopenharmony_ci device->bm_io_work.flags = flags; 35568c2ecf20Sopenharmony_ci 35578c2ecf20Sopenharmony_ci spin_lock_irq(&device->resource->req_lock); 35588c2ecf20Sopenharmony_ci set_bit(BITMAP_IO, &device->flags); 35598c2ecf20Sopenharmony_ci /* don't wait for pending application IO if the caller indicates that 35608c2ecf20Sopenharmony_ci * application IO does not conflict anyways. */ 35618c2ecf20Sopenharmony_ci if (flags == BM_LOCKED_CHANGE_ALLOWED || atomic_read(&device->ap_bio_cnt) == 0) { 35628c2ecf20Sopenharmony_ci if (!test_and_set_bit(BITMAP_IO_QUEUED, &device->flags)) 35638c2ecf20Sopenharmony_ci drbd_queue_work(&first_peer_device(device)->connection->sender_work, 35648c2ecf20Sopenharmony_ci &device->bm_io_work.w); 35658c2ecf20Sopenharmony_ci } 35668c2ecf20Sopenharmony_ci spin_unlock_irq(&device->resource->req_lock); 35678c2ecf20Sopenharmony_ci} 35688c2ecf20Sopenharmony_ci 35698c2ecf20Sopenharmony_ci/** 35708c2ecf20Sopenharmony_ci * drbd_bitmap_io() - Does an IO operation on the whole bitmap 35718c2ecf20Sopenharmony_ci * @device: DRBD device. 35728c2ecf20Sopenharmony_ci * @io_fn: IO callback to be called when bitmap IO is possible 35738c2ecf20Sopenharmony_ci * @why: Descriptive text of the reason for doing the IO 35748c2ecf20Sopenharmony_ci * 35758c2ecf20Sopenharmony_ci * freezes application IO while that the actual IO operations runs. This 35768c2ecf20Sopenharmony_ci * functions MAY NOT be called from worker context. 35778c2ecf20Sopenharmony_ci */ 35788c2ecf20Sopenharmony_ciint drbd_bitmap_io(struct drbd_device *device, int (*io_fn)(struct drbd_device *), 35798c2ecf20Sopenharmony_ci char *why, enum bm_flag flags) 35808c2ecf20Sopenharmony_ci{ 35818c2ecf20Sopenharmony_ci /* Only suspend io, if some operation is supposed to be locked out */ 35828c2ecf20Sopenharmony_ci const bool do_suspend_io = flags & (BM_DONT_CLEAR|BM_DONT_SET|BM_DONT_TEST); 35838c2ecf20Sopenharmony_ci int rv; 35848c2ecf20Sopenharmony_ci 35858c2ecf20Sopenharmony_ci D_ASSERT(device, current != first_peer_device(device)->connection->worker.task); 35868c2ecf20Sopenharmony_ci 35878c2ecf20Sopenharmony_ci if (do_suspend_io) 35888c2ecf20Sopenharmony_ci drbd_suspend_io(device); 35898c2ecf20Sopenharmony_ci 35908c2ecf20Sopenharmony_ci drbd_bm_lock(device, why, flags); 35918c2ecf20Sopenharmony_ci rv = io_fn(device); 35928c2ecf20Sopenharmony_ci drbd_bm_unlock(device); 35938c2ecf20Sopenharmony_ci 35948c2ecf20Sopenharmony_ci if (do_suspend_io) 35958c2ecf20Sopenharmony_ci drbd_resume_io(device); 35968c2ecf20Sopenharmony_ci 35978c2ecf20Sopenharmony_ci return rv; 35988c2ecf20Sopenharmony_ci} 35998c2ecf20Sopenharmony_ci 36008c2ecf20Sopenharmony_civoid drbd_md_set_flag(struct drbd_device *device, int flag) __must_hold(local) 36018c2ecf20Sopenharmony_ci{ 36028c2ecf20Sopenharmony_ci if ((device->ldev->md.flags & flag) != flag) { 36038c2ecf20Sopenharmony_ci drbd_md_mark_dirty(device); 36048c2ecf20Sopenharmony_ci device->ldev->md.flags |= flag; 36058c2ecf20Sopenharmony_ci } 36068c2ecf20Sopenharmony_ci} 36078c2ecf20Sopenharmony_ci 36088c2ecf20Sopenharmony_civoid drbd_md_clear_flag(struct drbd_device *device, int flag) __must_hold(local) 36098c2ecf20Sopenharmony_ci{ 36108c2ecf20Sopenharmony_ci if ((device->ldev->md.flags & flag) != 0) { 36118c2ecf20Sopenharmony_ci drbd_md_mark_dirty(device); 36128c2ecf20Sopenharmony_ci device->ldev->md.flags &= ~flag; 36138c2ecf20Sopenharmony_ci } 36148c2ecf20Sopenharmony_ci} 36158c2ecf20Sopenharmony_ciint drbd_md_test_flag(struct drbd_backing_dev *bdev, int flag) 36168c2ecf20Sopenharmony_ci{ 36178c2ecf20Sopenharmony_ci return (bdev->md.flags & flag) != 0; 36188c2ecf20Sopenharmony_ci} 36198c2ecf20Sopenharmony_ci 36208c2ecf20Sopenharmony_cistatic void md_sync_timer_fn(struct timer_list *t) 36218c2ecf20Sopenharmony_ci{ 36228c2ecf20Sopenharmony_ci struct drbd_device *device = from_timer(device, t, md_sync_timer); 36238c2ecf20Sopenharmony_ci drbd_device_post_work(device, MD_SYNC); 36248c2ecf20Sopenharmony_ci} 36258c2ecf20Sopenharmony_ci 36268c2ecf20Sopenharmony_ciconst char *cmdname(enum drbd_packet cmd) 36278c2ecf20Sopenharmony_ci{ 36288c2ecf20Sopenharmony_ci /* THINK may need to become several global tables 36298c2ecf20Sopenharmony_ci * when we want to support more than 36308c2ecf20Sopenharmony_ci * one PRO_VERSION */ 36318c2ecf20Sopenharmony_ci static const char *cmdnames[] = { 36328c2ecf20Sopenharmony_ci 36338c2ecf20Sopenharmony_ci [P_DATA] = "Data", 36348c2ecf20Sopenharmony_ci [P_DATA_REPLY] = "DataReply", 36358c2ecf20Sopenharmony_ci [P_RS_DATA_REPLY] = "RSDataReply", 36368c2ecf20Sopenharmony_ci [P_BARRIER] = "Barrier", 36378c2ecf20Sopenharmony_ci [P_BITMAP] = "ReportBitMap", 36388c2ecf20Sopenharmony_ci [P_BECOME_SYNC_TARGET] = "BecomeSyncTarget", 36398c2ecf20Sopenharmony_ci [P_BECOME_SYNC_SOURCE] = "BecomeSyncSource", 36408c2ecf20Sopenharmony_ci [P_UNPLUG_REMOTE] = "UnplugRemote", 36418c2ecf20Sopenharmony_ci [P_DATA_REQUEST] = "DataRequest", 36428c2ecf20Sopenharmony_ci [P_RS_DATA_REQUEST] = "RSDataRequest", 36438c2ecf20Sopenharmony_ci [P_SYNC_PARAM] = "SyncParam", 36448c2ecf20Sopenharmony_ci [P_PROTOCOL] = "ReportProtocol", 36458c2ecf20Sopenharmony_ci [P_UUIDS] = "ReportUUIDs", 36468c2ecf20Sopenharmony_ci [P_SIZES] = "ReportSizes", 36478c2ecf20Sopenharmony_ci [P_STATE] = "ReportState", 36488c2ecf20Sopenharmony_ci [P_SYNC_UUID] = "ReportSyncUUID", 36498c2ecf20Sopenharmony_ci [P_AUTH_CHALLENGE] = "AuthChallenge", 36508c2ecf20Sopenharmony_ci [P_AUTH_RESPONSE] = "AuthResponse", 36518c2ecf20Sopenharmony_ci [P_STATE_CHG_REQ] = "StateChgRequest", 36528c2ecf20Sopenharmony_ci [P_PING] = "Ping", 36538c2ecf20Sopenharmony_ci [P_PING_ACK] = "PingAck", 36548c2ecf20Sopenharmony_ci [P_RECV_ACK] = "RecvAck", 36558c2ecf20Sopenharmony_ci [P_WRITE_ACK] = "WriteAck", 36568c2ecf20Sopenharmony_ci [P_RS_WRITE_ACK] = "RSWriteAck", 36578c2ecf20Sopenharmony_ci [P_SUPERSEDED] = "Superseded", 36588c2ecf20Sopenharmony_ci [P_NEG_ACK] = "NegAck", 36598c2ecf20Sopenharmony_ci [P_NEG_DREPLY] = "NegDReply", 36608c2ecf20Sopenharmony_ci [P_NEG_RS_DREPLY] = "NegRSDReply", 36618c2ecf20Sopenharmony_ci [P_BARRIER_ACK] = "BarrierAck", 36628c2ecf20Sopenharmony_ci [P_STATE_CHG_REPLY] = "StateChgReply", 36638c2ecf20Sopenharmony_ci [P_OV_REQUEST] = "OVRequest", 36648c2ecf20Sopenharmony_ci [P_OV_REPLY] = "OVReply", 36658c2ecf20Sopenharmony_ci [P_OV_RESULT] = "OVResult", 36668c2ecf20Sopenharmony_ci [P_CSUM_RS_REQUEST] = "CsumRSRequest", 36678c2ecf20Sopenharmony_ci [P_RS_IS_IN_SYNC] = "CsumRSIsInSync", 36688c2ecf20Sopenharmony_ci [P_SYNC_PARAM89] = "SyncParam89", 36698c2ecf20Sopenharmony_ci [P_COMPRESSED_BITMAP] = "CBitmap", 36708c2ecf20Sopenharmony_ci [P_DELAY_PROBE] = "DelayProbe", 36718c2ecf20Sopenharmony_ci [P_OUT_OF_SYNC] = "OutOfSync", 36728c2ecf20Sopenharmony_ci [P_RS_CANCEL] = "RSCancel", 36738c2ecf20Sopenharmony_ci [P_CONN_ST_CHG_REQ] = "conn_st_chg_req", 36748c2ecf20Sopenharmony_ci [P_CONN_ST_CHG_REPLY] = "conn_st_chg_reply", 36758c2ecf20Sopenharmony_ci [P_RETRY_WRITE] = "retry_write", 36768c2ecf20Sopenharmony_ci [P_PROTOCOL_UPDATE] = "protocol_update", 36778c2ecf20Sopenharmony_ci [P_TRIM] = "Trim", 36788c2ecf20Sopenharmony_ci [P_RS_THIN_REQ] = "rs_thin_req", 36798c2ecf20Sopenharmony_ci [P_RS_DEALLOCATED] = "rs_deallocated", 36808c2ecf20Sopenharmony_ci [P_WSAME] = "WriteSame", 36818c2ecf20Sopenharmony_ci [P_ZEROES] = "Zeroes", 36828c2ecf20Sopenharmony_ci 36838c2ecf20Sopenharmony_ci /* enum drbd_packet, but not commands - obsoleted flags: 36848c2ecf20Sopenharmony_ci * P_MAY_IGNORE 36858c2ecf20Sopenharmony_ci * P_MAX_OPT_CMD 36868c2ecf20Sopenharmony_ci */ 36878c2ecf20Sopenharmony_ci }; 36888c2ecf20Sopenharmony_ci 36898c2ecf20Sopenharmony_ci /* too big for the array: 0xfffX */ 36908c2ecf20Sopenharmony_ci if (cmd == P_INITIAL_META) 36918c2ecf20Sopenharmony_ci return "InitialMeta"; 36928c2ecf20Sopenharmony_ci if (cmd == P_INITIAL_DATA) 36938c2ecf20Sopenharmony_ci return "InitialData"; 36948c2ecf20Sopenharmony_ci if (cmd == P_CONNECTION_FEATURES) 36958c2ecf20Sopenharmony_ci return "ConnectionFeatures"; 36968c2ecf20Sopenharmony_ci if (cmd >= ARRAY_SIZE(cmdnames)) 36978c2ecf20Sopenharmony_ci return "Unknown"; 36988c2ecf20Sopenharmony_ci return cmdnames[cmd]; 36998c2ecf20Sopenharmony_ci} 37008c2ecf20Sopenharmony_ci 37018c2ecf20Sopenharmony_ci/** 37028c2ecf20Sopenharmony_ci * drbd_wait_misc - wait for a request to make progress 37038c2ecf20Sopenharmony_ci * @device: device associated with the request 37048c2ecf20Sopenharmony_ci * @i: the struct drbd_interval embedded in struct drbd_request or 37058c2ecf20Sopenharmony_ci * struct drbd_peer_request 37068c2ecf20Sopenharmony_ci */ 37078c2ecf20Sopenharmony_ciint drbd_wait_misc(struct drbd_device *device, struct drbd_interval *i) 37088c2ecf20Sopenharmony_ci{ 37098c2ecf20Sopenharmony_ci struct net_conf *nc; 37108c2ecf20Sopenharmony_ci DEFINE_WAIT(wait); 37118c2ecf20Sopenharmony_ci long timeout; 37128c2ecf20Sopenharmony_ci 37138c2ecf20Sopenharmony_ci rcu_read_lock(); 37148c2ecf20Sopenharmony_ci nc = rcu_dereference(first_peer_device(device)->connection->net_conf); 37158c2ecf20Sopenharmony_ci if (!nc) { 37168c2ecf20Sopenharmony_ci rcu_read_unlock(); 37178c2ecf20Sopenharmony_ci return -ETIMEDOUT; 37188c2ecf20Sopenharmony_ci } 37198c2ecf20Sopenharmony_ci timeout = nc->ko_count ? nc->timeout * HZ / 10 * nc->ko_count : MAX_SCHEDULE_TIMEOUT; 37208c2ecf20Sopenharmony_ci rcu_read_unlock(); 37218c2ecf20Sopenharmony_ci 37228c2ecf20Sopenharmony_ci /* Indicate to wake up device->misc_wait on progress. */ 37238c2ecf20Sopenharmony_ci i->waiting = true; 37248c2ecf20Sopenharmony_ci prepare_to_wait(&device->misc_wait, &wait, TASK_INTERRUPTIBLE); 37258c2ecf20Sopenharmony_ci spin_unlock_irq(&device->resource->req_lock); 37268c2ecf20Sopenharmony_ci timeout = schedule_timeout(timeout); 37278c2ecf20Sopenharmony_ci finish_wait(&device->misc_wait, &wait); 37288c2ecf20Sopenharmony_ci spin_lock_irq(&device->resource->req_lock); 37298c2ecf20Sopenharmony_ci if (!timeout || device->state.conn < C_CONNECTED) 37308c2ecf20Sopenharmony_ci return -ETIMEDOUT; 37318c2ecf20Sopenharmony_ci if (signal_pending(current)) 37328c2ecf20Sopenharmony_ci return -ERESTARTSYS; 37338c2ecf20Sopenharmony_ci return 0; 37348c2ecf20Sopenharmony_ci} 37358c2ecf20Sopenharmony_ci 37368c2ecf20Sopenharmony_civoid lock_all_resources(void) 37378c2ecf20Sopenharmony_ci{ 37388c2ecf20Sopenharmony_ci struct drbd_resource *resource; 37398c2ecf20Sopenharmony_ci int __maybe_unused i = 0; 37408c2ecf20Sopenharmony_ci 37418c2ecf20Sopenharmony_ci mutex_lock(&resources_mutex); 37428c2ecf20Sopenharmony_ci local_irq_disable(); 37438c2ecf20Sopenharmony_ci for_each_resource(resource, &drbd_resources) 37448c2ecf20Sopenharmony_ci spin_lock_nested(&resource->req_lock, i++); 37458c2ecf20Sopenharmony_ci} 37468c2ecf20Sopenharmony_ci 37478c2ecf20Sopenharmony_civoid unlock_all_resources(void) 37488c2ecf20Sopenharmony_ci{ 37498c2ecf20Sopenharmony_ci struct drbd_resource *resource; 37508c2ecf20Sopenharmony_ci 37518c2ecf20Sopenharmony_ci for_each_resource(resource, &drbd_resources) 37528c2ecf20Sopenharmony_ci spin_unlock(&resource->req_lock); 37538c2ecf20Sopenharmony_ci local_irq_enable(); 37548c2ecf20Sopenharmony_ci mutex_unlock(&resources_mutex); 37558c2ecf20Sopenharmony_ci} 37568c2ecf20Sopenharmony_ci 37578c2ecf20Sopenharmony_ci#ifdef CONFIG_DRBD_FAULT_INJECTION 37588c2ecf20Sopenharmony_ci/* Fault insertion support including random number generator shamelessly 37598c2ecf20Sopenharmony_ci * stolen from kernel/rcutorture.c */ 37608c2ecf20Sopenharmony_cistruct fault_random_state { 37618c2ecf20Sopenharmony_ci unsigned long state; 37628c2ecf20Sopenharmony_ci unsigned long count; 37638c2ecf20Sopenharmony_ci}; 37648c2ecf20Sopenharmony_ci 37658c2ecf20Sopenharmony_ci#define FAULT_RANDOM_MULT 39916801 /* prime */ 37668c2ecf20Sopenharmony_ci#define FAULT_RANDOM_ADD 479001701 /* prime */ 37678c2ecf20Sopenharmony_ci#define FAULT_RANDOM_REFRESH 10000 37688c2ecf20Sopenharmony_ci 37698c2ecf20Sopenharmony_ci/* 37708c2ecf20Sopenharmony_ci * Crude but fast random-number generator. Uses a linear congruential 37718c2ecf20Sopenharmony_ci * generator, with occasional help from get_random_bytes(). 37728c2ecf20Sopenharmony_ci */ 37738c2ecf20Sopenharmony_cistatic unsigned long 37748c2ecf20Sopenharmony_ci_drbd_fault_random(struct fault_random_state *rsp) 37758c2ecf20Sopenharmony_ci{ 37768c2ecf20Sopenharmony_ci long refresh; 37778c2ecf20Sopenharmony_ci 37788c2ecf20Sopenharmony_ci if (!rsp->count--) { 37798c2ecf20Sopenharmony_ci get_random_bytes(&refresh, sizeof(refresh)); 37808c2ecf20Sopenharmony_ci rsp->state += refresh; 37818c2ecf20Sopenharmony_ci rsp->count = FAULT_RANDOM_REFRESH; 37828c2ecf20Sopenharmony_ci } 37838c2ecf20Sopenharmony_ci rsp->state = rsp->state * FAULT_RANDOM_MULT + FAULT_RANDOM_ADD; 37848c2ecf20Sopenharmony_ci return swahw32(rsp->state); 37858c2ecf20Sopenharmony_ci} 37868c2ecf20Sopenharmony_ci 37878c2ecf20Sopenharmony_cistatic char * 37888c2ecf20Sopenharmony_ci_drbd_fault_str(unsigned int type) { 37898c2ecf20Sopenharmony_ci static char *_faults[] = { 37908c2ecf20Sopenharmony_ci [DRBD_FAULT_MD_WR] = "Meta-data write", 37918c2ecf20Sopenharmony_ci [DRBD_FAULT_MD_RD] = "Meta-data read", 37928c2ecf20Sopenharmony_ci [DRBD_FAULT_RS_WR] = "Resync write", 37938c2ecf20Sopenharmony_ci [DRBD_FAULT_RS_RD] = "Resync read", 37948c2ecf20Sopenharmony_ci [DRBD_FAULT_DT_WR] = "Data write", 37958c2ecf20Sopenharmony_ci [DRBD_FAULT_DT_RD] = "Data read", 37968c2ecf20Sopenharmony_ci [DRBD_FAULT_DT_RA] = "Data read ahead", 37978c2ecf20Sopenharmony_ci [DRBD_FAULT_BM_ALLOC] = "BM allocation", 37988c2ecf20Sopenharmony_ci [DRBD_FAULT_AL_EE] = "EE allocation", 37998c2ecf20Sopenharmony_ci [DRBD_FAULT_RECEIVE] = "receive data corruption", 38008c2ecf20Sopenharmony_ci }; 38018c2ecf20Sopenharmony_ci 38028c2ecf20Sopenharmony_ci return (type < DRBD_FAULT_MAX) ? _faults[type] : "**Unknown**"; 38038c2ecf20Sopenharmony_ci} 38048c2ecf20Sopenharmony_ci 38058c2ecf20Sopenharmony_ciunsigned int 38068c2ecf20Sopenharmony_ci_drbd_insert_fault(struct drbd_device *device, unsigned int type) 38078c2ecf20Sopenharmony_ci{ 38088c2ecf20Sopenharmony_ci static struct fault_random_state rrs = {0, 0}; 38098c2ecf20Sopenharmony_ci 38108c2ecf20Sopenharmony_ci unsigned int ret = ( 38118c2ecf20Sopenharmony_ci (drbd_fault_devs == 0 || 38128c2ecf20Sopenharmony_ci ((1 << device_to_minor(device)) & drbd_fault_devs) != 0) && 38138c2ecf20Sopenharmony_ci (((_drbd_fault_random(&rrs) % 100) + 1) <= drbd_fault_rate)); 38148c2ecf20Sopenharmony_ci 38158c2ecf20Sopenharmony_ci if (ret) { 38168c2ecf20Sopenharmony_ci drbd_fault_count++; 38178c2ecf20Sopenharmony_ci 38188c2ecf20Sopenharmony_ci if (__ratelimit(&drbd_ratelimit_state)) 38198c2ecf20Sopenharmony_ci drbd_warn(device, "***Simulating %s failure\n", 38208c2ecf20Sopenharmony_ci _drbd_fault_str(type)); 38218c2ecf20Sopenharmony_ci } 38228c2ecf20Sopenharmony_ci 38238c2ecf20Sopenharmony_ci return ret; 38248c2ecf20Sopenharmony_ci} 38258c2ecf20Sopenharmony_ci#endif 38268c2ecf20Sopenharmony_ci 38278c2ecf20Sopenharmony_ciconst char *drbd_buildtag(void) 38288c2ecf20Sopenharmony_ci{ 38298c2ecf20Sopenharmony_ci /* DRBD built from external sources has here a reference to the 38308c2ecf20Sopenharmony_ci git hash of the source code. */ 38318c2ecf20Sopenharmony_ci 38328c2ecf20Sopenharmony_ci static char buildtag[38] = "\0uilt-in"; 38338c2ecf20Sopenharmony_ci 38348c2ecf20Sopenharmony_ci if (buildtag[0] == 0) { 38358c2ecf20Sopenharmony_ci#ifdef MODULE 38368c2ecf20Sopenharmony_ci sprintf(buildtag, "srcversion: %-24s", THIS_MODULE->srcversion); 38378c2ecf20Sopenharmony_ci#else 38388c2ecf20Sopenharmony_ci buildtag[0] = 'b'; 38398c2ecf20Sopenharmony_ci#endif 38408c2ecf20Sopenharmony_ci } 38418c2ecf20Sopenharmony_ci 38428c2ecf20Sopenharmony_ci return buildtag; 38438c2ecf20Sopenharmony_ci} 38448c2ecf20Sopenharmony_ci 38458c2ecf20Sopenharmony_cimodule_init(drbd_init) 38468c2ecf20Sopenharmony_cimodule_exit(drbd_cleanup) 38478c2ecf20Sopenharmony_ci 38488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drbd_conn_str); 38498c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drbd_role_str); 38508c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drbd_disk_str); 38518c2ecf20Sopenharmony_ciEXPORT_SYMBOL(drbd_set_st_err_str); 3852