grub2とUUID


* 標準だとgrub2はファイルシステムのUUIDを元にどのデバイスかを区別しており、このままだと複製したbackup diskから起動しようとした時にそのUUIDのファイルシステムがのったデバイスがないといってrescue modeに落ちてしまいます。
* そこでUUIDで区別しないようにgrub2を設定してみます
====== grub2からuuidを排除 ======
* /etc/default/grubの#GRUB_DISABLE_LINUX_UUID=trueをコメントアウト
* 以下のパッチを当てる
[root@archlinux-proxmox grub]# diff -ur /usr/share/grub/grub-mkconfig_lib /backup/usr/share/grub/grub-mkconfig_lib
--- /usr/share/grub/grub-mkconfig_lib 2012-08-07 22:24:23.649377433 +0900
+++ /backup/usr/share/grub/grub-mkconfig_lib 2012-08-07 22:24:38.432711843 +0900
@@ -146,20 +146,20 @@
done
fi

- # If there's a filesystem UUID that GRUB is capable of identifying, use it;
- # otherwise set root as per value in device.map.
- fs_hint="`"${grub_probe}" --device "${device}" --target=compatibility_hint`"
- if [ "x$fs_hint" != x ]; then
- echo "set root='$fs_hint'"
- fi
- if fs_uuid="`"${grub_probe}" --device "${device}" --target=fs_uuid 2> /dev/null`" ; then
- hints="`"${grub_probe}" --device "${device}" --target=hints_string 2> /dev/null`" || hints=
- echo "if [ x$feature_platform_search_hint = xy ]; then"
- echo " search --no-floppy --fs-uuid --set=root ${hints} ${fs_uuid}"
- echo "else"
- echo " search --no-floppy --fs-uuid --set=root ${fs_uuid}"
- echo "fi"
- fi
+# # If there's a filesystem UUID that GRUB is capable of identifying, use it;
+# # otherwise set root as per value in device.map.
+# fs_hint="`"${grub_probe}" --device "${device}" --target=compatibility_hint`"
+# if [ "x$fs_hint" != x ]; then
+# echo "set root='$fs_hint'"
+# fi
+# if fs_uuid="`"${grub_probe}" --device "${device}" --target=fs_uuid 2> /dev/null`" ; then
+# hints="`"${grub_probe}" --device "${device}" --target=hints_string 2> /dev/null`" || hints=
+# echo "if [ x$feature_platform_search_hint = xy ]; then"
+# echo " search --no-floppy --fs-uuid --set=root ${hints} ${fs_uuid}"
+# echo "else"
+# echo " search --no-floppy --fs-uuid --set=root ${fs_uuid}"
+# echo "fi"
+# fi
}

grub_get_device_id ()

* grub-install /dev/sda

====== backupディスクにgrubを書き込む ======
* 以下のような状況の場合を説明しています
* mount /dev/sdb3 /backup
* mount /dev/sdb1 /backup/boot
* mount -t proc proc /backup/proc
* mount –bind /dev /backup/dev
* chroot /backup
* grub-install /dev/sdb

====== grub rescueモードでの操作 ======
* ls
* ls (hd0,msdos1)/grub
* set prefix=(hd0,msdos1)/grub
* insmod (hd0,msdos1)/grub/i386-pc/normal.mod
* normal

dd中の進行状況を表示


* ddにUSR1シグナルを送ると進行状況を表示してくれるのはmanに書いてあるのでご存知だと思います。
* それをいちいち手でやるのが面倒なので、スクリプトにしてみました
#!/bin/sh
while :
do
ps axuw| fgrep 'dd if=' | grep -v grep | awk '{print $2}' | xargs -i% sh -c 'kill -USR1 %'
sleep 1
done

ext3のディレクトリエントリの削除


* fs/ext3/namei.c
/*
* ext3_delete_entry deletes a directory entry by merging it with the
* previous entry
*/
static int ext3_delete_entry (handle_t *handle,
struct inode * dir,
struct ext3_dir_entry_2 * de_del,
struct buffer_head * bh)
{
struct ext3_dir_entry_2 * de, * pde;
int i;

i = 0;
pde = NULL;
de = (struct ext3_dir_entry_2 *) bh->b_data;
while (i < bh->b_size) {
if (!ext3_check_dir_entry("ext3_delete_entry", dir, de, bh, i))
return -EIO;
if (de == de_del) {
int err;

BUFFER_TRACE(bh, "get_write_access");
err = ext3_journal_get_write_access(handle, bh);
if (err)
goto journal_error;

if (pde)
pde->rec_len = ext3_rec_len_to_disk(
ext3_rec_len_from_disk(pde->rec_len) +
ext3_rec_len_from_disk(de->rec_len));
else
de->inode = 0;
dir->i_version++;
BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
err = ext3_journal_dirty_metadata(handle, bh);
if (err) {
journal_error:
ext3_std_error(dir->i_sb, err);
return err;
}
return 0;
}
i += ext3_rec_len_from_disk(de->rec_len);
pde = de;
de = ext3_next_entry(de);
}
return -ENOENT;
}

ext3のディレクトリエントリ


* ext3のディレクトリエントリの構造
* fs/ext3/ext3.h
/*
* Structure of a directory entry
*/
#define EXT3_NAME_LEN 255

struct ext3_dir_entry {
__le32 inode; /* Inode number */
__le16 rec_len; /* Directory entry length */
__le16 name_len; /* Name length */
char name[EXT3_NAME_LEN]; /* File name */
};

/*
* The new version of the directory entry. Since EXT3 structures are
* stored in intel byte order, and the name_len field could never be
* bigger than 255 chars, it's safe to reclaim the extra byte for the
* file_type field.
*/
struct ext3_dir_entry_2 {
__le32 inode; /* Inode number */
__le16 rec_len; /* Directory entry length */
__u8 name_len; /* Name length */
__u8 file_type;
char name[EXT3_NAME_LEN]; /* File name */
};

/*
* Ext3 directory file types. Only the low 3 bits are used. The
* other bits are reserved for now.
*/
#define EXT3_FT_UNKNOWN 0
#define EXT3_FT_REG_FILE 1
#define EXT3_FT_DIR 2
#define EXT3_FT_CHRDEV 3
#define EXT3_FT_BLKDEV 4
#define EXT3_FT_FIFO 5
#define EXT3_FT_SOCK 6
#define EXT3_FT_SYMLINK 7

#define EXT3_FT_MAX 8

シンボリックリンク


* 60バイト以下のシンボリックリンクはinodeのi_blockに格納され、データブロックを消費しない。そのぶんアクセスも速い。
* fs/ext3/namei.c
if (l > EXT3_N_BLOCKS * 4) {
inode->i_op = &ext3_symlink_inode_operations;
ext3_set_aops(inode);
/*
* We cannot call page_symlink() with transaction started
* because it calls into ext3_write_begin() which acquires page
* lock which ranks below transaction start (and it can also
* wait for journal commit if we are running out of space). So
* we have to stop transaction now and restart it when symlink
* contents is written.
*
* To keep fs consistent in case of crash, we have to put inode
* to orphan list in the mean time.
*/
drop_nlink(inode);
err = ext3_orphan_add(handle, inode);
ext3_journal_stop(handle);
if (err)
goto err_drop_inode;
err = __page_symlink(inode, symname, l, 1);
if (err)
goto err_drop_inode;
/*
* Now inode is being linked into dir (EXT3_DATA_TRANS_BLOCKS
* + EXT3_INDEX_EXTRA_TRANS_BLOCKS), inode is also modified
*/
handle = ext3_journal_start(dir,
EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
EXT3_INDEX_EXTRA_TRANS_BLOCKS + 1);
if (IS_ERR(handle)) {
err = PTR_ERR(handle);
goto err_drop_inode;
}
set_nlink(inode, 1);
err = ext3_orphan_del(handle, inode);
if (err) {
ext3_journal_stop(handle);
drop_nlink(inode);
goto err_drop_inode;
}
} else {
inode->i_op = &ext3_fast_symlink_inode_operations;
memcpy((char*)&EXT3_I(inode)->i_data,symname,l);
inode->i_size = l-1;
}