copy from linux kernel with more simple interface