diff options
Diffstat (limited to 'drivers/char/mem.c')
| -rw-r--r-- | drivers/char/mem.c | 165 | 
1 files changed, 71 insertions, 94 deletions
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 1256454b2d4..917403fe10d 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -21,19 +21,21 @@  #include <linux/ptrace.h>  #include <linux/device.h>  #include <linux/highmem.h> -#include <linux/crash_dump.h>  #include <linux/backing-dev.h> -#include <linux/bootmem.h>  #include <linux/splice.h>  #include <linux/pfn.h> +#include <linux/export.h> +#include <linux/io.h> +#include <linux/aio.h>  #include <asm/uaccess.h> -#include <asm/io.h>  #ifdef CONFIG_IA64  # include <linux/efi.h>  #endif +#define DEVPORT_MINOR	4 +  static inline unsigned long size_inside_page(unsigned long start,  					     unsigned long size)  { @@ -45,12 +47,9 @@ static inline unsigned long size_inside_page(unsigned long start,  }  #ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE -static inline int valid_phys_addr_range(unsigned long addr, size_t count) +static inline int valid_phys_addr_range(phys_addr_t addr, size_t count)  { -	if (addr + count > __pa(high_memory)) -		return 0; - -	return 1; +	return addr + count <= __pa(high_memory);  }  static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t size) @@ -96,10 +95,13 @@ void __weak unxlate_dev_mem_ptr(unsigned long phys, void *addr)  static ssize_t read_mem(struct file *file, char __user *buf,  			size_t count, loff_t *ppos)  { -	unsigned long p = *ppos; +	phys_addr_t p = *ppos;  	ssize_t read, sz;  	char *ptr; +	if (p != *ppos) +		return 0; +  	if (!valid_phys_addr_range(p, count))  		return -EFAULT;  	read = 0; @@ -153,11 +155,14 @@ static ssize_t read_mem(struct file *file, char __user *buf,  static ssize_t write_mem(struct file *file, const char __user *buf,  			 size_t count, loff_t *ppos)  { -	unsigned long p = *ppos; +	phys_addr_t p = *ppos;  	ssize_t written, sz;  	unsigned long copied;  	void *ptr; +	if (p != *ppos) +		return -EFBIG; +  	if (!valid_phys_addr_range(p, count))  		return -EFAULT; @@ -226,7 +231,7 @@ int __weak phys_mem_access_prot_allowed(struct file *file,   *   */  #ifdef pgprot_noncached -static int uncached_access(struct file *file, unsigned long addr) +static int uncached_access(struct file *file, phys_addr_t addr)  {  #if defined(CONFIG_IA64)  	/* @@ -258,7 +263,7 @@ static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,  				     unsigned long size, pgprot_t vma_prot)  {  #ifdef pgprot_noncached -	unsigned long offset = pfn << PAGE_SHIFT; +	phys_addr_t offset = pfn << PAGE_SHIFT;  	if (uncached_access(file, offset))  		return pgprot_noncached(vma_prot); @@ -322,7 +327,7 @@ static int mmap_mem(struct file *file, struct vm_area_struct *vma)  	vma->vm_ops = &mmap_mem_ops; -	/* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */ +	/* Remap-pfn-range will mark the range VM_IO */  	if (remap_pfn_range(vma,  			    vma->vm_start,  			    vma->vm_pgoff, @@ -356,40 +361,6 @@ static int mmap_kmem(struct file *file, struct vm_area_struct *vma)  }  #endif -#ifdef CONFIG_CRASH_DUMP -/* - * Read memory corresponding to the old kernel. - */ -static ssize_t read_oldmem(struct file *file, char __user *buf, -				size_t count, loff_t *ppos) -{ -	unsigned long pfn, offset; -	size_t read = 0, csize; -	int rc = 0; - -	while (count) { -		pfn = *ppos / PAGE_SIZE; -		if (pfn > saved_max_pfn) -			return read; - -		offset = (unsigned long)(*ppos % PAGE_SIZE); -		if (count > PAGE_SIZE - offset) -			csize = PAGE_SIZE - offset; -		else -			csize = count; - -		rc = copy_oldmem_page(pfn, buf, csize, offset, 1); -		if (rc < 0) -			return rc; -		buf += csize; -		*ppos += csize; -		read += csize; -		count -= csize; -	} -	return read; -} -#endif -  #ifdef CONFIG_DEVKMEM  /*   * This function reads the *virtual* memory as seen by the kernel. @@ -399,7 +370,7 @@ static ssize_t read_kmem(struct file *file, char __user *buf,  {  	unsigned long p = *ppos;  	ssize_t low_count, read, sz; -	char * kbuf; /* k-addr because vread() takes vmlist_lock rwlock */ +	char *kbuf; /* k-addr because vread() takes vmlist_lock rwlock */  	int err = 0;  	read = 0; @@ -527,7 +498,7 @@ static ssize_t write_kmem(struct file *file, const char __user *buf,  	unsigned long p = *ppos;  	ssize_t wrote = 0;  	ssize_t virtr = 0; -	char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */ +	char *kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */  	int err = 0;  	if (p < (unsigned long) high_memory) { @@ -595,7 +566,7 @@ static ssize_t write_port(struct file *file, const char __user *buf,  			  size_t count, loff_t *ppos)  {  	unsigned long i = *ppos; -	const char __user * tmp = buf; +	const char __user *tmp = buf;  	if (!access_ok(VERIFY_READ, buf, count))  		return -EFAULT; @@ -627,6 +598,18 @@ static ssize_t write_null(struct file *file, const char __user *buf,  	return count;  } +static ssize_t aio_read_null(struct kiocb *iocb, const struct iovec *iov, +			     unsigned long nr_segs, loff_t pos) +{ +	return 0; +} + +static ssize_t aio_write_null(struct kiocb *iocb, const struct iovec *iov, +			      unsigned long nr_segs, loff_t pos) +{ +	return iov_length(iov, nr_segs); +} +  static int pipe_to_null(struct pipe_inode_info *info, struct pipe_buffer *buf,  			struct splice_desc *sd)  { @@ -670,6 +653,24 @@ static ssize_t read_zero(struct file *file, char __user *buf,  	return written ? written : -EFAULT;  } +static ssize_t aio_read_zero(struct kiocb *iocb, const struct iovec *iov, +			     unsigned long nr_segs, loff_t pos) +{ +	size_t written = 0; +	unsigned long i; +	ssize_t ret; + +	for (i = 0; i < nr_segs; i++) { +		ret = read_zero(iocb->ki_filp, iov[i].iov_base, iov[i].iov_len, +				&pos); +		if (ret < 0) +			break; +		written += ret; +	} + +	return written ? written : -EFAULT; +} +  static int mmap_zero(struct file *file, struct vm_area_struct *vma)  {  #ifndef CONFIG_MMU @@ -708,13 +709,13 @@ static loff_t memory_lseek(struct file *file, loff_t offset, int orig)  {  	loff_t ret; -	mutex_lock(&file->f_path.dentry->d_inode->i_mutex); +	mutex_lock(&file_inode(file)->i_mutex);  	switch (orig) {  	case SEEK_CUR:  		offset += file->f_pos;  	case SEEK_SET:  		/* to avoid userland mistaking f_pos=-9 as -EBADF=-9 */ -		if ((unsigned long long)offset >= ~0xFFFULL) { +		if (IS_ERR_VALUE((unsigned long long)offset)) {  			ret = -EOVERFLOW;  			break;  		} @@ -725,11 +726,11 @@ static loff_t memory_lseek(struct file *file, loff_t offset, int orig)  	default:  		ret = -EINVAL;  	} -	mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); +	mutex_unlock(&file_inode(file)->i_mutex);  	return ret;  } -static int open_port(struct inode * inode, struct file * filp) +static int open_port(struct inode *inode, struct file *filp)  {  	return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;  } @@ -738,9 +739,9 @@ static int open_port(struct inode * inode, struct file * filp)  #define full_lseek      null_lseek  #define write_zero	write_null  #define read_full       read_zero +#define aio_write_zero	aio_write_null  #define open_mem	open_port  #define open_kmem	open_mem -#define open_oldmem	open_mem  static const struct file_operations mem_fops = {  	.llseek		= memory_lseek, @@ -766,6 +767,8 @@ static const struct file_operations null_fops = {  	.llseek		= null_lseek,  	.read		= read_null,  	.write		= write_null, +	.aio_read	= aio_read_null, +	.aio_write	= aio_write_null,  	.splice_write	= splice_write_null,  }; @@ -782,6 +785,8 @@ static const struct file_operations zero_fops = {  	.llseek		= zero_lseek,  	.read		= read_zero,  	.write		= write_zero, +	.aio_read	= aio_read_zero, +	.aio_write	= aio_write_zero,  	.mmap		= mmap_zero,  }; @@ -801,43 +806,9 @@ static const struct file_operations full_fops = {  	.write		= write_full,  }; -#ifdef CONFIG_CRASH_DUMP -static const struct file_operations oldmem_fops = { -	.read	= read_oldmem, -	.open	= open_oldmem, -	.llseek = default_llseek, -}; -#endif - -static ssize_t kmsg_write(struct file *file, const char __user *buf, -			  size_t count, loff_t *ppos) -{ -	char *tmp; -	ssize_t ret; - -	tmp = kmalloc(count + 1, GFP_KERNEL); -	if (tmp == NULL) -		return -ENOMEM; -	ret = -EFAULT; -	if (!copy_from_user(tmp, buf, count)) { -		tmp[count] = 0; -		ret = printk("%s", tmp); -		if (ret > count) -			/* printk can add a prefix */ -			ret = count; -	} -	kfree(tmp); -	return ret; -} - -static const struct file_operations kmsg_fops = { -	.write = kmsg_write, -	.llseek = noop_llseek, -}; -  static const struct memdev {  	const char *name; -	mode_t mode; +	umode_t mode;  	const struct file_operations *fops;  	struct backing_dev_info *dev_info;  } devlist[] = { @@ -853,9 +824,8 @@ static const struct memdev {  	 [7] = { "full", 0666, &full_fops, NULL },  	 [8] = { "random", 0666, &random_fops, NULL },  	 [9] = { "urandom", 0666, &urandom_fops, NULL }, -	[11] = { "kmsg", 0, &kmsg_fops, NULL }, -#ifdef CONFIG_CRASH_DUMP -	[12] = { "oldmem", 0, &oldmem_fops, NULL }, +#ifdef CONFIG_PRINTK +	[11] = { "kmsg", 0644, &kmsg_fops, NULL },  #endif  }; @@ -891,7 +861,7 @@ static const struct file_operations memory_fops = {  	.llseek = noop_llseek,  }; -static char *mem_devnode(struct device *dev, mode_t *mode) +static char *mem_devnode(struct device *dev, umode_t *mode)  {  	if (mode && devlist[MINOR(dev->devt)].mode)  		*mode = devlist[MINOR(dev->devt)].mode; @@ -920,6 +890,13 @@ static int __init chr_dev_init(void)  	for (minor = 1; minor < ARRAY_SIZE(devlist); minor++) {  		if (!devlist[minor].name)  			continue; + +		/* +		 * Create /dev/port? +		 */ +		if ((minor == DEVPORT_MINOR) && !arch_has_dev_port()) +			continue; +  		device_create(mem_class, NULL, MKDEV(MEM_MAJOR, minor),  			      NULL, devlist[minor].name);  	}  | 
