Linuxブロックデバイスのリクエストキューを特定するにはどうすればよいですか?


80

ネットワーク経由でハードディスクを接続するこのドライバーに取り組んでいます。コンピューターで2つ以上のハードディスクを有効にすると、最初の1つだけがパーティションを調べて識別されるというバグがあります。その結果、hdaに1つのパーティションがあり、hdbに1つのパーティションがある場合、hdaに接続するとすぐに、マウントできるパーティションができます。したがって、hda1は、マウントされるとすぐにblkidxyz123を取得します。しかし、先に進んでhdb1をマウントすると、同じblkidが表示され、実際、ドライバーはhdbではなくhdaから読み取っています。

だから、運転手がめちゃくちゃになっているところを見つけたと思います。以下は、間違ったデバイスにアクセスしているように見える最初の場所に置いたdump_stackを含むデバッグ出力です。

コードセクションは次のとおりです。

/*basically, this is just the request_queue processor. In the log output that
  follows, the second device, (hdb) has just been connected, right after hda
  was connected and hda1 was mounted to the system. */

void nblk_request_proc(struct request_queue *q)
{
struct request *req;
ndas_error_t err = NDAS_OK;

dump_stack();

while((req = NBLK_NEXT_REQUEST(q)) != NULL)
{
    dbgl_blk(8,"processing queue request from slot %d",SLOT_R(req));

    if (test_bit(NDAS_FLAG_QUEUE_SUSPENDED, &(NDAS_GET_SLOT_DEV(SLOT_R(req))->queue_flags)))  {
        printk ("ndas: Queue is suspended\n");
        /* Queue is suspended */
#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) )
        blk_start_request(req);
#else
        blkdev_dequeue_request(req);
#endif

これがログ出力です。何が起こっているのか、どこで悪い電話がかかってくるのかを理解するのに役立つコメントをいくつか追加しました。

  /* Just below here you can see "slot" mentioned many times. This is the 
     identification for the network case in which the hd is connected to the 
     network. So you will see slot 2 in this log because the first device has 
     already been connected and mounted. */

  kernel: [231644.155503] BL|4|slot_enable|/driver/block/ctrldev.c:281|adding disk: slot=2, first_minor=16, capacity=976769072|nd/dpcd1,64:15:44.38,3828:10
  kernel: [231644.155588] BL|3|ndop_open|/driver/block/ops.c:233|ing bdev=f6823400|nd/dpcd1,64:15:44.38,3720:10
  kernel: [231644.155598] BL|2|ndop_open|/driver/block/ops.c:247|slot =0x2|nd/dpcd1,64:15:44.38,3720:10
  kernel: [231644.155606] BL|2|ndop_open|/driver/block/ops.c:248|dev_t=0x3c00010|nd/dpcd1,64:15:44.38,3720:10
  kernel: [231644.155615] ND|3|ndas_query_slot|netdisk/nddev.c:791|slot=2 sdev=d33e2080|nd/dpcd1,64:15:44.38,3696:10
  kernel: [231644.155624] ND|3|ndas_query_slot|netdisk/nddev.c:817|ed|nd/dpcd1,64:15:44.38,3696:10
  kernel: [231644.155631] BL|3|ndop_open|/driver/block/ops.c:326|mode=1|nd/dpcd1,64:15:44.38,3720:10
  kernel: [231644.155640] BL|3|ndop_open|/driver/block/ops.c:365|ed open|nd/dpcd1,64:15:44.38,3724:10
  kernel: [231644.155653] BL|8|ndop_revalidate_disk|/driver/block/ops.c:2334|gendisk=c6afd800={major=60,first_minor=16,minors=0x10,disk_name=ndas-44700486-0,private_data=00000002,capacity=%lld}|nd/dpcd1,64:15:44.38,3660:10
  kernel: [231644.155668] BL|8|ndop_revalidate_disk|/driver/block/ops.c:2346|ed|nd/dpcd1,64:15:44.38,3652:10

  /* So at this point the hard disk is added (gendisk=c6...) and the identifications
     all match the network device. The driver is now about to begin scanning the 
     hard drive for existing partitions. the little 'ed', at the end of the previous
     line indicates that revalidate_disk has finished it's job. 

     Also, I think the request queue is indicated by the output dpcd1 near the very
     end of the line. 

     Now below we have entered the function that is pasted above. In the function
     you can see that the slot can be determined by the queue. And the log output
     after the stack dump shows it is from slot 1. (The first network drive that was
     already mounted.) */

        kernel: [231644.155677]  ndas-44700486-0:Pid: 467, comm: nd/dpcd1 Tainted: P           2.6.32-5-686 #1
  kernel: [231644.155711] Call Trace:
  kernel: [231644.155723]  [<fc5a7685>] ? nblk_request_proc+0x9/0x10c [ndas_block]
  kernel: [231644.155732]  [<c11298db>] ? __generic_unplug_device+0x23/0x25
  kernel: [231644.155737]  [<c1129afb>] ? generic_unplug_device+0x1e/0x2e
  kernel: [231644.155743]  [<c1123090>] ? blk_unplug+0x2e/0x31
  kernel: [231644.155750]  [<c10cceec>] ? block_sync_page+0x33/0x34
  kernel: [231644.155756]  [<c108770c>] ? sync_page+0x35/0x3d
  kernel: [231644.155763]  [<c126d568>] ? __wait_on_bit_lock+0x31/0x6a
  kernel: [231644.155768]  [<c10876d7>] ? sync_page+0x0/0x3d
  kernel: [231644.155773]  [<c10876aa>] ? __lock_page+0x76/0x7e
  kernel: [231644.155780]  [<c1043f1f>] ? wake_bit_function+0x0/0x3c
  kernel: [231644.155785]  [<c1087b76>] ? do_read_cache_page+0xdf/0xf8
  kernel: [231644.155791]  [<c10d21b9>] ? blkdev_readpage+0x0/0xc
  kernel: [231644.155796]  [<c1087bbc>] ? read_cache_page_async+0x14/0x18
  kernel: [231644.155801]  [<c1087bc9>] ? read_cache_page+0x9/0xf
  kernel: [231644.155808]  [<c10ed6fc>] ? read_dev_sector+0x26/0x60
  kernel: [231644.155813]  [<c10ee368>] ? adfspart_check_ICS+0x20/0x14c
  kernel: [231644.155819]  [<c10ee138>] ? rescan_partitions+0x17e/0x378
  kernel: [231644.155825]  [<c10ee348>] ? adfspart_check_ICS+0x0/0x14c
  kernel: [231644.155830]  [<c10d26a3>] ? __blkdev_get+0x225/0x2c7
  kernel: [231644.155836]  [<c10ed7e6>] ? register_disk+0xb0/0xfd
  kernel: [231644.155843]  [<c112e33b>] ? add_disk+0x9a/0xe8
  kernel: [231644.155848]  [<c112dafd>] ? exact_match+0x0/0x4
  kernel: [231644.155853]  [<c112deae>] ? exact_lock+0x0/0xd
  kernel: [231644.155861]  [<fc5a8b80>] ? slot_enable+0x405/0x4a5 [ndas_block]
  kernel: [231644.155868]  [<fc5a8c63>] ? ndcmd_enabled_handler+0x43/0x9e [ndas_block]
  kernel: [231644.155874]  [<fc5a8c20>] ? ndcmd_enabled_handler+0x0/0x9e [ndas_block]
  kernel: [231644.155891]  [<fc54b22b>] ? notify_func+0x38/0x4b [ndas_core]
  kernel: [231644.155906]  [<fc561cba>] ? _dpc_cancel+0x17c/0x626 [ndas_core]
  kernel: [231644.155919]  [<fc562005>] ? _dpc_cancel+0x4c7/0x626 [ndas_core]
  kernel: [231644.155933]  [<fc561cba>] ? _dpc_cancel+0x17c/0x626 [ndas_core]
  kernel: [231644.155941]  [<c1003d47>] ? kernel_thread_helper+0x7/0x10

  /* here are the output of the driver debugs. They show that this operation is
     being performed on the first devices request queue. */

  kernel: [231644.155948] BL|8|nblk_request_proc|/driver/block/block26.c:494|processing queue request from slot 1|nd/dpcd1,64:15:44.38,3408:10
  kernel: [231644.155959] BL|8|nblk_handle_io|/driver/block/block26.c:374|struct ndas_slot sd = NDAS GET SLOT DEV(slot 1)
  kernel: [231644.155966] |nd/dpcd1,64:15:44.38,3328:10
  kernel: [231644.155970] BL|8|nblk_handle_io|/driver/block/block26.c:458|case READA call ndas_read(slot=1, ndas_req)|nd/dpcd1,64:15:44.38,3328:10
  kernel: [231644.155979] ND|8|ndas_read|netdisk/nddev.c:824|read io: slot=1, cmd=0, req=x00|nd/dpcd1,64:15:44.38,3320:10

これで十分な背景情報になるといいのですが。現時点で明らかな質問は、「request_queuesはいつどこに割り当てられるのか」ということかもしれません。

これは、add_disk関数の少し前に処理されます。ディスクの追加は、ログ出力の最初の行です。

slot->disk = NULL;
spin_lock_init(&slot->lock);
slot->queue = blk_init_queue(
    nblk_request_proc, 
    &slot->lock
);

私の知る限り、これは標準的な操作です。では、元の質問に戻りましょう。リクエストキューをどこかで見つけて、新しいデバイスごとにインクリメントまたは一意であることを確認できますか、それともLinuxカーネルはメジャー番号ごとに1つのキューのみを使用しますか?このドライバーが2つの異なるブロックストレージに同じキューをロードしている理由を発見し、それが初期登録プロセス中に重複したblkidを引き起こしているかどうかを判断したいと思います。

私のためにこの状況を見てくれてありがとう。


8
KernelNewbiesメーリングリストを試してみることをお勧めします。
dlitz 2011

1
@ndasusers:新しいxx_request(req)を開始する前に、リクエストの「タイプ」を確認するのが理にかなっている場合があります。たぶん、着信要求は、すでにマウントされているhdaへの読み取りアクセスに関するものであり、それを新しいプラグインされたhdbに関連するものとして処理します。
boto 2012年

1
あなたはhdab1を書いてマウントしましたが、それも出てきます。hdb1のことですか?
イヴマーティン

メジャー番号とマイナー番号が同じ2つのデバイスを使用することはできないと思います。ドライブのマイナー番号とメジャー番号は何ですか?
イーサン

いい質問ですが、nbdを再実装しようとしていますか?
IanNorton 2012

回答:



0

この質問を投稿するに至ったバグの解決策を共有します。実際には、デバイス要求キューを識別する方法の質問には答えていませんが。

上記のコードでは、次のとおりです。

if (test_bit(NDAS_FLAG_QUEUE_SUSPENDED, 
       &(NDAS_GET_SLOT_DEV(SLOT_R(req))->queue_flags))) 

さて、その「SLOT_R(req)」がトラブルの原因でした。これは、gendiskデバイスを返す場所で定義されています。

#define SLOT_R(_request_) SLOT((_request_)->rq_disk)

これによりディスクが返されましたが、後のさまざまな操作に適切な値ではありませんでした。したがって、追加のブロックデバイスが読み込まれると、この関数は基本的に1を返し続けました(ブール値として処理されていたと思います)。したがって、すべての要求はディスク1の要求キューに積み上げられました。

修正は、ディスクがシステムに追加されたときにディスクのprivate_dataにすでに保存されていた正しいディスク識別値にアクセスすることでした。

Correct identifier definition:
   #define SLOT_R(_request_) ( (int) _request_->rq_disk->private_data )

How the correct disk number was stored.
   slot->disk->queue = slot->queue;
   slot->disk->private_data = (void*) (long) s;  <-- 's' is the disk id
   slot->queue_flags = 0;

これで、プライベートデータから正しいディスクIDが返されるため、すべての要求が正しいキューに送られます。

前述のように、これはキューを識別する方法を示していません。知識のない推測は次のようになります。

 x = (int) _request_->rq_disk->queue->id;

参照。Linuxでのrequest_queue機能 http://lxr.free-electrons.com/source/include/linux/blkdev.h#L270&321

助けてくれてありがとう!


以前のコメントへの返信:-boto:リクエストはこの関数でさらにテストされます。SLOT_Rが使用されていた場合、エラーは実際には別の場所で発生していました。-イヴ:訂正してくれてありがとう。それは私の間違いでした。-イーサン:ディスクのメジャーとマイナーは、ほとんどすべての場合に発見されたので、正しく表示されます。-イアン:これはNDASです。これはnbdと非常によく似ており、LAN上にブロックストレージを提供します。ただし、NDASは実際のハードウェアです。他の密接な実装はAoEです。
ndasusers 2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.