tcによる内向きトラフィックの制御


* outboundなトラフィックの制御は割と簡単に制御できるんだけど、inboundなトラフィックはingressで書いてやってもなかなか思うような制限値になってくれません。
* そこで、ifb(Intermediate Functional Block device)を使うとよいようです
* eth0に入ってくるトラフィックを50Mbpsに制限するスクリプト
#!/bin/sh
### traffic shape for inbound eth0
## Initialize
tc qdisc del dev eth0 ingress handle ffff: > /dev/null 2>&1
tc qdisc del dev ifb0 root handle 1: htb > /dev/null 2>&1

## ifb setup
modprobe ifb
sleep 2
ip link set dev ifb0 up

## mirror eth0 to ifb0
modprobe act_mirred
sleep 2
tc qdisc add dev eth0 ingress handle ffff:
tc filter add dev eth0 parent ffff: protocol ip u32 match u32 0 0 flowid 1:1 action mirred egress redirect dev ifb0

## traffic shape ifb0
tc qdisc add dev ifb0 root handle 1: htb default 10
tc class add dev ifb0 parent 1:1 classid 1:10 htb rate 50mbit

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;
}