static ssize_t read_kmem(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
ssize_t low_count, read, sz;
char *kbuf; /* k-addr because vread() takes vmlist_lock rwlock */
int err = 0;
read = 0;
if (p < (unsigned long) high_memory) {---------------------------------------属于low_memory内存处理。
low_count = count;
if (count > (unsigned long)high_memory - p)
low_count = (unsigned long)high_memory - p;--------------------------计算处于low_memory区域的内存大小。
...
while (low_count > 0) {
sz = size_inside_page(p, low_count);
kbuf = xlate_dev_kmem_ptr((void *)p);
if (!virt_addr_valid(kbuf))------------------------------------------地址在PAGE_OFFSET和high_memory之间。
return -ENXIO;
if (copy_to_user(buf, kbuf, sz))
return -EFAULT;
buf += sz;
p += sz;
read += sz;
low_count -= sz;
count -= sz;
}
}
if (count > 0) {-------------------------------------------------------------如果还有count没处理完,那么就属于high_memory。
kbuf = (char *)__get_free_page(GFP_KERNEL);
if (!kbuf)
return -ENOMEM;
while (count > 0) {
sz = size_inside_page(p, count);-------------------------------------如果p+count不跨页,那么sz=count;否则sz只取p所在页面剩余部分大小。这样确保下面的copy_to_user()不跨页。
if (!is_vmalloc_or_module_addr((void *)p)) {
err = -ENXIO;
break;
}
sz = vread(kbuf, (char *)p, sz);
if (!sz)
break;
if (copy_to_user(buf, kbuf, sz)) {
err = -EFAULT;
break;
}
count -= sz;
buf += sz;
read += sz;
p += sz;
}
free_page((unsigned long)kbuf);
}
*ppos = p;
return read ? read : err;
}
static ssize_t do_write_kmem(unsigned long p, const char __user *buf,
size_t count, loff_t *ppos)
{
ssize_t written, sz;
unsigned long copied;
written = 0;
...
while (count > 0) {
void *ptr;
sz = size_inside_page(p, count);
ptr = xlate_dev_kmem_ptr((void *)p);
if (!virt_addr_valid(ptr))
return -ENXIO;
copied = copy_from_user(ptr, buf, sz);
if (copied) {
written += sz - copied;
if (written)
break;
return -EFAULT;
}
buf += sz;
p += sz;
count -= sz;
written += sz;
}
*ppos += written;
return written;
}