Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 270030
b: refs/heads/master
c: ef3d0fd
h: refs/heads/master
v: v3
  • Loading branch information
Andi Kleen authored and root committed Oct 28, 2011
1 parent 020844c commit b949ccd
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 54 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 847cc6371ba820763773e993000410d6d8d23515
refs/heads/master: ef3d0fd27e90f67e35da516dafc1482c82939a60
2 changes: 1 addition & 1 deletion trunk/fs/btrfs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion trunk/fs/cifs/cifsfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,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)
Expand Down
4 changes: 2 additions & 2 deletions trunk/fs/gfs2/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ 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);
}
} else
error = generic_file_llseek_unlocked(file, offset, origin);
error = generic_file_llseek(file, offset, origin);

return error;
}
Expand Down
5 changes: 3 additions & 2 deletions trunk/fs/nfs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,11 +198,12 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
if (retval < 0)
return (loff_t)retval;

/* AK: should drop this lock. Unlikely to be needed. */
spin_lock(&inode->i_lock);
loff = generic_file_llseek_unlocked(filp, offset, origin);
loff = generic_file_llseek(filp, offset, origin);
spin_unlock(&inode->i_lock);
} else
loff = generic_file_llseek_unlocked(filp, offset, origin);
loff = generic_file_llseek(filp, offset, origin);
return loff;
}

Expand Down
85 changes: 41 additions & 44 deletions trunk/fs/read_write.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 - generic llseek implementation for regular files
* @file: file structure to seek on
* @offset: file offset to seek to
* @origin: type of seek
*
* Updates the file offset to the value specified by @offset and @origin.
* Locking must be provided by the caller.
* This is a generic implemenation of ->llseek usable for all normal local
* filesystems. It just updates the file offset to the value specified by
* @offset and @origin under i_mutex.
*
* Synchronization:
* SEEK_SET is 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.
* SEEK_END
*/
loff_t
generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin)
generic_file_llseek(struct file *file, loff_t offset, int origin)
{
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:
/*
Expand All @@ -62,61 +84,36 @@ 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,
inode->i_sb->s_maxbytes);
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:
/*
* 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;
}
EXPORT_SYMBOL(generic_file_llseek_unlocked);

/**
* generic_file_llseek - generic llseek implementation for regular files
* @file: file structure to seek on
* @offset: file offset to seek to
* @origin: type of seek
*
* This is a generic implemenation of ->llseek useable for all normal local
* filesystems. It just updates the file offset to the value specified by
* @offset and @origin under i_mutex.
*/
loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
{
loff_t rval;

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 lseek_execute(file, inode, offset, inode->i_sb->s_maxbytes);
}
EXPORT_SYMBOL(generic_file_llseek);

Expand Down
9 changes: 6 additions & 3 deletions trunk/include/linux/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -964,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
Expand Down Expand Up @@ -2398,8 +2403,6 @@ 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 int generic_file_open(struct inode * inode, struct file * filp);
extern int nonseekable_open(struct inode * inode, struct file * filp);

Expand Down

0 comments on commit b949ccd

Please sign in to comment.