if (mapping->nrpages) {
invalidate_bh_lrus();
lru_add_drain_all(); /* make sure all lru add caches are flushed */
invalidate_mapping_pages(mapping, 0, -1);
}
}
EXPORT_SYMBOL(invalidate_bdev);
/* * Drop all buffers & page cache for given bdev range. This function bails * with error if bdev has other exclusive owner (such as filesystem).
*/ int truncate_bdev_range(struct block_device *bdev, blk_mode_t mode,
loff_t lstart, loff_t lend)
{ /* * If we don't hold exclusive handle for the device, upgrade to it * while we discard the buffer cache to avoid discarding buffers * under live filesystem.
*/ if (!(mode & BLK_OPEN_EXCL)) { int err = bd_prepare_to_claim(bdev, truncate_bdev_range, NULL); if (err) goto invalidate;
}
while (bsize < PAGE_SIZE) { if (size & bsize) break;
bsize <<= 1;
}
BD_INODE(bdev)->i_blkbits = blksize_bits(bsize);
mapping_set_folio_min_order(BD_INODE(bdev)->i_mapping,
get_order(bsize));
}
/** * bdev_validate_blocksize - check that this block size is acceptable * @bdev: blockdevice to check * @block_size: block size to check * * For block device users that do not use buffer heads or the block device * page cache, make sure that this block size can be used with the device. * * Return: On success zero is returned, negative error code on failure.
*/ int bdev_validate_blocksize(struct block_device *bdev, int block_size)
{ if (blk_validate_block_size(block_size)) return -EINVAL;
/* Size cannot be smaller than the size supported by the device */ if (block_size < bdev_logical_block_size(bdev)) return -EINVAL;
int set_blocksize(struct file *file, int size)
{ struct inode *inode = file->f_mapping->host; struct block_device *bdev = I_BDEV(inode); int ret;
ret = bdev_validate_blocksize(bdev, size); if (ret) return ret;
if (!file->private_data) return -EINVAL;
/* Don't change the size if it is same as current */ if (inode->i_blkbits != blksize_bits(size)) { /* * Flush and truncate the pagecache before we reconfigure the * mapping geometry because folio sizes are variable now. If a * reader has already allocated a folio whose size is smaller * than the new min_order but invokes readahead after the new * min_order becomes visible, readahead will think there are * "zero" blocks per folio and crash. Take the inode and * invalidation locks to avoid racing with * read/write/fallocate.
*/
inode_lock(inode);
filemap_invalidate_lock(inode->i_mapping);
int sb_set_blocksize(struct super_block *sb, int size)
{ if (!(sb->s_type->fs_flags & FS_LBS) && size > PAGE_SIZE) return 0; if (set_blocksize(sb->s_bdev_file, size)) return 0; /* If we get here, we know size is validated */
sb->s_blocksize = size;
sb->s_blocksize_bits = blksize_bits(size); return sb->s_blocksize;
}
EXPORT_SYMBOL(sb_set_blocksize);
int sb_min_blocksize(struct super_block *sb, int size)
{ int minsize = bdev_logical_block_size(sb->s_bdev); if (size < minsize)
size = minsize; return sb_set_blocksize(sb, size);
}
EXPORT_SYMBOL(sb_min_blocksize);
int sync_blockdev_nowait(struct block_device *bdev)
{ if (!bdev) return 0; return filemap_flush(bdev->bd_mapping);
}
EXPORT_SYMBOL_GPL(sync_blockdev_nowait);
/* * Write out and wait upon all the dirty data associated with a block * device via its mapping. Does not take the superblock lock.
*/ int sync_blockdev(struct block_device *bdev)
{ if (!bdev) return 0; return filemap_write_and_wait(bdev->bd_mapping);
}
EXPORT_SYMBOL(sync_blockdev);
/** * bdev_freeze - lock a filesystem and force it into a consistent state * @bdev: blockdevice to lock * * If a superblock is found on this device, we take the s_umount semaphore * on it to make sure nobody unmounts until the snapshot creation is done. * The reference counter (bd_fsfreeze_count) guarantees that only the last * unfreeze process can unfreeze the frozen filesystem actually when multiple * freeze requests arrive simultaneously. It counts up in bdev_freeze() and * count down in bdev_thaw(). When it becomes 0, thaw_bdev() will unfreeze * actually. * * Return: On success zero is returned, negative error code on failure.
*/ int bdev_freeze(struct block_device *bdev)
{ int error = 0;
mutex_lock(&bdev->bd_fsfreeze_mutex);
if (atomic_inc_return(&bdev->bd_fsfreeze_count) > 1) {
mutex_unlock(&bdev->bd_fsfreeze_mutex); return 0;
}
/** * bdev_thaw - unlock filesystem * @bdev: blockdevice to unlock * * Unlocks the filesystem and marks it writeable again after bdev_freeze(). * * Return: On success zero is returned, negative error code on failure.
*/ int bdev_thaw(struct block_device *bdev)
{ int error = -EINVAL, nr_freeze;
mutex_lock(&bdev->bd_fsfreeze_mutex);
/* * If this returns < 0 it means that @bd_fsfreeze_count was * already 0 and no decrement was performed.
*/
nr_freeze = atomic_dec_if_positive(&bdev->bd_fsfreeze_count); if (nr_freeze < 0) goto out;
long nr_blockdev_pages(void)
{ struct inode *inode; long ret = 0;
spin_lock(&blockdev_superblock->s_inode_list_lock);
list_for_each_entry(inode, &blockdev_superblock->s_inodes, i_sb_list)
ret += inode->i_mapping->nrpages;
spin_unlock(&blockdev_superblock->s_inode_list_lock);
return ret;
}
/** * bd_may_claim - test whether a block device can be claimed * @bdev: block device of interest * @holder: holder trying to claim @bdev * @hops: holder ops * * Test whether @bdev can be claimed by @holder. * * RETURNS: * %true if @bdev can be claimed, %false otherwise.
*/ staticbool bd_may_claim(struct block_device *bdev, void *holder, conststruct blk_holder_ops *hops)
{ struct block_device *whole = bdev_whole(bdev);
lockdep_assert_held(&bdev_lock);
if (bdev->bd_holder) { /* * The same holder can always re-claim.
*/ if (bdev->bd_holder == holder) { if (WARN_ON_ONCE(bdev->bd_holder_ops != hops)) returnfalse; returntrue;
} returnfalse;
}
/* * If the whole devices holder is set to bd_may_claim, a partition on * the device is claimed, but not the whole device.
*/ if (whole != bdev &&
whole->bd_holder && whole->bd_holder != bd_may_claim) returnfalse; returntrue;
}
/** * bd_prepare_to_claim - claim a block device * @bdev: block device of interest * @holder: holder trying to claim @bdev * @hops: holder ops. * * Claim @bdev. This function fails if @bdev is already claimed by another * holder and waits if another claiming is in progress. return, the caller * has ownership of bd_claiming and bd_holder[s]. * * RETURNS: * 0 if @bdev can be claimed, -EBUSY otherwise.
*/ int bd_prepare_to_claim(struct block_device *bdev, void *holder, conststruct blk_holder_ops *hops)
{ struct block_device *whole = bdev_whole(bdev);
if (WARN_ON_ONCE(!holder)) return -EINVAL;
retry:
mutex_lock(&bdev_lock); /* if someone else claimed, fail */ if (!bd_may_claim(bdev, holder, hops)) {
mutex_unlock(&bdev_lock); return -EBUSY;
}
/* if claiming is already in progress, wait for it to finish */ if (whole->bd_claiming) {
wait_queue_head_t *wq = __var_waitqueue(&whole->bd_claiming);
DEFINE_WAIT(wait);
/* yay, all mine */
whole->bd_claiming = holder;
mutex_unlock(&bdev_lock); return 0;
}
EXPORT_SYMBOL_GPL(bd_prepare_to_claim); /* only for the loop driver */
/** * bd_finish_claiming - finish claiming of a block device * @bdev: block device of interest * @holder: holder that has claimed @bdev * @hops: block device holder operations * * Finish exclusive open of a block device. Mark the device as exlusively * open by the holder and wake up all waiters for exclusive open to finish.
*/ staticvoid bd_finish_claiming(struct block_device *bdev, void *holder, conststruct blk_holder_ops *hops)
{ struct block_device *whole = bdev_whole(bdev);
mutex_lock(&bdev_lock);
BUG_ON(!bd_may_claim(bdev, holder, hops)); /* * Note that for a whole device bd_holders will be incremented twice, * and bd_holder will be set to bd_may_claim before being set to holder
*/
whole->bd_holders++;
whole->bd_holder = bd_may_claim;
bdev->bd_holders++;
mutex_lock(&bdev->bd_holder_lock);
bdev->bd_holder = holder;
bdev->bd_holder_ops = hops;
mutex_unlock(&bdev->bd_holder_lock);
bd_clear_claiming(whole, holder);
mutex_unlock(&bdev_lock);
}
/** * bd_abort_claiming - abort claiming of a block device * @bdev: block device of interest * @holder: holder that has claimed @bdev * * Abort claiming of a block device when the exclusive open failed. This can be * also used when exclusive open is not actually desired and we just needed * to block other exclusive openers for a while.
*/ void bd_abort_claiming(struct block_device *bdev, void *holder)
{
mutex_lock(&bdev_lock);
bd_clear_claiming(bdev_whole(bdev), holder);
mutex_unlock(&bdev_lock);
}
EXPORT_SYMBOL(bd_abort_claiming);
/* * Release a claim on the device. The holder fields are protected with * bdev_lock. open_mutex is used to synchronize disk_holder unlinking.
*/
mutex_lock(&bdev_lock);
WARN_ON_ONCE(bdev->bd_holder != holder);
WARN_ON_ONCE(--bdev->bd_holders < 0);
WARN_ON_ONCE(--whole->bd_holders < 0); if (!bdev->bd_holders) {
mutex_lock(&bdev->bd_holder_lock);
bdev->bd_holder = NULL;
bdev->bd_holder_ops = NULL;
mutex_unlock(&bdev->bd_holder_lock); if (bdev_test_flag(bdev, BD_WRITE_HOLDER))
unblock = true;
} if (!whole->bd_holders)
whole->bd_holder = NULL;
mutex_unlock(&bdev_lock);
/* * If this was the last claim, remove holder link and unblock evpoll if * it was a write holder.
*/ if (unblock) {
disk_unblock_events(bdev->bd_disk);
bdev_clear_flag(bdev, BD_WRITE_HOLDER);
}
}
if (disk->fops->open) {
ret = disk->fops->open(disk, mode); if (ret) { /* avoid ghost partitions on a removed medium */ if (ret == -ENOMEDIUM &&
test_bit(GD_NEED_PART_SCAN, &disk->state))
bdev_disk_changed(disk, true); return ret;
}
}
if (!atomic_read(&bdev->bd_openers))
set_init_blocksize(bdev);
atomic_inc(&bdev->bd_openers); if (test_bit(GD_NEED_PART_SCAN, &disk->state)) { /* * Only return scanning errors if we are called from contexts * that explicitly want them, e.g. the BLKRRPART ioctl.
*/
ret = bdev_disk_changed(disk, false); if (ret && (mode & BLK_OPEN_STRICT_SCAN)) {
blkdev_put_whole(bdev); return ret;
}
} return 0;
}
/* * We're using error pointers to indicate to ->release() when we * failed to open that block device. Also this doesn't make sense.
*/ if (WARN_ON_ONCE(IS_ERR(holder))) return -EINVAL;
inode = ilookup(blockdev_superblock, dev); if (!inode && autoload && IS_ENABLED(CONFIG_BLOCK_LEGACY_AUTOLOAD)) {
blk_request_module(dev);
inode = ilookup(blockdev_superblock, dev); if (inode)
pr_warn_ratelimited( "block device autoloading is deprecated and will be removed.\n");
} if (!inode) return NULL;
/* switch from the inode reference to a device mode one: */
bdev = &BDEV_I(inode)->bdev; if (!kobject_get_unless_zero(&bdev->bd_device.kobj))
bdev = NULL;
iput(inode); return bdev;
}
/** * bdev_open - open a block device * @bdev: block device to open * @mode: open mode (BLK_OPEN_*) * @holder: exclusive holder identifier * @hops: holder operations * @bdev_file: file for the block device * * Open the block device. If @holder is not %NULL, the block device is opened * with exclusive access. Exclusive opens may nest for the same @holder. * * CONTEXT: * Might sleep. * * RETURNS: * zero on success, -errno on failure.
*/ int bdev_open(struct block_device *bdev, blk_mode_t mode, void *holder, conststruct blk_holder_ops *hops, struct file *bdev_file)
{ bool unblock_events = true; struct gendisk *disk = bdev->bd_disk; int ret;
if (holder) {
mode |= BLK_OPEN_EXCL;
ret = bd_prepare_to_claim(bdev, holder, hops); if (ret) return ret;
} else { if (WARN_ON_ONCE(mode & BLK_OPEN_EXCL)) return -EIO;
}
disk_block_events(disk);
mutex_lock(&disk->open_mutex);
ret = -ENXIO; if (!disk_live(disk)) goto abort_claiming; if (!try_module_get(disk->fops->owner)) goto abort_claiming;
ret = -EBUSY; if (!bdev_may_open(bdev, mode)) goto put_module; if (bdev_is_partition(bdev))
ret = blkdev_get_part(bdev, mode); else
ret = blkdev_get_whole(bdev, mode); if (ret) goto put_module;
bdev_claim_write_access(bdev, mode); if (holder) {
bd_finish_claiming(bdev, holder, hops);
/* * Block event polling for write claims if requested. Any write * holder makes the write_holder state stick until all are * released. This is good enough and tracking individual * writeable reference is too fragile given the way @mode is * used in blkdev_get/put().
*/ if ((mode & BLK_OPEN_WRITE) &&
!bdev_test_flag(bdev, BD_WRITE_HOLDER) &&
(disk->event_flags & DISK_EVENT_FLAG_BLOCK_ON_EXCL_WRITE)) {
bdev_set_flag(bdev, BD_WRITE_HOLDER);
unblock_events = false;
}
}
mutex_unlock(&disk->open_mutex);
/* * If BLK_OPEN_WRITE_IOCTL is set then this is a historical quirk * associated with the floppy driver where it has allowed ioctls if the * file was opened for writing, but does not allow reads or writes. * Make sure that this quirk is reflected in @f_flags. * * It can also happen if a block device is opened as O_RDWR | O_WRONLY.
*/ staticunsigned blk_to_file_flags(blk_mode_t mode)
{ unsignedint flags = 0;
ret = bdev_open(bdev, mode, holder, hops, bdev_file); if (ret) { /* We failed to open the block device. Let ->release() know. */
bdev_file->private_data = ERR_PTR(ret);
fput(bdev_file); return ERR_PTR(ret);
} return bdev_file;
}
EXPORT_SYMBOL(bdev_file_open_by_dev);
/* We failed to open that block device. */ if (IS_ERR(holder)) goto put_no_open;
/* * Sync early if it looks like we're the last one. If someone else * opens the block device between now and the decrement of bd_openers * then we did a sync that we didn't need to, but that's not the end * of the world and we want to avoid long (could be several minute) * syncs while holding the mutex.
*/ if (atomic_read(&bdev->bd_openers) == 1)
sync_blockdev(bdev);
/* * Trigger event checking and tell drivers to flush MEDIA_CHANGE * event. This is to ensure detection of media removal commanded * from userland - e.g. eject(1).
*/
disk_flush_events(disk, DISK_EVENT_MEDIA_CHANGE);
if (bdev_is_partition(bdev))
blkdev_put_part(bdev); else
blkdev_put_whole(bdev);
mutex_unlock(&disk->open_mutex);
/** * bdev_fput - yield claim to the block device and put the file * @bdev_file: open block device * * Yield claim on the block device and put the file. Ensure that the * block device can be reclaimed before the file is closed which is a * deferred operation.
*/ void bdev_fput(struct file *bdev_file)
{ if (WARN_ON_ONCE(bdev_file->f_op != &def_blk_fops)) return;
mutex_lock(&disk->open_mutex);
bdev_yield_write_access(bdev_file);
bd_yield_claim(bdev_file); /* * Tell release we already gave up our hold on the * device and if write restrictions are available that * we already gave up write access to the device.
*/
bdev_file->private_data = BDEV_I(bdev_file->f_mapping->host);
mutex_unlock(&disk->open_mutex);
}
fput(bdev_file);
}
EXPORT_SYMBOL(bdev_fput);
/** * lookup_bdev() - Look up a struct block_device by name. * @pathname: Name of the block device in the filesystem. * @dev: Pointer to the block device's dev_t, if found. * * Lookup the block device's dev_t at @pathname in the current * namespace if possible and return it in @dev. * * Context: May sleep. * Return: 0 if succeeded, negative errno otherwise.
*/ int lookup_bdev(constchar *pathname, dev_t *dev)
{ struct inode *inode; struct path path; int error;
if (!pathname || !*pathname) return -EINVAL;
error = kern_path(pathname, LOOKUP_FOLLOW, &path); if (error) return error;
inode = d_backing_inode(path.dentry);
error = -ENOTBLK; if (!S_ISBLK(inode->i_mode)) goto out_path_put;
error = -EACCES; if (!may_open_dev(&path)) goto out_path_put;
/** * bdev_mark_dead - mark a block device as dead * @bdev: block device to operate on * @surprise: indicate a surprise removal * * Tell the file system that this devices or media is dead. If @surprise is set * to %true the device or media is already gone, if not we are preparing for an * orderly removal. * * This calls into the file system, which then typicall syncs out all dirty data * and writes back inodes and then invalidates any cached data in the inodes on * the file system. In addition we also invalidate the block device mapping.
*/ void bdev_mark_dead(struct block_device *bdev, bool surprise)
{
mutex_lock(&bdev->bd_holder_lock); if (bdev->bd_holder_ops && bdev->bd_holder_ops->mark_dead)
bdev->bd_holder_ops->mark_dead(bdev, surprise); else {
mutex_unlock(&bdev->bd_holder_lock);
sync_blockdev(bdev);
}
invalidate_bdev(bdev);
} /* * New drivers should not use this directly. There are some drivers however * that needs this for historical reasons. For example, the DASD driver has * historically had a shutdown to offline mode that doesn't actually remove the * gendisk that otherwise looks a lot like a safe device removal.
*/
EXPORT_SYMBOL_GPL(bdev_mark_dead);
spin_lock(&inode->i_lock); if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW) ||
mapping->nrpages == 0) {
spin_unlock(&inode->i_lock); continue;
}
__iget(inode);
spin_unlock(&inode->i_lock);
spin_unlock(&blockdev_superblock->s_inode_list_lock); /* * We hold a reference to 'inode' so it couldn't have been * removed from s_inodes list while we dropped the * s_inode_list_lock We cannot iput the inode now as we can * be holding the last reference and we cannot iput it under * s_inode_list_lock. So we keep the reference and iput it * later.
*/
iput(old_inode);
old_inode = inode;
bdev = I_BDEV(inode);
mutex_lock(&bdev->bd_disk->open_mutex); if (!atomic_read(&bdev->bd_openers)) {
; /* skip */
} elseif (wait) { /* * We keep the error status of individual mapping so * that applications can catch the writeback error using * fsync(2). See filemap_fdatawait_keep_errors() for * details.
*/
filemap_fdatawait_keep_errors(inode->i_mapping);
} else {
filemap_fdatawrite(inode->i_mapping);
}
mutex_unlock(&bdev->bd_disk->open_mutex);
/* * Note that d_backing_inode() returns the block device node inode, not * the block device's internal inode. Therefore it is *not* valid to * use I_BDEV() here; the block device has to be looked up by i_rdev * instead.
*/
bdev = blkdev_get_no_open(d_backing_inode(path->dentry)->i_rdev, false); if (!bdev) return;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.