FreeBSD と Linux の rmt

| No Comments | No TrackBacks

研究室のファイルサーバは幾つかあるが、メジャーな奴は (残念なことに) Linux で、xfs を使っている。で、テープドライブのつながっているホストは FreeBSD なのだが、こいつに xfsdump しようとすると、

rmtopen: remote host type, "FreeBSD", is unknown to librmt.

というメッセージが出て、dump は始まるものの、ファイルサイズなどは無視されて、テープの終わりまでに dump が終了しなければそのまま abort 、という結末になってしまう。で、昔 Solaris と FreeBSD と Linux をごっちゃにして使っていた頃は、そんなの気にしたことなかったので、なんでだろうなー、と調べていると、librmt というのはどうやら、xfsdump のソースに含まれているライブラリらしい。それに、Linux の rmt はどうやら BSD 由来のものであり、rmt が理解するコマンドは Linux でも FreeBSD でも全く同じようだ。rmt のコマンドには、uname を返すようなものはないので、

ということで、xfsdump のソース取ってきて眺めてみた。librmt/rmtopen.c が怪しい。
まず、uname は rsh 経由で呼ばれているようだ。


170 snprintf(cmd, sizeof(cmd), "%s %s uname", rsh_path, system);
173 rmt_f = popen(cmd, "r");
183 char *c = fgets(uname, sizeof(uname), rmt_f);

検索に使われているテーブルはたぶんこれ。

50 struct uname_table uname_table[] =
51 { {UNAME_LINUX, "Linux"}, {UNAME_IRIX, "IRIX"}, {0,0} };

で、ここまでは簡単そうなのだが、rmt が I とか S で扱う構造体には互換性がなさそうだ。rmtioctl.c を見る限り、I (MTIOCOP) は使っていなそうだが、S (MTIOCGET) のほうは使う模様。これは、mtget 構造体をそのまま返すんじゃないかと思う。

rmtioctl.c には、


47 struct linux32_mtget
48 {
49 int32_t mt_type; /* Type of magtape device. */
50 int32_t mt_resid; /* Residual count: */
51 /* The following registers are device dependent. */
52 int32_t mt_dsreg; /* Status register. */
53 int32_t mt_gstat; /* Generic (device independent) status. */
54 int32_t mt_erreg; /* Error register. */
55 /* The next two fields are not always used. */
56 int32_t mt_fileno; /* Number of current file on tape. */
57 int32_t mt_blkno; /* Current block number. */
58 };

というのがあり、一方 FreeBSD の /usr/include/sys/mtio.h

110 struct mtget {
111 short mt_type; /* type of magtape device */
112 /* the following two registers are grossly device dependent */
113 short mt_dsreg; /* ``drive status'' register */
114 short mt_erreg; /* ``error'' register */
115 /* end device-dependent registers */
122 short mt_resid; /* residual count */
123 #if defined (__FreeBSD__)
124 int32_t mt_blksiz; /* presently operating blocksize */
125 int32_t mt_density; /* presently operating density */
126 u_int32_t mt_comp; /* presently operating compression */
127 int32_t mt_blksiz0; /* blocksize for mode 0 */
128 int32_t mt_blksiz1; /* blocksize for mode 1 */
129 int32_t mt_blksiz2; /* blocksize for mode 2 */
130 int32_t mt_blksiz3; /* blocksize for mode 3 */
131 int32_t mt_density0; /* density for mode 0 */
132 int32_t mt_density1; /* density for mode 1 */
133 int32_t mt_density2; /* density for mode 2 */
134 int32_t mt_density3; /* density for mode 3 */
135 /* the following are not yet implemented */
136 u_int32_t mt_comp0; /* compression type for mode 0 */
137 u_int32_t mt_comp1; /* compression type for mode 1 */
138 u_int32_t mt_comp2; /* compression type for mode 2 */
139 u_int32_t mt_comp3; /* compression type for mode 3 */
140 /* end not yet implemented */
141 #endif
142 int32_t mt_fileno; /* relative file number of current posit
ion */
143 int32_t mt_blkno; /* relative block number of current posi
tion */
144 };

みたいな感じで、圧倒的に FreeBSD のほうが詳しい情報が返ってくるのであり、こりゃ互換性はないね。というわけで、大幅に手を加える必要がありそうだ。IRIX の場合、最終的には

364 if (RMTHOST(fildes) == UNAME_IRIX) {
365 struct mtget *dstp = (struct mtget *)arg;
366 struct irix_mtget *srcp = (struct irix_mtget *)irixget;
367 short status = srcp->mt_dsreg;
368
369 dstp->mt_type = srcp->mt_type;
370 dstp->mt_erreg = srcp->mt_erreg;
371 dstp->mt_resid = srcp->mt_resid;
372 dstp->mt_fileno = srcp->mt_fileno;
373 dstp->mt_blkno = srcp->mt_blkno;
374 dstp->mt_dsreg = srcp->mt_dsreg; /* different semantics */
375
376 /* need to do tape status conversions */
377 dstp->mt_gstat = 0;
378 if (status & IRIX_MT_EOT)
379 dstp->mt_gstat |= GMT_EOT(0xffffffff);
380 if (status & IRIX_MT_BOT)
381 dstp->mt_gstat |= GMT_BOT(0xffffffff);
382 if (status & IRIX_MT_WPROT)
383 dstp->mt_gstat |= GMT_WR_PROT(0xffffffff);
384 if (status & IRIX_MT_ONL)
385 dstp->mt_gstat |= GMT_ONLINE(0xffffffff);
386 if (status & IRIX_MT_EOD)
387 dstp->mt_gstat |= GMT_EOD(0xffffffff);
388 if (status & IRIX_MT_FMK)
389 dstp->mt_gstat |= GMT_EOF(0xffffffff);
390 if (status & IRIX_MT_EW)
391 ;/* No GMT_ to map it to */
392 }

みたいにして、32bit Linux な mtget に反映されるし、32bit Linux の場合は、

393 else if (islinux32) {
394 struct mtget *dstp = (struct mtget *)arg;
395 struct linux32_mtget *srcp = (struct linux32_mtget *)linux32get;
396
397 dstp->mt_type = srcp->mt_type;
398 dstp->mt_erreg = srcp->mt_erreg;
399 dstp->mt_resid = srcp->mt_resid;
400 dstp->mt_fileno = srcp->mt_fileno;
401 dstp->mt_blkno = srcp->mt_blkno;
402 dstp->mt_dsreg = srcp->mt_dsreg;
403 dstp->mt_gstat = srcp->mt_gstat;
404 }

とするだけだ。こんな感じのを書いてやれば良さそう (ほんとはこの手前で、必要な場合にはバイトオーダの変換を行っているのだけれど、僕が使うのは今のところぜんぶ x86 だから手抜きをすることにする。Solaris なファイルサーバがあるという理想的な環境では、話が変わるわけだが...)。

FreeBSD の mtget から Linux の mtget にそのまま値を渡して良さそうなのは、
- mt_type (short → int32)
- mt_resid (short → int32: でもこれって 32kB だとすぐあふれるから、違う IOCTL を使うべきらしい)
- mt_dsreg (short → int32)
- mt_erreg (short → int32)
- mt_fileno (int32 → int32)
- mt_blkno (int32 → int32)
で、変換しなければならない (かもしれない) のは、
- mt_gstat ( ? → int32)
なのだが、これは FreeBSD の mtget には、該当する値がない気がする。これはつまり、テープの終わりとかが検出できないのであり、何本ものテープにまたがって dump する場合には非常に問題なような気もする。しかし、実際のところ xfsdump はこの変数を使っていないように見えるので、とりあえず 0 にしときゃいいんではないだろうか...?

(きっと、続く)

No TrackBacks

TrackBack URL: http://yasu2.prosou.nu/mt/mt-tb.cgi/1401

Leave a comment

OpenID accepted here Learn more about OpenID
Powered by Movable Type 5.02

August 2010

Sun Mon Tue Wed Thu Fri Sat
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        

About this Entry

This page contains a single entry by Yasunori Osana published on August 12, 2007 10:34 PM.

overdrive:/dev/DVD was the previous entry in this blog.

EmacsでTAB連打? is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.