Loading Documentation/filesystems/xip.txt +9 −6 Original line number Original line Diff line number Diff line Loading @@ -28,12 +28,15 @@ Implementation Execute-in-place is implemented in three steps: block device operation, Execute-in-place is implemented in three steps: block device operation, address space operation, and file operations. address space operation, and file operations. A block device operation named direct_access is used to retrieve a A block device operation named direct_access is used to translate the reference (pointer) to a block on-disk. The reference is supposed to be block device sector number to a page frame number (pfn) that identifies cpu-addressable, physical address and remain valid until the release operation the physical page for the memory. It also returns a kernel virtual is performed. A struct block_device reference is used to address the device, address that can be used to access the memory. and a sector_t argument is used to identify the individual block. As an alternative, memory technology devices can be used for this. The direct_access method takes a 'size' parameter that indicates the number of bytes being requested. The function should return the number of bytes that can be contiguously accessed at that offset. It may also return a negative errno if an error occurs. The block device operation is optional, these block devices support it as of The block device operation is optional, these block devices support it as of today: today: Loading arch/powerpc/sysdev/axonram.c +4 −13 Original line number Original line Diff line number Diff line Loading @@ -139,26 +139,17 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio) * axon_ram_direct_access - direct_access() method for block device * axon_ram_direct_access - direct_access() method for block device * @device, @sector, @data: see block_device_operations method * @device, @sector, @data: see block_device_operations method */ */ static int static long axon_ram_direct_access(struct block_device *device, sector_t sector, axon_ram_direct_access(struct block_device *device, sector_t sector, void **kaddr, unsigned long *pfn) void **kaddr, unsigned long *pfn, long size) { { struct axon_ram_bank *bank = device->bd_disk->private_data; struct axon_ram_bank *bank = device->bd_disk->private_data; loff_t offset; loff_t offset = (loff_t)sector << AXON_RAM_SECTOR_SHIFT; offset = sector; if (device->bd_part != NULL) offset += device->bd_part->start_sect; offset <<= AXON_RAM_SECTOR_SHIFT; if (offset >= bank->size) { dev_err(&bank->device->dev, "Access outside of address space\n"); return -ERANGE; } *kaddr = (void *)(bank->ph_addr + offset); *kaddr = (void *)(bank->ph_addr + offset); *pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT; *pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT; return 0; return bank->size - offset; } } static const struct block_device_operations axon_ram_devops = { static const struct block_device_operations axon_ram_devops = { Loading drivers/block/brd.c +7 −7 Original line number Original line Diff line number Diff line Loading @@ -370,25 +370,25 @@ static int brd_rw_page(struct block_device *bdev, sector_t sector, } } #ifdef CONFIG_BLK_DEV_XIP #ifdef CONFIG_BLK_DEV_XIP static int brd_direct_access(struct block_device *bdev, sector_t sector, static long brd_direct_access(struct block_device *bdev, sector_t sector, void **kaddr, unsigned long *pfn) void **kaddr, unsigned long *pfn, long size) { { struct brd_device *brd = bdev->bd_disk->private_data; struct brd_device *brd = bdev->bd_disk->private_data; struct page *page; struct page *page; if (!brd) if (!brd) return -ENODEV; return -ENODEV; if (sector & (PAGE_SECTORS-1)) return -EINVAL; if (sector + PAGE_SECTORS > get_capacity(bdev->bd_disk)) return -ERANGE; page = brd_insert_page(brd, sector); page = brd_insert_page(brd, sector); if (!page) if (!page) return -ENOSPC; return -ENOSPC; *kaddr = page_address(page); *kaddr = page_address(page); *pfn = page_to_pfn(page); *pfn = page_to_pfn(page); return 0; /* * TODO: If size > PAGE_SIZE, we could look to see if the next page in * the file happens to be mapped to the next page of physical RAM. */ return PAGE_SIZE; } } #endif #endif Loading drivers/s390/block/dcssblk.c +9 −12 Original line number Original line Diff line number Diff line Loading @@ -28,8 +28,8 @@ static int dcssblk_open(struct block_device *bdev, fmode_t mode); static int dcssblk_open(struct block_device *bdev, fmode_t mode); static void dcssblk_release(struct gendisk *disk, fmode_t mode); static void dcssblk_release(struct gendisk *disk, fmode_t mode); static void dcssblk_make_request(struct request_queue *q, struct bio *bio); static void dcssblk_make_request(struct request_queue *q, struct bio *bio); static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum, static long dcssblk_direct_access(struct block_device *bdev, sector_t secnum, void **kaddr, unsigned long *pfn); void **kaddr, unsigned long *pfn, long size); static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0"; static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0"; Loading Loading @@ -866,25 +866,22 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio) bio_io_error(bio); bio_io_error(bio); } } static int static long dcssblk_direct_access (struct block_device *bdev, sector_t secnum, dcssblk_direct_access (struct block_device *bdev, sector_t secnum, void **kaddr, unsigned long *pfn) void **kaddr, unsigned long *pfn, long size) { { struct dcssblk_dev_info *dev_info; struct dcssblk_dev_info *dev_info; unsigned long pgoff; unsigned long offset, dev_sz; dev_info = bdev->bd_disk->private_data; dev_info = bdev->bd_disk->private_data; if (!dev_info) if (!dev_info) return -ENODEV; return -ENODEV; if (secnum % (PAGE_SIZE/512)) dev_sz = dev_info->end - dev_info->start; return -EINVAL; offset = secnum * 512; pgoff = secnum / (PAGE_SIZE / 512); *kaddr = (void *) (dev_info->start + offset); if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start) return -ERANGE; *kaddr = (void *) (dev_info->start+pgoff*PAGE_SIZE); *pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT; *pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT; return 0; return dev_sz - offset; } } static void static void Loading fs/block_dev.c +40 −0 Original line number Original line Diff line number Diff line Loading @@ -429,6 +429,46 @@ int bdev_write_page(struct block_device *bdev, sector_t sector, } } EXPORT_SYMBOL_GPL(bdev_write_page); EXPORT_SYMBOL_GPL(bdev_write_page); /** * bdev_direct_access() - Get the address for directly-accessibly memory * @bdev: The device containing the memory * @sector: The offset within the device * @addr: Where to put the address of the memory * @pfn: The Page Frame Number for the memory * @size: The number of bytes requested * * If a block device is made up of directly addressable memory, this function * will tell the caller the PFN and the address of the memory. The address * may be directly dereferenced within the kernel without the need to call * ioremap(), kmap() or similar. The PFN is suitable for inserting into * page tables. * * Return: negative errno if an error occurs, otherwise the number of bytes * accessible at this address. */ long bdev_direct_access(struct block_device *bdev, sector_t sector, void **addr, unsigned long *pfn, long size) { long avail; const struct block_device_operations *ops = bdev->bd_disk->fops; if (size < 0) return size; if (!ops->direct_access) return -EOPNOTSUPP; if ((sector + DIV_ROUND_UP(size, 512)) > part_nr_sects_read(bdev->bd_part)) return -ERANGE; sector += get_start_sect(bdev); if (sector % (PAGE_SIZE / 512)) return -EINVAL; avail = ops->direct_access(bdev, sector, addr, pfn, size); if (!avail) return -ERANGE; return min(avail, size); } EXPORT_SYMBOL_GPL(bdev_direct_access); /* /* * pseudo-fs * pseudo-fs */ */ Loading Loading
Documentation/filesystems/xip.txt +9 −6 Original line number Original line Diff line number Diff line Loading @@ -28,12 +28,15 @@ Implementation Execute-in-place is implemented in three steps: block device operation, Execute-in-place is implemented in three steps: block device operation, address space operation, and file operations. address space operation, and file operations. A block device operation named direct_access is used to retrieve a A block device operation named direct_access is used to translate the reference (pointer) to a block on-disk. The reference is supposed to be block device sector number to a page frame number (pfn) that identifies cpu-addressable, physical address and remain valid until the release operation the physical page for the memory. It also returns a kernel virtual is performed. A struct block_device reference is used to address the device, address that can be used to access the memory. and a sector_t argument is used to identify the individual block. As an alternative, memory technology devices can be used for this. The direct_access method takes a 'size' parameter that indicates the number of bytes being requested. The function should return the number of bytes that can be contiguously accessed at that offset. It may also return a negative errno if an error occurs. The block device operation is optional, these block devices support it as of The block device operation is optional, these block devices support it as of today: today: Loading
arch/powerpc/sysdev/axonram.c +4 −13 Original line number Original line Diff line number Diff line Loading @@ -139,26 +139,17 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio) * axon_ram_direct_access - direct_access() method for block device * axon_ram_direct_access - direct_access() method for block device * @device, @sector, @data: see block_device_operations method * @device, @sector, @data: see block_device_operations method */ */ static int static long axon_ram_direct_access(struct block_device *device, sector_t sector, axon_ram_direct_access(struct block_device *device, sector_t sector, void **kaddr, unsigned long *pfn) void **kaddr, unsigned long *pfn, long size) { { struct axon_ram_bank *bank = device->bd_disk->private_data; struct axon_ram_bank *bank = device->bd_disk->private_data; loff_t offset; loff_t offset = (loff_t)sector << AXON_RAM_SECTOR_SHIFT; offset = sector; if (device->bd_part != NULL) offset += device->bd_part->start_sect; offset <<= AXON_RAM_SECTOR_SHIFT; if (offset >= bank->size) { dev_err(&bank->device->dev, "Access outside of address space\n"); return -ERANGE; } *kaddr = (void *)(bank->ph_addr + offset); *kaddr = (void *)(bank->ph_addr + offset); *pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT; *pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT; return 0; return bank->size - offset; } } static const struct block_device_operations axon_ram_devops = { static const struct block_device_operations axon_ram_devops = { Loading
drivers/block/brd.c +7 −7 Original line number Original line Diff line number Diff line Loading @@ -370,25 +370,25 @@ static int brd_rw_page(struct block_device *bdev, sector_t sector, } } #ifdef CONFIG_BLK_DEV_XIP #ifdef CONFIG_BLK_DEV_XIP static int brd_direct_access(struct block_device *bdev, sector_t sector, static long brd_direct_access(struct block_device *bdev, sector_t sector, void **kaddr, unsigned long *pfn) void **kaddr, unsigned long *pfn, long size) { { struct brd_device *brd = bdev->bd_disk->private_data; struct brd_device *brd = bdev->bd_disk->private_data; struct page *page; struct page *page; if (!brd) if (!brd) return -ENODEV; return -ENODEV; if (sector & (PAGE_SECTORS-1)) return -EINVAL; if (sector + PAGE_SECTORS > get_capacity(bdev->bd_disk)) return -ERANGE; page = brd_insert_page(brd, sector); page = brd_insert_page(brd, sector); if (!page) if (!page) return -ENOSPC; return -ENOSPC; *kaddr = page_address(page); *kaddr = page_address(page); *pfn = page_to_pfn(page); *pfn = page_to_pfn(page); return 0; /* * TODO: If size > PAGE_SIZE, we could look to see if the next page in * the file happens to be mapped to the next page of physical RAM. */ return PAGE_SIZE; } } #endif #endif Loading
drivers/s390/block/dcssblk.c +9 −12 Original line number Original line Diff line number Diff line Loading @@ -28,8 +28,8 @@ static int dcssblk_open(struct block_device *bdev, fmode_t mode); static int dcssblk_open(struct block_device *bdev, fmode_t mode); static void dcssblk_release(struct gendisk *disk, fmode_t mode); static void dcssblk_release(struct gendisk *disk, fmode_t mode); static void dcssblk_make_request(struct request_queue *q, struct bio *bio); static void dcssblk_make_request(struct request_queue *q, struct bio *bio); static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum, static long dcssblk_direct_access(struct block_device *bdev, sector_t secnum, void **kaddr, unsigned long *pfn); void **kaddr, unsigned long *pfn, long size); static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0"; static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0"; Loading Loading @@ -866,25 +866,22 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio) bio_io_error(bio); bio_io_error(bio); } } static int static long dcssblk_direct_access (struct block_device *bdev, sector_t secnum, dcssblk_direct_access (struct block_device *bdev, sector_t secnum, void **kaddr, unsigned long *pfn) void **kaddr, unsigned long *pfn, long size) { { struct dcssblk_dev_info *dev_info; struct dcssblk_dev_info *dev_info; unsigned long pgoff; unsigned long offset, dev_sz; dev_info = bdev->bd_disk->private_data; dev_info = bdev->bd_disk->private_data; if (!dev_info) if (!dev_info) return -ENODEV; return -ENODEV; if (secnum % (PAGE_SIZE/512)) dev_sz = dev_info->end - dev_info->start; return -EINVAL; offset = secnum * 512; pgoff = secnum / (PAGE_SIZE / 512); *kaddr = (void *) (dev_info->start + offset); if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start) return -ERANGE; *kaddr = (void *) (dev_info->start+pgoff*PAGE_SIZE); *pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT; *pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT; return 0; return dev_sz - offset; } } static void static void Loading
fs/block_dev.c +40 −0 Original line number Original line Diff line number Diff line Loading @@ -429,6 +429,46 @@ int bdev_write_page(struct block_device *bdev, sector_t sector, } } EXPORT_SYMBOL_GPL(bdev_write_page); EXPORT_SYMBOL_GPL(bdev_write_page); /** * bdev_direct_access() - Get the address for directly-accessibly memory * @bdev: The device containing the memory * @sector: The offset within the device * @addr: Where to put the address of the memory * @pfn: The Page Frame Number for the memory * @size: The number of bytes requested * * If a block device is made up of directly addressable memory, this function * will tell the caller the PFN and the address of the memory. The address * may be directly dereferenced within the kernel without the need to call * ioremap(), kmap() or similar. The PFN is suitable for inserting into * page tables. * * Return: negative errno if an error occurs, otherwise the number of bytes * accessible at this address. */ long bdev_direct_access(struct block_device *bdev, sector_t sector, void **addr, unsigned long *pfn, long size) { long avail; const struct block_device_operations *ops = bdev->bd_disk->fops; if (size < 0) return size; if (!ops->direct_access) return -EOPNOTSUPP; if ((sector + DIV_ROUND_UP(size, 512)) > part_nr_sects_read(bdev->bd_part)) return -ERANGE; sector += get_start_sect(bdev); if (sector % (PAGE_SIZE / 512)) return -EINVAL; avail = ops->direct_access(bdev, sector, addr, pfn, size); if (!avail) return -ERANGE; return min(avail, size); } EXPORT_SYMBOL_GPL(bdev_direct_access); /* /* * pseudo-fs * pseudo-fs */ */ Loading