Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/hch/vfs-queue
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/hch/vfs-queue: (21 commits) leases: fix write-open/read-lease race nfs: drop unnecessary locking in llseek ext4: replace cut'n'pasted llseek code with generic_file_llseek_size vfs: add generic_file_llseek_size vfs: do (nearly) lockless generic_file_llseek direct-io: merge direct_io_walker into __blockdev_direct_IO direct-io: inline the complete submission path direct-io: separate map_bh from dio direct-io: use a slab cache for struct dio direct-io: rearrange fields in dio/dio_submit to avoid holes direct-io: fix a wrong comment direct-io: separate fields only used in the submission path from struct dio vfs: fix spinning prevention in prune_icache_sb vfs: add a comment to inode_permission() vfs: pass all mask flags check_acl and posix_acl_permission vfs: add hex format for MAY_* flag values vfs: indicate that the permission functions take all the MAY_* flags compat: sync compat_stats with statfs. vfs: add "device" tag to /proc/self/mountstats cleanup: vfs: small comment fix for block_invalidatepage ... Fix up trivial conflict in fs/gfs2/file.c (llseek changes)
This commit is contained in:
commit
f362f98e7c
@ -111,7 +111,8 @@ struct compat_statfs {
|
||||
int f_bavail;
|
||||
compat_fsid_t f_fsid;
|
||||
int f_namelen;
|
||||
int f_spare[6];
|
||||
int f_flags;
|
||||
int f_spare[5];
|
||||
};
|
||||
|
||||
#define COMPAT_RLIM_INFINITY 0x7fffffffUL
|
||||
|
@ -105,7 +105,8 @@ struct compat_statfs {
|
||||
__kernel_fsid_t f_fsid;
|
||||
s32 f_namelen;
|
||||
s32 f_frsize;
|
||||
s32 f_spare[5];
|
||||
s32 f_flags;
|
||||
s32 f_spare[4];
|
||||
};
|
||||
|
||||
struct compat_sigcontext {
|
||||
|
@ -100,7 +100,8 @@ struct compat_statfs {
|
||||
compat_fsid_t f_fsid;
|
||||
int f_namelen; /* SunOS ignores this field. */
|
||||
int f_frsize;
|
||||
int f_spare[5];
|
||||
int f_flags;
|
||||
int f_spare[4];
|
||||
};
|
||||
|
||||
#define COMPAT_RLIM_OLD_INFINITY 0x7fffffff
|
||||
|
@ -131,7 +131,8 @@ struct compat_statfs {
|
||||
compat_fsid_t f_fsid;
|
||||
s32 f_namelen;
|
||||
s32 f_frsize;
|
||||
s32 f_spare[6];
|
||||
s32 f_flags;
|
||||
s32 f_spare[5];
|
||||
};
|
||||
|
||||
#define COMPAT_RLIM_OLD_INFINITY 0x7fffffff
|
||||
|
@ -134,7 +134,8 @@ struct compat_statfs {
|
||||
compat_fsid_t f_fsid;
|
||||
int f_namelen; /* SunOS ignores this field. */
|
||||
int f_frsize;
|
||||
int f_spare[5];
|
||||
int f_flags;
|
||||
int f_spare[4];
|
||||
};
|
||||
|
||||
#define COMPAT_RLIM_INFINITY 0x7fffffff
|
||||
|
@ -108,7 +108,8 @@ struct compat_statfs {
|
||||
compat_fsid_t f_fsid;
|
||||
int f_namelen; /* SunOS ignores this field. */
|
||||
int f_frsize;
|
||||
int f_spare[5];
|
||||
int f_flags;
|
||||
int f_spare[4];
|
||||
};
|
||||
|
||||
#define COMPAT_RLIM_OLD_INFINITY 0x7fffffff
|
||||
|
@ -1821,7 +1821,7 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int origin)
|
||||
switch (origin) {
|
||||
case SEEK_END:
|
||||
case SEEK_CUR:
|
||||
offset = generic_file_llseek_unlocked(file, offset, origin);
|
||||
offset = generic_file_llseek(file, offset, origin);
|
||||
goto out;
|
||||
case SEEK_DATA:
|
||||
case SEEK_HOLE:
|
||||
|
@ -1470,13 +1470,13 @@ static void discard_buffer(struct buffer_head * bh)
|
||||
}
|
||||
|
||||
/**
|
||||
* block_invalidatepage - invalidate part of all of a buffer-backed page
|
||||
* block_invalidatepage - invalidate part or all of a buffer-backed page
|
||||
*
|
||||
* @page: the page which is affected
|
||||
* @offset: the index of the truncation point
|
||||
*
|
||||
* block_invalidatepage() is called when all or part of the page has become
|
||||
* invalidatedby a truncate operation.
|
||||
* invalidated by a truncate operation.
|
||||
*
|
||||
* block_invalidatepage() does not have to release all buffers, but it must
|
||||
* ensure that no dirty buffer is left outside @offset and that no I/O
|
||||
|
@ -730,7 +730,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
|
||||
if (rc < 0)
|
||||
return (loff_t)rc;
|
||||
}
|
||||
return generic_file_llseek_unlocked(file, offset, origin);
|
||||
return generic_file_llseek(file, offset, origin);
|
||||
}
|
||||
|
||||
static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
|
||||
|
@ -246,11 +246,8 @@ static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *
|
||||
__put_user(kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]) ||
|
||||
__put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) ||
|
||||
__put_user(kbuf->f_frsize, &ubuf->f_frsize) ||
|
||||
__put_user(0, &ubuf->f_spare[0]) ||
|
||||
__put_user(0, &ubuf->f_spare[1]) ||
|
||||
__put_user(0, &ubuf->f_spare[2]) ||
|
||||
__put_user(0, &ubuf->f_spare[3]) ||
|
||||
__put_user(0, &ubuf->f_spare[4]))
|
||||
__put_user(kbuf->f_flags, &ubuf->f_flags) ||
|
||||
__clear_user(ubuf->f_spare, sizeof(ubuf->f_spare)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
646
fs/direct-io.c
646
fs/direct-io.c
File diff suppressed because it is too large
Load Diff
@ -224,53 +224,8 @@ loff_t ext4_llseek(struct file *file, loff_t offset, int origin)
|
||||
maxbytes = EXT4_SB(inode->i_sb)->s_bitmap_maxbytes;
|
||||
else
|
||||
maxbytes = inode->i_sb->s_maxbytes;
|
||||
mutex_lock(&inode->i_mutex);
|
||||
switch (origin) {
|
||||
case SEEK_END:
|
||||
offset += inode->i_size;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
if (offset == 0) {
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
return file->f_pos;
|
||||
}
|
||||
offset += file->f_pos;
|
||||
break;
|
||||
case SEEK_DATA:
|
||||
/*
|
||||
* In the generic case the entire file is data, so as long as
|
||||
* offset isn't at the end of the file then the offset is data.
|
||||
*/
|
||||
if (offset >= inode->i_size) {
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
return -ENXIO;
|
||||
}
|
||||
break;
|
||||
case SEEK_HOLE:
|
||||
/*
|
||||
* There is a virtual hole at the end of the file, so as long as
|
||||
* offset isn't i_size or larger, return i_size.
|
||||
*/
|
||||
if (offset >= inode->i_size) {
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
return -ENXIO;
|
||||
}
|
||||
offset = inode->i_size;
|
||||
break;
|
||||
}
|
||||
|
||||
if (offset < 0 || offset > maxbytes) {
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (offset != file->f_pos) {
|
||||
file->f_pos = offset;
|
||||
file->f_version = 0;
|
||||
}
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
return offset;
|
||||
return generic_file_llseek_size(file, offset, origin, maxbytes);
|
||||
}
|
||||
|
||||
const struct file_operations ext4_file_operations = {
|
||||
|
@ -66,13 +66,13 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin)
|
||||
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY,
|
||||
&i_gh);
|
||||
if (!error) {
|
||||
error = generic_file_llseek_unlocked(file, offset, origin);
|
||||
error = generic_file_llseek(file, offset, origin);
|
||||
gfs2_glock_dq_uninit(&i_gh);
|
||||
}
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
case SEEK_SET:
|
||||
error = generic_file_llseek_unlocked(file, offset, origin);
|
||||
error = generic_file_llseek(file, offset, origin);
|
||||
break;
|
||||
default:
|
||||
error = -EINVAL;
|
||||
|
@ -634,7 +634,7 @@ void prune_icache_sb(struct super_block *sb, int nr_to_scan)
|
||||
* inode to the back of the list so we don't spin on it.
|
||||
*/
|
||||
if (!spin_trylock(&inode->i_lock)) {
|
||||
list_move(&inode->i_lru, &sb->s_inode_lru);
|
||||
list_move_tail(&inode->i_lru, &sb->s_inode_lru);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
17
fs/namei.c
17
fs/namei.c
@ -221,14 +221,12 @@ static int check_acl(struct inode *inode, int mask)
|
||||
}
|
||||
|
||||
/*
|
||||
* This does basic POSIX ACL permission checking
|
||||
* This does the basic permission checking
|
||||
*/
|
||||
static int acl_permission_check(struct inode *inode, int mask)
|
||||
{
|
||||
unsigned int mode = inode->i_mode;
|
||||
|
||||
mask &= MAY_READ | MAY_WRITE | MAY_EXEC | MAY_NOT_BLOCK;
|
||||
|
||||
if (current_user_ns() != inode_userns(inode))
|
||||
goto other_perms;
|
||||
|
||||
@ -257,7 +255,7 @@ other_perms:
|
||||
/**
|
||||
* generic_permission - check for access rights on a Posix-like filesystem
|
||||
* @inode: inode to check access rights for
|
||||
* @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
|
||||
* @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC, ...)
|
||||
*
|
||||
* Used to check for read/write/execute permissions on a file.
|
||||
* We use "fsuid" for this, letting us set arbitrary permissions
|
||||
@ -273,7 +271,7 @@ int generic_permission(struct inode *inode, int mask)
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Do the basic POSIX ACL permission checks.
|
||||
* Do the basic permission checks.
|
||||
*/
|
||||
ret = acl_permission_check(inode, mask);
|
||||
if (ret != -EACCES)
|
||||
@ -331,12 +329,14 @@ static inline int do_inode_permission(struct inode *inode, int mask)
|
||||
/**
|
||||
* inode_permission - check for access rights to a given inode
|
||||
* @inode: inode to check permission on
|
||||
* @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC)
|
||||
* @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC, ...)
|
||||
*
|
||||
* Used to check for read/write/execute permissions on an inode.
|
||||
* We use "fsuid" for this, letting us set arbitrary permissions
|
||||
* for filesystem access without changing the "normal" uids which
|
||||
* are used for other things.
|
||||
*
|
||||
* When checking for MAY_APPEND, MAY_WRITE must also be set in @mask.
|
||||
*/
|
||||
int inode_permission(struct inode *inode, int mask)
|
||||
{
|
||||
@ -2035,10 +2035,7 @@ static int may_open(struct path *path, int acc_mode, int flag)
|
||||
if (flag & O_NOATIME && !inode_owner_or_capable(inode))
|
||||
return -EPERM;
|
||||
|
||||
/*
|
||||
* Ensure there are no outstanding leases on the file.
|
||||
*/
|
||||
return break_lease(inode, flag);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_truncate(struct file *filp)
|
||||
|
@ -1109,6 +1109,7 @@ static int show_vfsstat(struct seq_file *m, void *v)
|
||||
|
||||
/* device */
|
||||
if (mnt->mnt_sb->s_op->show_devname) {
|
||||
seq_puts(m, "device ");
|
||||
err = mnt->mnt_sb->s_op->show_devname(m, mnt);
|
||||
} else {
|
||||
if (mnt->mnt_devname) {
|
||||
|
@ -180,8 +180,6 @@ force_reval:
|
||||
|
||||
static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
|
||||
{
|
||||
loff_t loff;
|
||||
|
||||
dprintk("NFS: llseek file(%s/%s, %lld, %d)\n",
|
||||
filp->f_path.dentry->d_parent->d_name.name,
|
||||
filp->f_path.dentry->d_name.name,
|
||||
@ -197,13 +195,9 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
|
||||
int retval = nfs_revalidate_file_size(inode, filp);
|
||||
if (retval < 0)
|
||||
return (loff_t)retval;
|
||||
}
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
loff = generic_file_llseek_unlocked(filp, offset, origin);
|
||||
spin_unlock(&inode->i_lock);
|
||||
} else
|
||||
loff = generic_file_llseek_unlocked(filp, offset, origin);
|
||||
return loff;
|
||||
return generic_file_llseek(filp, offset, origin);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -685,6 +685,10 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
|
||||
if (error)
|
||||
goto cleanup_all;
|
||||
|
||||
error = break_lease(inode, f->f_flags);
|
||||
if (error)
|
||||
goto cleanup_all;
|
||||
|
||||
if (!open && f->f_op)
|
||||
open = f->f_op->open;
|
||||
if (open) {
|
||||
|
@ -218,6 +218,8 @@ posix_acl_permission(struct inode *inode, const struct posix_acl *acl, int want)
|
||||
const struct posix_acl_entry *pa, *pe, *mask_obj;
|
||||
int found = 0;
|
||||
|
||||
want &= MAY_READ | MAY_WRITE | MAY_EXEC | MAY_NOT_BLOCK;
|
||||
|
||||
FOREACH_ACL_ENTRY(pa, acl, pe) {
|
||||
switch(pa->e_tag) {
|
||||
case ACL_USER_OBJ:
|
||||
|
@ -35,23 +35,45 @@ static inline int unsigned_offsets(struct file *file)
|
||||
return file->f_mode & FMODE_UNSIGNED_OFFSET;
|
||||
}
|
||||
|
||||
static loff_t lseek_execute(struct file *file, struct inode *inode,
|
||||
loff_t offset, loff_t maxsize)
|
||||
{
|
||||
if (offset < 0 && !unsigned_offsets(file))
|
||||
return -EINVAL;
|
||||
if (offset > maxsize)
|
||||
return -EINVAL;
|
||||
|
||||
if (offset != file->f_pos) {
|
||||
file->f_pos = offset;
|
||||
file->f_version = 0;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* generic_file_llseek_unlocked - lockless generic llseek implementation
|
||||
* generic_file_llseek_size - generic llseek implementation for regular files
|
||||
* @file: file structure to seek on
|
||||
* @offset: file offset to seek to
|
||||
* @origin: type of seek
|
||||
* @size: max size of file system
|
||||
*
|
||||
* Updates the file offset to the value specified by @offset and @origin.
|
||||
* Locking must be provided by the caller.
|
||||
* This is a variant of generic_file_llseek that allows passing in a custom
|
||||
* file size.
|
||||
*
|
||||
* Synchronization:
|
||||
* SEEK_SET and SEEK_END are unsynchronized (but atomic on 64bit platforms)
|
||||
* SEEK_CUR is synchronized against other SEEK_CURs, but not read/writes.
|
||||
* read/writes behave like SEEK_SET against seeks.
|
||||
*/
|
||||
loff_t
|
||||
generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin)
|
||||
generic_file_llseek_size(struct file *file, loff_t offset, int origin,
|
||||
loff_t maxsize)
|
||||
{
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
|
||||
switch (origin) {
|
||||
case SEEK_END:
|
||||
offset += inode->i_size;
|
||||
offset += i_size_read(inode);
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
/*
|
||||
@ -62,14 +84,22 @@ generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin)
|
||||
*/
|
||||
if (offset == 0)
|
||||
return file->f_pos;
|
||||
offset += file->f_pos;
|
||||
break;
|
||||
/*
|
||||
* f_lock protects against read/modify/write race with other
|
||||
* SEEK_CURs. Note that parallel writes and reads behave
|
||||
* like SEEK_SET.
|
||||
*/
|
||||
spin_lock(&file->f_lock);
|
||||
offset = lseek_execute(file, inode, file->f_pos + offset,
|
||||
maxsize);
|
||||
spin_unlock(&file->f_lock);
|
||||
return offset;
|
||||
case SEEK_DATA:
|
||||
/*
|
||||
* In the generic case the entire file is data, so as long as
|
||||
* offset isn't at the end of the file then the offset is data.
|
||||
*/
|
||||
if (offset >= inode->i_size)
|
||||
if (offset >= i_size_read(inode))
|
||||
return -ENXIO;
|
||||
break;
|
||||
case SEEK_HOLE:
|
||||
@ -77,26 +107,15 @@ generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin)
|
||||
* There is a virtual hole at the end of the file, so as long as
|
||||
* offset isn't i_size or larger, return i_size.
|
||||
*/
|
||||
if (offset >= inode->i_size)
|
||||
if (offset >= i_size_read(inode))
|
||||
return -ENXIO;
|
||||
offset = inode->i_size;
|
||||
offset = i_size_read(inode);
|
||||
break;
|
||||
}
|
||||
|
||||
if (offset < 0 && !unsigned_offsets(file))
|
||||
return -EINVAL;
|
||||
if (offset > inode->i_sb->s_maxbytes)
|
||||
return -EINVAL;
|
||||
|
||||
/* Special lock needed here? */
|
||||
if (offset != file->f_pos) {
|
||||
file->f_pos = offset;
|
||||
file->f_version = 0;
|
||||
}
|
||||
|
||||
return offset;
|
||||
return lseek_execute(file, inode, offset, maxsize);
|
||||
}
|
||||
EXPORT_SYMBOL(generic_file_llseek_unlocked);
|
||||
EXPORT_SYMBOL(generic_file_llseek_size);
|
||||
|
||||
/**
|
||||
* generic_file_llseek - generic llseek implementation for regular files
|
||||
@ -110,13 +129,10 @@ EXPORT_SYMBOL(generic_file_llseek_unlocked);
|
||||
*/
|
||||
loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
|
||||
{
|
||||
loff_t rval;
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
|
||||
mutex_lock(&file->f_dentry->d_inode->i_mutex);
|
||||
rval = generic_file_llseek_unlocked(file, offset, origin);
|
||||
mutex_unlock(&file->f_dentry->d_inode->i_mutex);
|
||||
|
||||
return rval;
|
||||
return generic_file_llseek_size(file, offset, origin,
|
||||
inode->i_sb->s_maxbytes);
|
||||
}
|
||||
EXPORT_SYMBOL(generic_file_llseek);
|
||||
|
||||
|
@ -58,14 +58,15 @@ struct inodes_stat_t {
|
||||
|
||||
#define NR_FILE 8192 /* this can well be larger on a larger system */
|
||||
|
||||
#define MAY_EXEC 1
|
||||
#define MAY_WRITE 2
|
||||
#define MAY_READ 4
|
||||
#define MAY_APPEND 8
|
||||
#define MAY_ACCESS 16
|
||||
#define MAY_OPEN 32
|
||||
#define MAY_CHDIR 64
|
||||
#define MAY_NOT_BLOCK 128 /* called from RCU mode, don't block */
|
||||
#define MAY_EXEC 0x00000001
|
||||
#define MAY_WRITE 0x00000002
|
||||
#define MAY_READ 0x00000004
|
||||
#define MAY_APPEND 0x00000008
|
||||
#define MAY_ACCESS 0x00000010
|
||||
#define MAY_OPEN 0x00000020
|
||||
#define MAY_CHDIR 0x00000040
|
||||
/* called from RCU mode, don't block */
|
||||
#define MAY_NOT_BLOCK 0x00000080
|
||||
|
||||
/*
|
||||
* flags in file.f_mode. Note that FMODE_READ and FMODE_WRITE must correspond
|
||||
@ -963,7 +964,12 @@ struct file {
|
||||
#define f_dentry f_path.dentry
|
||||
#define f_vfsmnt f_path.mnt
|
||||
const struct file_operations *f_op;
|
||||
spinlock_t f_lock; /* f_ep_links, f_flags, no IRQ */
|
||||
|
||||
/*
|
||||
* Protects f_ep_links, f_flags, f_pos vs i_size in lseek SEEK_CUR.
|
||||
* Must not be taken from IRQ context.
|
||||
*/
|
||||
spinlock_t f_lock;
|
||||
#ifdef CONFIG_SMP
|
||||
int f_sb_list_cpu;
|
||||
#endif
|
||||
@ -2401,8 +2407,8 @@ file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping);
|
||||
extern loff_t noop_llseek(struct file *file, loff_t offset, int origin);
|
||||
extern loff_t no_llseek(struct file *file, loff_t offset, int origin);
|
||||
extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin);
|
||||
extern loff_t generic_file_llseek_unlocked(struct file *file, loff_t offset,
|
||||
int origin);
|
||||
extern loff_t generic_file_llseek_size(struct file *file, loff_t offset,
|
||||
int origin, loff_t maxsize);
|
||||
extern int generic_file_open(struct inode * inode, struct file * filp);
|
||||
extern int nonseekable_open(struct inode * inode, struct file * filp);
|
||||
|
||||
|
@ -2115,6 +2115,7 @@ void iov_iter_advance(struct iov_iter *i, size_t bytes)
|
||||
} else {
|
||||
const struct iovec *iov = i->iov;
|
||||
size_t base = i->iov_offset;
|
||||
unsigned long nr_segs = i->nr_segs;
|
||||
|
||||
/*
|
||||
* The !iov->iov_len check ensures we skip over unlikely
|
||||
@ -2130,11 +2131,13 @@ void iov_iter_advance(struct iov_iter *i, size_t bytes)
|
||||
base += copy;
|
||||
if (iov->iov_len == base) {
|
||||
iov++;
|
||||
nr_segs--;
|
||||
base = 0;
|
||||
}
|
||||
}
|
||||
i->iov = iov;
|
||||
i->iov_offset = base;
|
||||
i->nr_segs = nr_segs;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(iov_iter_advance);
|
||||
|
Loading…
Reference in New Issue
Block a user