ℹ️本記事は古いコンテンツを変換して表示しています。
表示が崩れたり、リンクが正しくない可能性があります。ご了承ください。
ℹ️本記事は古いコンテンツを変換して表示しています。
表示が崩れたり、リンクが正しくない可能性があります。ご了承ください。
2016/01/19 01:01 : GlusterFSのdisperseを試す(その3)
この間の続き。やっと解決。FreeBSDとLinuxのmajor/minor/makedev関数の違い、statが通常ファイルに対して返すrdev値の違いによる問題。
[2016-01-15 01:01:54.466105] W [ec-combine.c:76:ec_iatt_combine] 0-gv0-disperse-0: Failed to combine iatt (inode: 11735403145588290470-11735403145588290470, links: 1-1, uid: 0-0, gid: 0-0, rdev: 322123661424-571232551144, size: 148176896-148209664, mode: 100644-100644)
sizeはとりあえずいい。healなんだから、大きさが違うこともある。でもrdevとやらは良くない匂いがする。
rdevはそもそもキャラクタデバイスなんかを表す番号のはず。エラーログにある数字は一体なんなのか。
(gdb) printf "%16llx\n%16llx\n", 322123661424, 571232551144 4b00110070 85001d00e8
ますます怪しい。この値を作っているのはlibglusterfs/src/iatt.h
の以下の部分。
static inline int iatt_from_stat (struct iatt *iatt, struct stat *stat) { /* snip */ iatt->ia_rdev = ia_makedev (major (stat->st_rdev), minor (stat->st_rdev));
これはおなじみstruct stat
から、glusterfsの内部で使うstruct iatt
に変換している模様。ではia_makedev
とmajor
、minor
はどこにあるのか。ia_makedev
はすぐ近く(同じiatt.h)に。
ia_makedev (uint32_t ia_maj, uint32_t ia_min) { return ((((uint64_t) ia_maj) << 32) | ia_min); }
major
とminor
は、FreeBSDの場合は/usr/include/sys/types.h
にある。
#define major(x) ((int)(((u_int)(x) >> 8)&0xff)) /* major number */ #define minor(x) ((int)((x)&0xffff00ff)) /* minor number */ #define makedev(x,y) ((dev_t)(((x) << 8) | (y))) /* create dev_t */
ずいぶんと面白い定義になってるけど、きっと"歴史的経緯"というやつだろう。で、こいつらのせいでrdevは本来の値から変な変形を受けている。struct stat
からstruct iatt
が作られたのなら、こうなるはずだ。
stat側: 11223344 iatt側: 3311220044
これに先の値を当てはめて元に戻してみる。
iatt側1: 4b00110070 stat側1: 00114b70 (=1133424) iatt側2: 85001d00e8 stat側2: 001d85e8 (=1934824)
それっぽいので、このrdev値をもつファイルを探してみよう。
# ssh root@10.0.0.1 "find /dummy-root/glusterfs-data | xargs -n 1 stat -f '%r %R'" > /tmp/stats-1.txt # ssh root@10.0.0.2 "find /dummy-root/glusterfs-data | xargs -n 1 stat -f '%r %R'" > /tmp/stats-2.txt # ssh root@10.0.0.3 "find /dummy-root/glusterfs-data | xargs -n 1 stat -f '%r %R'" > /tmp/stats-3.txt # grep -E "1133424|1934824" /tmp/statall* /tmp/statall2.txt:1133424 /dummy-root/glusterfs-data/brick/.glusterfs/ae/93/ae930c59-e4ab-4142-a2dc-86fbeccab3a6 /tmp/statall2.txt:1133424 /dummy-root/glusterfs-data/brick/random.dat /tmp/statall3.txt:1934824 /dummy-root/glusterfs-data/brick/.glusterfs/ae/93/ae930c59-e4ab-4142-a2dc-86fbeccab3a6 /tmp/statall3.txt:1934824 /dummy-root/glusterfs-data/brick/random.dat
出てきた。
ところで、rdev
ってregular fileに付くの……?
# stat -f '%r %N' / /COPYRIGHT /dummy-root 4294967295 / 4294967295 /COPYRIGHT 120 /dummy-root
/
はZFS。UFSだとregular fileもrdevは有効な値になる……?
ちょっとバージョンは違うけどFreeBSD 9.0のソースコードより、sys/ufs/ufs/dinode.h:
/* * The di_db fields may be overlaid with other information for * file types that do not have associated disk storage. Block * and character devices overlay the first data block with their * dev_t value. Short symbolic links place their path in the * di_db area. */ #define di_rdev di_db[0]
意訳するとdi_dbフィールドはディスク領域を割り当てないようなファイルタイプについては他の情報が載ってる場合があるよ
。デバイス系だとdev_t番号、すなわちrdevの値。ディスク領域を割り当てるようなファイル、つまりregular fileの場合、ここは本来Direct disk blocks
なので、きっと割り当てブロックの情報が入るのであろう。つまり、regular fileに対して実行したstatのst_rdev
は読んではいけない。
POSIXのstatの定義はどうなっているか。stat - get file statussys/stat.h
はっきりとは書かれていないが、構造体定義にst_rdev
はDevice ID (if file is character or block special).
と書かれているので、character/block device以外については不定と考えるべきだろう。少なくとも、いつも同じ値を返す義理はない。
となればglusterfsのバグ。さくっと直して続けてみる。
[2016-01-16 01:27:35.331128] W [ec-common.c:162:ec_check_status] 0-gv0-disperse-0: Operation failed on some subvolumes (up=7, mask=5, remaining=0, good=5, bad=2) [2016-01-16 01:27:35.331231] I [ec-heal.c:546:ec_heal_init] 0-ec: Healing '(null)', gfid db8166d5-06be-4d04-bbf1-de9f2b911ccb [2016-01-16 01:27:35.331278] E [ec-helpers.c:473:ec_loc_parent] 0-gv0-disperse-0: Parent inode missing for loc_t [2016-01-16 01:27:35.331319] W [ec-common.c:121:ec_heal_report] 0-gv0-disperse-0: Heal failed (error 5)
これはどうやらディレクトリがHealできていないのが原因らしい。
client# ls -al /glusterfs
もしくは、実運用などでまとめてHealするなら、
でできる。
これでエラーもおさまった。先の件もバグに登録済み。
あとはESXiから使う話に戻ろう。