设为首页】 【加入收藏】 【网站地图】 【商品折扣
娱乐一生 娱乐明星
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
首页  |  Linux  |  Windows xp  |  windows2003  |  Windows Vista  |  资讯动态  |  UNIX  |  Windows9x  |  Windows2000  |  Mac Os  |  FreeBSD  |  Solaris  |  Vista系统
proc_root_fs /proc proc_net /proc/net proc_bus /proc/bus proc_root_driver /proc/driver
  回调函数

  我们可以使用 write_proc 函数向 /proc 中写入一项。这个函数的原型如下:

int mod_write( struct file *filp, const char __user *buff,
               unsigned long len, void *data );

  filp 参数实际上是一个打开文件结构(我们可以忽略这个参数)。buff 参数是传递给您的字符串数据。缓冲区地址实际上是一个用户空间的缓冲区,因此我们不能直接读取它。len 参数定义了在 buff 中有多少数据要被写入。data 参数是一个指向私有数据的指针(参见 清单 7)。在这个模块中,我们声明了一个这种类型的函数来处理到达的数据。

  Linux 提供了一组 API 来在用户空间和内核空间之间移动数据。对于 write_proc 的情况来说,我们使用了 copy_from_user 函数来维护用户空间的数据。

  读回调函数

  我们可以使用 read_proc 函数从一个 /proc 项中读取数据(从内核空间到用户空间)。这个函数的原型如下:

int mod_read( char *page, char **start, off_t off,
              int count, int *eof, void *data );

  

       

  page 参数是这些数据写入到的位置,其中 count 定义了可以写入的最大字符数。在返回多页数据(通常一页是 4KB)时,我们需要使用 start 和 off 参数。当所有数据全部写入之后,就需要设置 eof(文件结束参数)。与 write 类似,data 表示的也是私有数据。此处提供的 page 缓冲区在内核空间中。因此,我们可以直接写入,而不用调用 copy_to_user。

  其他有用的函数

  我们还可以使用 proc_mkdir、symlinks 以及 proc_symlink 在 /proc 文件系统中创建目录。对于只需要一个 read 函数的简单 /proc 项来说,可以使用 create_proc_read_entry,这会创建一个 /proc 项,并在一个调用中对 read_proc 函数进行初始化。这些函数的原型如清单 8 所示。


  清单 8. 其他有用的 /proc 函数

/* Create a directory in the proc filesystem */
struct proc_dir_entry *proc_mkdir( const char *name,
                                     struct proc_dir_entry *parent );

/* Create a symlink in the proc filesystem */
struct proc_dir_entry *proc_symlink( const char *name,
                                       struct proc_dir_entry *parent,
                                       const char *dest );

/* Create a proc_dir_entry with a read_proc_t in one call */
struct proc_dir_entry *create_proc_read_entry( const char *name,
                                                  mode_t mode,
                                                  struct proc_dir_entry *base,
                                                  read_proc_t *read_proc,
                                                  void *data );

/* Copy buffer to user-space from kernel-space */
unsigned long copy_to_user( void __user *to,
                              const void *from,
                              unsigned long n );

/* Copy buffer to kernel-space from user-space */
unsigned long copy_from_user( void *to,
                                const void __user *from,
                                unsigned long n );

/* Allocate a 'virtually' contiguous block of memory */
void *vmalloc( unsigned long size );

/* Free a vmalloc'd block of memory */
void vfree( void *addr );

/* Export a symbol to the kernel (make it visible to the kernel) */
EXPORT_SYMBOL( symbol );

/* Export all symbols in a file to the kernel (declare before module.h) */
EXPORT_SYMTAB

  通过 /proc 文件系统实现财富分发

  下面是一个可以支持读写的 LKM。这个简单的程序提供了一个财富甜点分发。在加载这个模块之后,用户就可以使用 echo 命令向其中导入文本财富,然后再使用 cat 命令逐一读出。

  清单 9 给出了基本的模块函数和变量。init 函数(init_fortune_module)负责使用 vmalloc 来为这个点心罐分配空间,然后使用 memset 将其全部清零。使用所分配并已经清空的 cookie_pot 内存,我们在 /proc 中创建了一个 proc_dir_entry 项,并将其称为 fortune。当 proc_entry 成功创建之后,对自己的本地变量和 proc_entry 结构进行了初始化。我们加载了 /proc read 和 write 函数(如清单 9 和清单 10 所示),并确定这个模块的所有者。cleanup 函数简单地从 /proc 文件系统中删除这一项,然后释放 cookie_pot 所占据的内存。

  cookie_pot 是一个固定大小(4KB)的页,它使用两个索引进行管理。第一个是 cookie_index,标识了要将下一个 cookie 写到哪里去。变量 next_fortune 标识了下一个 cookie 应该从哪里读取以便进行输出。在所有的 fortune 项都读取之后,我们简单地回到了 next_fortune。


  清单 9. 模块的 init/cleanup 和变量

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Fortune Cookie Kernel Module");
MODULE_AUTHOR("M. Tim Jones");

#define MAX_COOKIE_LENGTH       PAGE_SIZE
static struct proc_dir_entry *proc_entry;

static char *cookie_pot;  // Space for fortune strings
static int cookie_index;  // Index to write next fortune
static int next_fortune;  // Index to read next fortune


int init_fortune_module( void )
{
  int ret = 0;

  cookie_pot = (char *)vmalloc( MAX_COOKIE_LENGTH );

  if (!cookie_pot) {
    ret = -ENOMEM;
  } else {

    memset( cookie_pot, 0, MAX_COOKIE_LENGTH );

    proc_entry = create_proc_entry( "fortune", 0644, NULL );

    if (proc_entry == NULL) {

      ret = -ENOMEM;
      vfree(cookie_pot);
      printk(KERN_INFO "fortune: Couldn't create proc entry\n");

    } else {

      cookie_index = 0;
      next_fortune = 0;

      proc_entry->read_proc = fortune_read;
      proc_entry->write_proc = fortune_write;
      proc_entry->owner = THIS_MODULE;
      printk(KERN_INFO "fortune: Module loaded.\n");

    }

  }

  return ret;
}


void cleanup_fortune_module( void )
{
  remove_proc_entry("fortune", &proc_root);
  vfree(cookie_pot);
  printk(KERN_INFO "fortune: Module unloaded.\n");
}


module_init( init_fortune_module );
module_exit( cleanup_fortune_module );

  向这个罐中新写入一个 cookie 非常简单(如清单 10 所示)。使用这个写入 cookie 的长度,我们可以检查是否有这么多空间可用。如果没有,就返回 -ENOSPC,它会返回给用户空间。否则,就说明空间存在,我们使用 copy_from_user 将用户缓冲区中的数据直接拷贝到 cookie_pot 中。然后增大 cookie_index(基于用户缓冲区的长度)并使用 NULL 来结束这个字符串。最后,返回实际写入 cookie_pot 的字符的个数,它会返回到用户进程。


  清单 10. 对 fortune 进行写入操作所使用的函数

  对 fortune 进行读取也非常简单,如清单 11 所示。由于我们刚才写入数据的缓冲区(page)已经在内核空间中了,因此可以直接对其进行操作,并使用 sprintf 来写入下一个 fortune。如果 next_fortune 索引大于 cookie_index(要写入的下一个位置),那么我们就将 next_fortune 返回为 0,这是第一个 fortune 的索引。在将这个 fortune 写入用户缓冲区之后,在 next_fortune 索引上增加刚才写入的 fortune 的长度。这样就变成了下一个可用 fortune 的索引。这个 fortune 的长度会被返回并传递给用户。

  清单 11. 对 fortune 进行读取操作所使用的函数

int fortune_read( char *page, char **start, off_t off,
                   int count, int *eof, void *data )
{
  int len;

  if (off > 0) {
    *eof = 1;
    return 0;
  }

  /* Wrap-around */
  if (next_fortune >= cookie_index) next_fortune = 0;

  len = sprintf(page, "%s\n", &cookie_pot[next_fortune]);

  next_fortune += len;

  return len;
}

  从这个简单的例子中,我们可以看出通过 /proc 文件系统与内核进行通信实际上是件非常简单的事情。现在让我们来看一下这个 fortune 模块的用法(参见清单 12)。


  清单 12. 展示 fortune cookie LKM 的用法

[root@plato]# insmod fortune.ko
[root@plato]# echo "Success is an individual proposition.  Thomas Watson" > /proc/fortune
[root@plato]# echo "If a man does his best, what else is there?  Gen. Patton" > /proc/fortune
[root@plato]# echo "Cats: All your base are belong to us.  Zero Wing" > /proc/fortune
[root@plato]# cat /proc/fortune
Success is an individual proposition.  Thomas Watson
[root@plato]# cat /proc/fortune
If a man does his best, what else is there?  General Patton
[root@plato]#

  /proc 虚拟文件系统可以广泛地用来报告内核的信息,也可以用来进行动态配置。我们会发现它对于驱动程序和模块编程来说都是非常完整的。在下面的 参考资料 中,我们可以学习到更多相关知识。

     


当前位置:首页 >> 系统维护 >> 在双引导Linux系统上实现OS自动切换

在双引导Linux系统上实现OS自动切换 -

    利用本文中介绍的这些技巧,我们可以在一个双引导的机器上自动从一个操作系统切换到另外一个操作系统,无需任何人工干预。您可以使用本文提供的脚本在自己的机器上复制这种同时运行 Linux? 和 Windows? 的设置。

    既然我们可以非常简单地直接手工实现这种操作系统的切换,为什么还希望自动化此操作呢?简单的答案是自动化过程可以让使用多个操作系统变得容易得多。例如您要在多个操作系统平台上测试软件,那么这种功能就会特别有用。

    本文在介绍这些技巧时假设您已经安装好了操作系统,并使用 GRUB 配置了多重引导。GRUB 是 GRand Unified Bootloader 的简称,它在机器启动时加载,然后机器的控制权被转交给 OS 内核软件。有关部署 GRUB 的帮助信息,请参阅本文后面的 参考资料 一节。

    本文介绍的技巧可以适用于:

    Microsoft? Windows XP Professional Microsoft Windows Server 2003 Debian Linux 3.1(Sarge)

    Red Hat Enterprise Server(RHES) 3 GRUB 0.97;虽然使用这个版本的 GRUB 成功了,但不保证使用其他 bootloader 也会获得成功步骤 1. 设置磁盘分区

    在开始配置系统之前,确保有一个最新的系统备份,并且手头有一张援助用的 CD.如果在执行这些步骤时出现了问题,那么机器可能无法启动。如果发现自己面临的风险是无法接受的,那么最好不要继续执行以下步骤。

    创建 Bootcontrol 分区

    在一块硬盘上创建一个小分区。在这个分区上必须创建这样一个文件系统:要切换的所有操作系统都能够加载这个文件系统,并可以对这个文件执行写入操作。我们选择使用 FAT32.尽管整个 Bootcontrol 系统只需要不到 1MB 的磁盘空间,但是 FAT32 默认最小限制为 256MB,因此这会浪费一些空间。

    如果没有足够的未分配空间,可以通过缩小或删除现有分区来创建这部分空间。 在 Linux 中可以使用 GNU parted 命令来实现这项功能。如果在执行 parted 操作之后,现有分区的次序发生了变化,那么可能还需要更新 /etc/fstab 文件。有关的更多信息,请参阅 parted 的文档。

    当使用 parted 在测试机器上创建所需的分区时,会看到如清单 1 中所示的结果:

    清单 1. 创建必需的分区

repton:~# cat /etc/fstab
# /etc/fstab: static file system information.
# <file system> <mount point> <type> <options> <dump> <pass>
proc /proc proc defaults 0 0
/dev/hda2 / ext3 defaults 0 1
/dev/hda6 /home ext3 defaults 0 2
/dev/hda7 /opt ext3 defaults 0 2
/dev/hda5 none swap sw 0 0
/dev/hdc /media/cdrom0 iso9660 ro,user,noauto 0 0
/dev/fd0 /media/floppy0 auto rw,user,noauto 0 0
repton:~# umount /home
repton:~# parted
Using /dev/hda
(parted) print
Disk geometry for /dev/hda: 0.000-57231.562 megabytes
Disk label type: msdos
Minor Start End Type Filesystem Flags
1 0.031 18412.734 primary ntfs boot
2 18418.271 25085.874 primary ext3
3 25085.874 57231.562 extended
5 25085.905 26458.615 logical linux-swap
6 26458.646 49999.174 logical ext3
7 49999.206 57231.562 logical ext3
(parted) resize 6 26458 49739
(parted) mkpartfs logical fat32 49739 49999
(parted) print
Disk geometry for /dev/hda: 0.000-57231.562 megabytes
Disk label type: msdos
Minor Start End Type Filesystem Flags
1 0.031 18412.734 primary ntfs boot
2 18418.271 25085.874 primary ext3
3 25085.874 57231.562 extended
5 25085.905 26458.615 logical linux-swap
6 26458.646 49740.314 logical ext3
8 49740.346 49999.174 logical fat32
7 49999.206 57231.562 logical ext3
(parted) q
repton:~# mount /home
    挂载 Linux 分区

    在为控制分区创建好空间之后,需要将其挂载到 Linux 中,这样就可以在 Linux 中看到这个分区。在本例中,我们将以下内容添加到了 /etc/fstab 中:

    # <file system> <mount point> <type> <options> <dump> <pass> /dev/hda8 /boot/control vfat umask=022,dmask=022,fmask=022 0 2然后使用下面的命令来创建挂载点并挂载这个文件系统:

    mkdir /boot/control mount /boot/control

    还需要更新 GRUB 在分区结果上维护的信息。在这个测试系统上,我们使用下面的命令:grub-install /dev/hda.

    挂载 Windows 分区

    通过(手工)重新启动到 Windows,验证上面的分区编辑步骤不会破坏 Windows 的引导过程。 然后为刚才创建的 Bootcontrol 卷分配一个驱动器字符。在现代版的 Windows 上,可以使用 Computer Management MMC snap-in(右键点击 My Computer,然后选择 Manage)。在以前的版本上,可以选择 Start > Administrative Tools.

    

 

  清单 4. 编译 LKM

[root@plato]# make -C /usr/src/linux-`uname -r` SUBDIRS=$PWD modules
make: Entering directory `/usr/src/linux-2.6.11'
  CC [M]  /root/projects/misc/module2.6/simple/simple-lkm.o
  Building modules, stage 2.
  MODPOST
  CC      /root/projects/misc/module2.6/simple/simple-lkm.mod.o
  LD [M]  /root/projects/misc/module2.6/simple/simple-lkm.ko
make: Leaving directory `/usr/src/linux-2.6.11'
[root@plato]#

  结果会生成一个 simple-lkm.ko 文件。这个新的命名约定可以帮助将这些内核对象(LKM)与标准对象区分开来。现在可以加载或卸载这个模块了,然后可以查看它的输出。要加载这个模块,请使用 insmod 命令;反之,要卸载这个模块,请使用 rmmod 命令。lsmod 可以显示当前加载的 LKM(参见清单 5)。

  清单 5. 插入、检查和删除 LKM

[root@plato]# insmod simple-lkm.ko
[root@plato]# lsmod
Module                  Size  Used by
simple_lkm              1536  0
autofs4                26244  0
video                  13956  0
button                  5264  0
battery                 7684  0
ac                      3716  0
yenta_socket           18952  3
rsrc_nonstatic          9472  1 yenta_socket
uhci_hcd               32144  0
i2c_piix4               7824  0
dm_mod                 56468  3
[root@plato]# rmmod simple-lkm
[root@plato]#

  注意,内核的输出进到了内核回环缓冲区中,而不是打印到 stdout 上,这是因为 stdout 是进程特有的环境。要查看内核回环缓冲区中的消息,可以使用 dmesg 工具(或者通过 /proc 本身使用 cat /proc/kmsg 命令)。清单 6 给出了 dmesg 显示的最后几条消息。


  清单 6. 查看来自 LKM 的内核输出

[root@plato]# dmesg  tail -5
cs: IO port probe 0xa00-0xaff: clean.
eth0: Link is down
eth0: Link is up, running at 100Mbit half-duplex
my_module_init called.  Module is now loaded.
my_module_cleanup called.  Module is now unloaded.
[root@plato]#

  可以在内核输出中看到这个模块的消息。现在让我们暂时离开这个简单的例子,来看几个可以用来开发有用 LKM 的内核 API。

  集成到 /proc 文件系统中

  内核程序员可以使用的标准 API,LKM 程序员也可以使用。LKM 甚至可以导出内核使用的新变量和函数。有关 API 的完整介绍已经超出了本文的范围,因此我们在这里只是简单地介绍后面在展示一个更有用的 LKM 时所使用的几个元素。

  创建并删除 /proc 项

  要在 /proc 文件系统中创建一个虚拟文件,请使用 create_proc_entry 函数。这个函数可以接收一个文件名、一组权限和这个文件在 /proc 文件系统中出现的位置。create_proc_entry 的返回值是一个 proc_dir_entry 指针(或者为 NULL,说明在 create 时发生了错误)。然后就可以使用这个返回的指针来配置这个虚拟文件的其他参数,例如在对该文件执行读操作时应该调用的函数。create_proc_entry 的原型和 proc_dir_entry 结构中的一部分如清单 7 所示。


  清单 7. 用来管理 /proc 文件系统项的元素

struct proc_dir_entry *create_proc_entry( const char *name, mode_t mode,
                                             struct proc_dir_entry *parent );

struct proc_dir_entry {
	const char *name;			// virtual file name
	mode_t mode;				// mode permissions
	uid_t uid;				// File's user id
	gid_t gid;				// File's group id
	struct inode_operations *proc_iops;	// Inode operations functions
	struct file_operations *proc_fops;	// File operations functions
	struct proc_dir_entry *parent;		// Parent directory
	...
	read_proc_t *read_proc;			// /proc read function
	write_proc_t *write_proc;		// /proc write function
	void *data;				// Pointer to private data
	atomic_t count;				// use count
	...
};

void remove_proc_entry( const char *name, struct proc_dir_entry *parent );

  稍后我们就可以看到如何使用 read_proc 和 write_proc 命令来插入对这个虚拟文件进行读写的函数。

  要从 /proc 中删除一个文件,可以使用 remove_proc_entry 函数。要使用这个函数,我们需要提供文件名字符串,以及这个文件在 /proc 文件系统中的位置(parent)。这个函数原型如清单 7 所示。

  parent 参数可以为 NULL(表示 /proc 根目录),也可以是很多其他值,这取决于我们希望将这个文件放到什么地方。表 1 列出了可以使用的其他一些父 proc_dir_entry,以及它们在这个文件系统中的位置。


表 1. proc_dir_entry 快捷变量

proc_dir_entry 在文件系统中的位置

 加入收藏 打印本页 关闭窗口 返回顶部
相关文章
· Referrers统计系统的乱码问题解决
· 剖析关于SecureCrt使用 H2的补充
· 教 #20320 #2231
· 关于Linux图形界面的基本知识
· 小技巧:直接用Grub启动98和XP的办法
· 详细介绍James中的主机名和本地域
· 在RedHat As3.0上搞辅助D 的困惑
· 谈谈本地邮件用户和虚拟邮件用户关系
· 一步步从Win2k D  移植到 Linux 下
· 可选的指令集扩展MI 的发展历程
 

娱乐图摘

更多 >>

靓丽清纯美女meimei

美女私房全裸照
导演劝女演员脱衣服(视频)

大胆火辣人体艺术写真(图)

黑丝妹妹热辣诱惑-丝袜美女妹妹

PLMM 漂亮妹妹图集-妹妹图库

全球美女图库-美女集中营

52MM 我爱漂亮妹妹-制服妹妹诱惑

图王图库-世界美女明星图片资料库
美女写真集锦

激情两性-解密性生活
浴室MM湿身内衣诱惑
邻家小妹洗澡被偷拍(视频)

热点文章

更多

· Mount命令:Linux外置存储介质挂载方法
· 新书推荐:Linux逻辑卷管理(LVM)
· Linux操作系统下双启动环境的陷阱问题
· 几种Linux嵌入式开发环境的简单介绍
· 实用技巧一则 Linux系统对文件进行加锁
· Linux技巧:逐步移动分区的操作方式
· Linux 探索 第一幕 传奇的开始
· 分析Windows和Linux动态库
· Linux 用户(User)查询篇
· Qpo er 的 Quota 问题

热点文章

更多