📄 nvram.c
字号:
return 0;}/* setup_nvram_partition * * This will setup the partition we need for buffering the * error logs and cleanup partitions if needed. * * The general strategy is the following: * 1.) If there is ppc64,linux partition large enough then use it. * 2.) If there is not a ppc64,linux partition large enough, search * for a free partition that is large enough. * 3.) If there is not a free partition large enough remove * _all_ OS partitions and consolidate the space. * 4.) Will first try getting a chunk that will satisfy the maximum * error log size (NVRAM_MAX_REQ). * 5.) If the max chunk cannot be allocated then try finding a chunk * that will satisfy the minum needed (NVRAM_MIN_REQ). */static int setup_nvram_partition(void){ struct list_head * p; struct nvram_partition * part; int rc; /* see if we have an OS partition that meets our needs. will try getting the max we need. If not we'll delete partitions and try again. */ list_for_each(p, &nvram_part->partition) { part = list_entry(p, struct nvram_partition, partition); if (part->header.signature != NVRAM_SIG_OS) continue; if (strcmp(part->header.name, "ppc64,linux")) continue; if (part->header.length >= NVRAM_MIN_REQ) { /* found our partition */ error_log_nvram_index = part->index + NVRAM_HEADER_LEN; error_log_nvram_size = (part->header.length * NVRAM_BLOCK_LEN) - NVRAM_HEADER_LEN - sizeof(struct err_log_info); return 0; } } /* try creating a partition with the free space we have */ rc = create_os_nvram_partition(); if (!rc) { return 0; } /* need to free up some space */ rc = remove_os_nvram_partition(); if (rc) { return rc; } /* create a partition in this new space */ rc = create_os_nvram_partition(); if (rc) { printk(KERN_ERR "create_os_nvram_partition: Could not find a " "NVRAM partition large enough (%d)\n", rc); return rc; } return 0;}static int remove_os_nvram_partition(void){ struct list_head *i; struct list_head *j; struct nvram_partition * part; struct nvram_partition * cur_part; int rc; list_for_each(i, &nvram_part->partition) { part = list_entry(i, struct nvram_partition, partition); if (part->header.signature != NVRAM_SIG_OS) continue; /* Make os partition a free partition */ part->header.signature = NVRAM_SIG_FREE; sprintf(part->header.name, "wwwwwwwwwwww"); part->header.checksum = nvram_checksum(&part->header); /* Merge contiguous free partitions backwards */ list_for_each_prev(j, &part->partition) { cur_part = list_entry(j, struct nvram_partition, partition); if (cur_part == nvram_part || cur_part->header.signature != NVRAM_SIG_FREE) { break; } part->header.length += cur_part->header.length; part->header.checksum = nvram_checksum(&part->header); part->index = cur_part->index; list_del(&cur_part->partition); kfree(cur_part); j = &part->partition; /* fixup our loop */ } /* Merge contiguous free partitions forwards */ list_for_each(j, &part->partition) { cur_part = list_entry(j, struct nvram_partition, partition); if (cur_part == nvram_part || cur_part->header.signature != NVRAM_SIG_FREE) { break; } part->header.length += cur_part->header.length; part->header.checksum = nvram_checksum(&part->header); list_del(&cur_part->partition); kfree(cur_part); j = &part->partition; /* fixup our loop */ } rc = write_nvram_header(part); if (rc <= 0) { printk(KERN_ERR "remove_os_nvram_partition: write_nvram failed (%d)\n", rc); return rc; } } return 0;}/* create_os_nvram_partition * * Create a OS linux partition to buffer error logs. * Will create a partition starting at the first free * space found if space has enough room. */static int create_os_nvram_partition(void){ struct list_head * p; struct nvram_partition * part; struct nvram_partition * new_part = NULL; struct nvram_partition * free_part; struct err_log_info seq_init = { 0, 0 }; loff_t tmp_index; long size = 0; int rc; /* Find a free partition that will give us the maximum needed size If can't find one that will give us the minimum size needed */ list_for_each(p, &nvram_part->partition) { part = list_entry(p, struct nvram_partition, partition); if (part->header.signature != NVRAM_SIG_FREE) continue; if (part->header.length >= NVRAM_MAX_REQ) { size = NVRAM_MAX_REQ; free_part = part; break; } if (!size && part->header.length >= NVRAM_MIN_REQ) { size = NVRAM_MIN_REQ; free_part = part; } } if (!size) { return -ENOSPC; } /* Create our OS partition */ new_part = kmalloc(sizeof(struct nvram_partition), GFP_KERNEL); if (!new_part) { printk(KERN_ERR "create_os_nvram_partition: kmalloc failed\n"); return -ENOMEM; } new_part->index = free_part->index; new_part->header.signature = NVRAM_SIG_OS; new_part->header.length = size; sprintf(new_part->header.name, "ppc64,linux"); new_part->header.checksum = nvram_checksum(&new_part->header); rc = write_nvram_header(new_part); if (rc <= 0) { printk(KERN_ERR "create_os_nvram_partition: write_nvram_header \ failed (%d)\n", rc); kfree(new_part); return rc; } /* make sure and initialize to zero the sequence number and the error type logged */ tmp_index = new_part->index + NVRAM_HEADER_LEN; rc = write_nvram((char *)&seq_init, sizeof(seq_init), &tmp_index); if (rc <= 0) { printk(KERN_ERR "create_os_nvram_partition: write_nvram failed (%d)\n", rc); kfree(new_part); return rc; } error_log_nvram_index = new_part->index + NVRAM_HEADER_LEN; error_log_nvram_size = (new_part->header.length * NVRAM_BLOCK_LEN) - NVRAM_HEADER_LEN - sizeof(struct err_log_info); list_add_tail(&new_part->partition, &free_part->partition); if (free_part->header.length <= size) { list_del(&free_part->partition); kfree(free_part); return 0; } /* Adjust the partition we stole the space from */ free_part->index += size * NVRAM_BLOCK_LEN; free_part->header.length -= size; free_part->header.checksum = nvram_checksum(&free_part->header); rc = write_nvram_header(free_part); if (rc <= 0) { printk(KERN_ERR "create_os_nvram_partition: write_nvram_header " "failed (%d)\n", rc); error_log_nvram_index = -1; error_log_nvram_size = 0; return rc; } return 0;}void print_nvram_partitions(char * label){ struct list_head * p; struct nvram_partition * tmp_part; printk(KERN_WARNING "--------%s---------\n", label); printk(KERN_WARNING "indx\t\tsig\tchks\tlen\tname\n"); list_for_each(p, &nvram_part->partition) { tmp_part = list_entry(p, struct nvram_partition, partition); printk(KERN_WARNING "%d \t%02x\t%02x\t%d\t%s\n", tmp_part->index, tmp_part->header.signature, tmp_part->header.checksum, tmp_part->header.length, tmp_part->header.name); }}/* write_error_log_nvram * In NVRAM the partition containing the error log buffer will looks like: * Header (in bytes): * +-----------+----------+--------+------------+------------------+ * | signature | checksum | length | name | data | * |0 |1 |2 3|4 15|16 length-1| * +-----------+----------+--------+------------+------------------+ * NOTE: length is in NVRAM_BLOCK_LEN * * The 'data' section would look like (in bytes): * +--------------+------------+-----------------------------------+ * | event_logged | sequence # | error log | * |0 3|4 7|8 error_log_nvram_size-1| * +--------------+------------+-----------------------------------+ * * event_logged: 0 if event has not been logged to syslog, 1 if it has * sequence #: The unique sequence # for each event. (until it wraps) * error log: The error log from event_scan */int write_error_log_nvram(char * buff, int num_bytes, unsigned int err_type){ int rc; loff_t tmp_index; struct err_log_info info; if (no_more_logging) { return -EPERM; } if (error_log_nvram_index == -1) { return -ESPIPE; } if (num_bytes > error_log_nvram_size) { num_bytes = error_log_nvram_size; } info.error_type = err_type; info.seq_num = error_log_cnt; tmp_index = error_log_nvram_index; rc = write_nvram((char *)&info, sizeof(struct err_log_info), &tmp_index); if (rc <= 0) { printk(KERN_ERR "write_error_log_nvram: Failed write_nvram (%d)\n", rc); return rc; } rc = write_nvram(buff, num_bytes, &tmp_index); if (rc <= 0) { printk(KERN_ERR "write_error_log_nvram: Failed write_nvram (%d)\n", rc); return rc; } return 0;}/* read_error_log_nvram * * Reads nvram for error log for at most 'num_bytes' */int read_error_log_nvram(char * buff, int num_bytes, unsigned int * err_type){ int rc; loff_t tmp_index; struct err_log_info info; if (error_log_nvram_index == -1) return -1; if (num_bytes > error_log_nvram_size) num_bytes = error_log_nvram_size; tmp_index = error_log_nvram_index; rc = read_nvram((char *)&info, sizeof(struct err_log_info), &tmp_index); if (rc <= 0) { printk(KERN_ERR "read_error_log_nvram: Failed read_nvram (%d)\n", rc); return rc; } rc = read_nvram(buff, num_bytes, &tmp_index); if (rc <= 0) { printk(KERN_ERR "read_error_log_nvram: Failed read_nvram (%d)\n", rc); return rc; } error_log_cnt = info.seq_num; *err_type = info.error_type; return 0;}/* This doesn't actually zero anything, but it sets the event_logged * word to tell that this event is safely in syslog. */int clear_error_log_nvram(){ loff_t tmp_index; int clear_word = ERR_FLAG_ALREADY_LOGGED; int rc; if (error_log_nvram_index == -1) { return -ESPIPE; } tmp_index = error_log_nvram_index; rc = write_nvram((char *)&clear_word, sizeof(int), &tmp_index); if (rc <= 0) { printk(KERN_ERR "clear_error_log_nvram: Failed write_nvram (%d)\n", rc); return rc; } return 0;}static int write_nvram_header(struct nvram_partition * part){ loff_t tmp_index; int rc; tmp_index = part->index; rc = write_nvram((char *)&part->header, NVRAM_HEADER_LEN, &tmp_index); return rc;}static unsigned char nvram_checksum(struct nvram_header *p){ unsigned int c_sum, c_sum2; unsigned short *sp = (unsigned short *)p->name; /* assume 6 shorts */ c_sum = p->signature + p->length + sp[0] + sp[1] + sp[2] + sp[3] + sp[4] + sp[5]; /* The sum may have spilled into the 3rd byte. Fold it back. */ c_sum = ((c_sum & 0xffff) + (c_sum >> 16)) & 0xffff; /* The sum cannot exceed 2 bytes. Fold it into a checksum */ c_sum2 = (c_sum >> 8) + (c_sum << 8); c_sum = ((c_sum + c_sum2) >> 8) & 0xff; return c_sum;}module_init(nvram_init);module_exit(nvram_cleanup);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -