/* * Grab the exclusive iolock for a data copy from src to dest, making * sure to abide vfs locking order (lowest pointer value goes first) and * breaking the pnfs layout leases on dest before proceeding. The loop * is needed because we cannot call the blocking break_layout() with the * src iolock held, and therefore have to back out both locks. */ static int xfs_iolock_two_inodes_and_break_layout( struct inode *src, struct inode *dest) { int error; retry: if (src < dest) { inode_lock_shared(src); inode_lock_nested(dest, I_MUTEX_NONDIR2); } else { /* src >= dest */ inode_lock(dest); } error = break_layout(dest, false); if (error == -EWOULDBLOCK) { inode_unlock(dest); if (src < dest) inode_unlock_shared(src); error = break_layout(dest, true); if (error) return error; goto retry; } if (error) { inode_unlock(dest); if (src < dest) inode_unlock_shared(src); return error; } if (src > dest) inode_lock_shared_nested(src, I_MUTEX_NONDIR2); return 0; }
static ssize_t ext2_dax_read_iter(struct kiocb *iocb, struct iov_iter *to) { struct inode *inode = iocb->ki_filp->f_mapping->host; ssize_t ret; if (!iov_iter_count(to)) return 0; /* skip atime */ inode_lock_shared(inode); ret = dax_iomap_rw(iocb, to, &ext2_iomap_ops); inode_unlock_shared(inode); file_accessed(iocb->ki_filp); return ret; }
/* Unlock both inodes after they've been prepped for a range clone. */ void xfs_reflink_remap_unlock( struct file *file_in, struct file *file_out) { struct inode *inode_in = file_inode(file_in); struct xfs_inode *src = XFS_I(inode_in); struct inode *inode_out = file_inode(file_out); struct xfs_inode *dest = XFS_I(inode_out); bool same_inode = (inode_in == inode_out); xfs_iunlock(dest, XFS_MMAPLOCK_EXCL); if (!same_inode) xfs_iunlock(src, XFS_MMAPLOCK_SHARED); inode_unlock(inode_out); if (!same_inode) inode_unlock_shared(inode_in); }
int iterate_dir(struct file *file, struct dir_context *ctx) { struct inode *inode = file_inode(file); bool shared = false; int res = -ENOTDIR; if (file->f_op->iterate_shared) shared = true; else if (!file->f_op->iterate) goto out; res = security_file_permission(file, MAY_READ); if (res) goto out; if (shared) res = down_read_killable(&inode->i_rwsem); else res = down_write_killable(&inode->i_rwsem); if (res) goto out; res = -ENOENT; if (!IS_DEADDIR(inode)) { ctx->pos = file->f_pos; if (shared) res = file->f_op->iterate_shared(file, ctx); else res = file->f_op->iterate(file, ctx); file->f_pos = ctx->pos; fsnotify_access(file); file_accessed(file); } if (shared) inode_unlock_shared(inode); else inode_unlock(inode); out: return res; }