1
0
Fork 0

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)
hifive-unleashed-5.1
Linus Torvalds 2011-10-28 10:49:34 -07:00
commit f362f98e7c
22 changed files with 440 additions and 431 deletions

View File

@ -111,7 +111,8 @@ struct compat_statfs {
int f_bavail; int f_bavail;
compat_fsid_t f_fsid; compat_fsid_t f_fsid;
int f_namelen; int f_namelen;
int f_spare[6]; int f_flags;
int f_spare[5];
}; };
#define COMPAT_RLIM_INFINITY 0x7fffffffUL #define COMPAT_RLIM_INFINITY 0x7fffffffUL

View File

@ -105,7 +105,8 @@ struct compat_statfs {
__kernel_fsid_t f_fsid; __kernel_fsid_t f_fsid;
s32 f_namelen; s32 f_namelen;
s32 f_frsize; s32 f_frsize;
s32 f_spare[5]; s32 f_flags;
s32 f_spare[4];
}; };
struct compat_sigcontext { struct compat_sigcontext {

View File

@ -100,7 +100,8 @@ struct compat_statfs {
compat_fsid_t f_fsid; compat_fsid_t f_fsid;
int f_namelen; /* SunOS ignores this field. */ int f_namelen; /* SunOS ignores this field. */
int f_frsize; int f_frsize;
int f_spare[5]; int f_flags;
int f_spare[4];
}; };
#define COMPAT_RLIM_OLD_INFINITY 0x7fffffff #define COMPAT_RLIM_OLD_INFINITY 0x7fffffff

View File

@ -131,7 +131,8 @@ struct compat_statfs {
compat_fsid_t f_fsid; compat_fsid_t f_fsid;
s32 f_namelen; s32 f_namelen;
s32 f_frsize; s32 f_frsize;
s32 f_spare[6]; s32 f_flags;
s32 f_spare[5];
}; };
#define COMPAT_RLIM_OLD_INFINITY 0x7fffffff #define COMPAT_RLIM_OLD_INFINITY 0x7fffffff

View File

@ -134,7 +134,8 @@ struct compat_statfs {
compat_fsid_t f_fsid; compat_fsid_t f_fsid;
int f_namelen; /* SunOS ignores this field. */ int f_namelen; /* SunOS ignores this field. */
int f_frsize; int f_frsize;
int f_spare[5]; int f_flags;
int f_spare[4];
}; };
#define COMPAT_RLIM_INFINITY 0x7fffffff #define COMPAT_RLIM_INFINITY 0x7fffffff

View File

@ -108,7 +108,8 @@ struct compat_statfs {
compat_fsid_t f_fsid; compat_fsid_t f_fsid;
int f_namelen; /* SunOS ignores this field. */ int f_namelen; /* SunOS ignores this field. */
int f_frsize; int f_frsize;
int f_spare[5]; int f_flags;
int f_spare[4];
}; };
#define COMPAT_RLIM_OLD_INFINITY 0x7fffffff #define COMPAT_RLIM_OLD_INFINITY 0x7fffffff

View File

@ -1821,7 +1821,7 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int origin)
switch (origin) { switch (origin) {
case SEEK_END: case SEEK_END:
case SEEK_CUR: case SEEK_CUR:
offset = generic_file_llseek_unlocked(file, offset, origin); offset = generic_file_llseek(file, offset, origin);
goto out; goto out;
case SEEK_DATA: case SEEK_DATA:
case SEEK_HOLE: case SEEK_HOLE:

View File

@ -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 * @page: the page which is affected
* @offset: the index of the truncation point * @offset: the index of the truncation point
* *
* block_invalidatepage() is called when all or part of the page has become * 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 * 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 * ensure that no dirty buffer is left outside @offset and that no I/O

View File

@ -730,7 +730,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
if (rc < 0) if (rc < 0)
return (loff_t)rc; 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) static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)

View File

@ -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[0], &ubuf->f_fsid.val[0]) ||
__put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) || __put_user(kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]) ||
__put_user(kbuf->f_frsize, &ubuf->f_frsize) || __put_user(kbuf->f_frsize, &ubuf->f_frsize) ||
__put_user(0, &ubuf->f_spare[0]) || __put_user(kbuf->f_flags, &ubuf->f_flags) ||
__put_user(0, &ubuf->f_spare[1]) || __clear_user(ubuf->f_spare, sizeof(ubuf->f_spare)))
__put_user(0, &ubuf->f_spare[2]) ||
__put_user(0, &ubuf->f_spare[3]) ||
__put_user(0, &ubuf->f_spare[4]))
return -EFAULT; return -EFAULT;
return 0; return 0;
} }

File diff suppressed because it is too large Load Diff

View File

@ -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; maxbytes = EXT4_SB(inode->i_sb)->s_bitmap_maxbytes;
else else
maxbytes = inode->i_sb->s_maxbytes; 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) { return generic_file_llseek_size(file, offset, origin, 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;
} }
const struct file_operations ext4_file_operations = { const struct file_operations ext4_file_operations = {

View File

@ -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, error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY,
&i_gh); &i_gh);
if (!error) { if (!error) {
error = generic_file_llseek_unlocked(file, offset, origin); error = generic_file_llseek(file, offset, origin);
gfs2_glock_dq_uninit(&i_gh); gfs2_glock_dq_uninit(&i_gh);
} }
break; break;
case SEEK_CUR: case SEEK_CUR:
case SEEK_SET: case SEEK_SET:
error = generic_file_llseek_unlocked(file, offset, origin); error = generic_file_llseek(file, offset, origin);
break; break;
default: default:
error = -EINVAL; error = -EINVAL;

View File

@ -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. * inode to the back of the list so we don't spin on it.
*/ */
if (!spin_trylock(&inode->i_lock)) { 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; continue;
} }

View File

@ -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) static int acl_permission_check(struct inode *inode, int mask)
{ {
unsigned int mode = inode->i_mode; unsigned int mode = inode->i_mode;
mask &= MAY_READ | MAY_WRITE | MAY_EXEC | MAY_NOT_BLOCK;
if (current_user_ns() != inode_userns(inode)) if (current_user_ns() != inode_userns(inode))
goto other_perms; goto other_perms;
@ -257,7 +255,7 @@ other_perms:
/** /**
* generic_permission - check for access rights on a Posix-like filesystem * generic_permission - check for access rights on a Posix-like filesystem
* @inode: inode to check access rights for * @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. * Used to check for read/write/execute permissions on a file.
* We use "fsuid" for this, letting us set arbitrary permissions * We use "fsuid" for this, letting us set arbitrary permissions
@ -273,7 +271,7 @@ int generic_permission(struct inode *inode, int mask)
int ret; int ret;
/* /*
* Do the basic POSIX ACL permission checks. * Do the basic permission checks.
*/ */
ret = acl_permission_check(inode, mask); ret = acl_permission_check(inode, mask);
if (ret != -EACCES) 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_permission - check for access rights to a given inode
* @inode: inode to check permission on * @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. * Used to check for read/write/execute permissions on an inode.
* We use "fsuid" for this, letting us set arbitrary permissions * We use "fsuid" for this, letting us set arbitrary permissions
* for filesystem access without changing the "normal" uids which * for filesystem access without changing the "normal" uids which
* are used for other things. * 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) 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)) if (flag & O_NOATIME && !inode_owner_or_capable(inode))
return -EPERM; return -EPERM;
/* return 0;
* Ensure there are no outstanding leases on the file.
*/
return break_lease(inode, flag);
} }
static int handle_truncate(struct file *filp) static int handle_truncate(struct file *filp)

View File

@ -1109,6 +1109,7 @@ static int show_vfsstat(struct seq_file *m, void *v)
/* device */ /* device */
if (mnt->mnt_sb->s_op->show_devname) { if (mnt->mnt_sb->s_op->show_devname) {
seq_puts(m, "device ");
err = mnt->mnt_sb->s_op->show_devname(m, mnt); err = mnt->mnt_sb->s_op->show_devname(m, mnt);
} else { } else {
if (mnt->mnt_devname) { if (mnt->mnt_devname) {

View File

@ -180,8 +180,6 @@ force_reval:
static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) 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", dprintk("NFS: llseek file(%s/%s, %lld, %d)\n",
filp->f_path.dentry->d_parent->d_name.name, filp->f_path.dentry->d_parent->d_name.name,
filp->f_path.dentry->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); int retval = nfs_revalidate_file_size(inode, filp);
if (retval < 0) if (retval < 0)
return (loff_t)retval; return (loff_t)retval;
}
spin_lock(&inode->i_lock); return generic_file_llseek(filp, offset, origin);
loff = generic_file_llseek_unlocked(filp, offset, origin);
spin_unlock(&inode->i_lock);
} else
loff = generic_file_llseek_unlocked(filp, offset, origin);
return loff;
} }
/* /*

View File

@ -685,6 +685,10 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
if (error) if (error)
goto cleanup_all; goto cleanup_all;
error = break_lease(inode, f->f_flags);
if (error)
goto cleanup_all;
if (!open && f->f_op) if (!open && f->f_op)
open = f->f_op->open; open = f->f_op->open;
if (open) { if (open) {

View File

@ -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; const struct posix_acl_entry *pa, *pe, *mask_obj;
int found = 0; int found = 0;
want &= MAY_READ | MAY_WRITE | MAY_EXEC | MAY_NOT_BLOCK;
FOREACH_ACL_ENTRY(pa, acl, pe) { FOREACH_ACL_ENTRY(pa, acl, pe) {
switch(pa->e_tag) { switch(pa->e_tag) {
case ACL_USER_OBJ: case ACL_USER_OBJ:

View File

@ -35,23 +35,45 @@ static inline int unsigned_offsets(struct file *file)
return file->f_mode & FMODE_UNSIGNED_OFFSET; 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 * @file: file structure to seek on
* @offset: file offset to seek to * @offset: file offset to seek to
* @origin: type of seek * @origin: type of seek
* @size: max size of file system
* *
* Updates the file offset to the value specified by @offset and @origin. * This is a variant of generic_file_llseek that allows passing in a custom
* Locking must be provided by the caller. * 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 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; struct inode *inode = file->f_mapping->host;
switch (origin) { switch (origin) {
case SEEK_END: case SEEK_END:
offset += inode->i_size; offset += i_size_read(inode);
break; break;
case SEEK_CUR: case SEEK_CUR:
/* /*
@ -62,14 +84,22 @@ generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin)
*/ */
if (offset == 0) if (offset == 0)
return file->f_pos; 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: case SEEK_DATA:
/* /*
* In the generic case the entire file is data, so as long as * 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. * 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; return -ENXIO;
break; break;
case SEEK_HOLE: 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 * 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. * offset isn't i_size or larger, return i_size.
*/ */
if (offset >= inode->i_size) if (offset >= i_size_read(inode))
return -ENXIO; return -ENXIO;
offset = inode->i_size; offset = i_size_read(inode);
break; break;
} }
if (offset < 0 && !unsigned_offsets(file)) return lseek_execute(file, inode, offset, maxsize);
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;
} }
EXPORT_SYMBOL(generic_file_llseek_unlocked); EXPORT_SYMBOL(generic_file_llseek_size);
/** /**
* generic_file_llseek - generic llseek implementation for regular files * 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 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); return generic_file_llseek_size(file, offset, origin,
rval = generic_file_llseek_unlocked(file, offset, origin); inode->i_sb->s_maxbytes);
mutex_unlock(&file->f_dentry->d_inode->i_mutex);
return rval;
} }
EXPORT_SYMBOL(generic_file_llseek); EXPORT_SYMBOL(generic_file_llseek);

View File

@ -58,14 +58,15 @@ struct inodes_stat_t {
#define NR_FILE 8192 /* this can well be larger on a larger system */ #define NR_FILE 8192 /* this can well be larger on a larger system */
#define MAY_EXEC 1 #define MAY_EXEC 0x00000001
#define MAY_WRITE 2 #define MAY_WRITE 0x00000002
#define MAY_READ 4 #define MAY_READ 0x00000004
#define MAY_APPEND 8 #define MAY_APPEND 0x00000008
#define MAY_ACCESS 16 #define MAY_ACCESS 0x00000010
#define MAY_OPEN 32 #define MAY_OPEN 0x00000020
#define MAY_CHDIR 64 #define MAY_CHDIR 0x00000040
#define MAY_NOT_BLOCK 128 /* called from RCU mode, don't block */ /* 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 * 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_dentry f_path.dentry
#define f_vfsmnt f_path.mnt #define f_vfsmnt f_path.mnt
const struct file_operations *f_op; 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 #ifdef CONFIG_SMP
int f_sb_list_cpu; int f_sb_list_cpu;
#endif #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 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 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(struct file *file, loff_t offset, int origin);
extern loff_t generic_file_llseek_unlocked(struct file *file, loff_t offset, extern loff_t generic_file_llseek_size(struct file *file, loff_t offset,
int origin); int origin, loff_t maxsize);
extern int generic_file_open(struct inode * inode, struct file * filp); extern int generic_file_open(struct inode * inode, struct file * filp);
extern int nonseekable_open(struct inode * inode, struct file * filp); extern int nonseekable_open(struct inode * inode, struct file * filp);

View File

@ -2115,6 +2115,7 @@ void iov_iter_advance(struct iov_iter *i, size_t bytes)
} else { } else {
const struct iovec *iov = i->iov; const struct iovec *iov = i->iov;
size_t base = i->iov_offset; size_t base = i->iov_offset;
unsigned long nr_segs = i->nr_segs;
/* /*
* The !iov->iov_len check ensures we skip over unlikely * 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; base += copy;
if (iov->iov_len == base) { if (iov->iov_len == base) {
iov++; iov++;
nr_segs--;
base = 0; base = 0;
} }
} }
i->iov = iov; i->iov = iov;
i->iov_offset = base; i->iov_offset = base;
i->nr_segs = nr_segs;
} }
} }
EXPORT_SYMBOL(iov_iter_advance); EXPORT_SYMBOL(iov_iter_advance);