aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/file.c2
-rw-r--r--fs/cifs/cifsfs.c2
-rw-r--r--fs/gfs2/file.c4
-rw-r--r--fs/nfs/file.c5
-rw-r--r--fs/read_write.c85
-rw-r--r--include/linux/fs.h9
6 files changed, 54 insertions, 53 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index e4e57d59edb7..1266f6e9cdb2 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1821,7 +1821,7 @@ static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int origin)
1821 switch (origin) { 1821 switch (origin) {
1822 case SEEK_END: 1822 case SEEK_END:
1823 case SEEK_CUR: 1823 case SEEK_CUR:
1824 offset = generic_file_llseek_unlocked(file, offset, origin); 1824 offset = generic_file_llseek(file, offset, origin);
1825 goto out; 1825 goto out;
1826 case SEEK_DATA: 1826 case SEEK_DATA:
1827 case SEEK_HOLE: 1827 case SEEK_HOLE:
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 54b8f1e7da94..db7ce87d37a5 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -723,7 +723,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
723 if (rc < 0) 723 if (rc < 0)
724 return (loff_t)rc; 724 return (loff_t)rc;
725 } 725 }
726 return generic_file_llseek_unlocked(file, offset, origin); 726 return generic_file_llseek(file, offset, origin);
727} 727}
728 728
729static int cifs_setlease(struct file *file, long arg, struct file_lock **lease) 729static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index edeb9e802903..fe6bc0207818 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -63,11 +63,11 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin)
63 error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, 63 error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY,
64 &i_gh); 64 &i_gh);
65 if (!error) { 65 if (!error) {
66 error = generic_file_llseek_unlocked(file, offset, origin); 66 error = generic_file_llseek(file, offset, origin);
67 gfs2_glock_dq_uninit(&i_gh); 67 gfs2_glock_dq_uninit(&i_gh);
68 } 68 }
69 } else 69 } else
70 error = generic_file_llseek_unlocked(file, offset, origin); 70 error = generic_file_llseek(file, offset, origin);
71 71
72 return error; 72 return error;
73} 73}
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 28b8c3f3cda3..12623abcf3d4 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -198,11 +198,12 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin)
198 if (retval < 0) 198 if (retval < 0)
199 return (loff_t)retval; 199 return (loff_t)retval;
200 200
201 /* AK: should drop this lock. Unlikely to be needed. */
201 spin_lock(&inode->i_lock); 202 spin_lock(&inode->i_lock);
202 loff = generic_file_llseek_unlocked(filp, offset, origin); 203 loff = generic_file_llseek(filp, offset, origin);
203 spin_unlock(&inode->i_lock); 204 spin_unlock(&inode->i_lock);
204 } else 205 } else
205 loff = generic_file_llseek_unlocked(filp, offset, origin); 206 loff = generic_file_llseek(filp, offset, origin);
206 return loff; 207 return loff;
207} 208}
208 209
diff --git a/fs/read_write.c b/fs/read_write.c
index 179f1c33ea57..672b187def62 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -35,23 +35,45 @@ static inline int unsigned_offsets(struct file *file)
35 return file->f_mode & FMODE_UNSIGNED_OFFSET; 35 return file->f_mode & FMODE_UNSIGNED_OFFSET;
36} 36}
37 37
38static loff_t lseek_execute(struct file *file, struct inode *inode,
39 loff_t offset, loff_t maxsize)
40{
41 if (offset < 0 && !unsigned_offsets(file))
42 return -EINVAL;
43 if (offset > maxsize)
44 return -EINVAL;
45
46 if (offset != file->f_pos) {
47 file->f_pos = offset;
48 file->f_version = 0;
49 }
50 return offset;
51}
52
38/** 53/**
39 * generic_file_llseek_unlocked - lockless generic llseek implementation 54 * generic_file_llseek - generic llseek implementation for regular files
40 * @file: file structure to seek on 55 * @file: file structure to seek on
41 * @offset: file offset to seek to 56 * @offset: file offset to seek to
42 * @origin: type of seek 57 * @origin: type of seek
43 * 58 *
44 * Updates the file offset to the value specified by @offset and @origin. 59 * This is a generic implemenation of ->llseek usable for all normal local
45 * Locking must be provided by the caller. 60 * filesystems. It just updates the file offset to the value specified by
61 * @offset and @origin under i_mutex.
62 *
63 * Synchronization:
64 * SEEK_SET is unsynchronized (but atomic on 64bit platforms)
65 * SEEK_CUR is synchronized against other SEEK_CURs, but not read/writes.
66 * read/writes behave like SEEK_SET against seeks.
67 * SEEK_END
46 */ 68 */
47loff_t 69loff_t
48generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin) 70generic_file_llseek(struct file *file, loff_t offset, int origin)
49{ 71{
50 struct inode *inode = file->f_mapping->host; 72 struct inode *inode = file->f_mapping->host;
51 73
52 switch (origin) { 74 switch (origin) {
53 case SEEK_END: 75 case SEEK_END:
54 offset += inode->i_size; 76 offset += i_size_read(inode);
55 break; 77 break;
56 case SEEK_CUR: 78 case SEEK_CUR:
57 /* 79 /*
@@ -62,14 +84,22 @@ generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin)
62 */ 84 */
63 if (offset == 0) 85 if (offset == 0)
64 return file->f_pos; 86 return file->f_pos;
65 offset += file->f_pos; 87 /*
66 break; 88 * f_lock protects against read/modify/write race with other
89 * SEEK_CURs. Note that parallel writes and reads behave
90 * like SEEK_SET.
91 */
92 spin_lock(&file->f_lock);
93 offset = lseek_execute(file, inode, file->f_pos + offset,
94 inode->i_sb->s_maxbytes);
95 spin_unlock(&file->f_lock);
96 return offset;
67 case SEEK_DATA: 97 case SEEK_DATA:
68 /* 98 /*
69 * In the generic case the entire file is data, so as long as 99 * In the generic case the entire file is data, so as long as
70 * offset isn't at the end of the file then the offset is data. 100 * offset isn't at the end of the file then the offset is data.
71 */ 101 */
72 if (offset >= inode->i_size) 102 if (offset >= i_size_read(inode))
73 return -ENXIO; 103 return -ENXIO;
74 break; 104 break;
75 case SEEK_HOLE: 105 case SEEK_HOLE:
@@ -77,46 +107,13 @@ generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin)
77 * There is a virtual hole at the end of the file, so as long as 107 * There is a virtual hole at the end of the file, so as long as
78 * offset isn't i_size or larger, return i_size. 108 * offset isn't i_size or larger, return i_size.
79 */ 109 */
80 if (offset >= inode->i_size) 110 if (offset >= i_size_read(inode))
81 return -ENXIO; 111 return -ENXIO;
82 offset = inode->i_size; 112 offset = i_size_read(inode);
83 break; 113 break;
84 } 114 }
85 115
86 if (offset < 0 && !unsigned_offsets(file)) 116 return lseek_execute(file, inode, offset, inode->i_sb->s_maxbytes);
87 return -EINVAL;
88 if (offset > inode->i_sb->s_maxbytes)
89 return -EINVAL;
90
91 /* Special lock needed here? */
92 if (offset != file->f_pos) {
93 file->f_pos = offset;
94 file->f_version = 0;
95 }
96
97 return offset;
98}
99EXPORT_SYMBOL(generic_file_llseek_unlocked);
100
101/**
102 * generic_file_llseek - generic llseek implementation for regular files
103 * @file: file structure to seek on
104 * @offset: file offset to seek to
105 * @origin: type of seek
106 *
107 * This is a generic implemenation of ->llseek useable for all normal local
108 * filesystems. It just updates the file offset to the value specified by
109 * @offset and @origin under i_mutex.
110 */
111loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
112{
113 loff_t rval;
114
115 mutex_lock(&file->f_dentry->d_inode->i_mutex);
116 rval = generic_file_llseek_unlocked(file, offset, origin);
117 mutex_unlock(&file->f_dentry->d_inode->i_mutex);
118
119 return rval;
120} 117}
121EXPORT_SYMBOL(generic_file_llseek); 118EXPORT_SYMBOL(generic_file_llseek);
122 119
diff --git a/include/linux/fs.h b/include/linux/fs.h
index c1884e974ff4..db85196f6308 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -964,7 +964,12 @@ struct file {
964#define f_dentry f_path.dentry 964#define f_dentry f_path.dentry
965#define f_vfsmnt f_path.mnt 965#define f_vfsmnt f_path.mnt
966 const struct file_operations *f_op; 966 const struct file_operations *f_op;
967 spinlock_t f_lock; /* f_ep_links, f_flags, no IRQ */ 967
968 /*
969 * Protects f_ep_links, f_flags, f_pos vs i_size in lseek SEEK_CUR.
970 * Must not be taken from IRQ context.
971 */
972 spinlock_t f_lock;
968#ifdef CONFIG_SMP 973#ifdef CONFIG_SMP
969 int f_sb_list_cpu; 974 int f_sb_list_cpu;
970#endif 975#endif
@@ -2398,8 +2403,6 @@ file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping);
2398extern loff_t noop_llseek(struct file *file, loff_t offset, int origin); 2403extern loff_t noop_llseek(struct file *file, loff_t offset, int origin);
2399extern loff_t no_llseek(struct file *file, loff_t offset, int origin); 2404extern loff_t no_llseek(struct file *file, loff_t offset, int origin);
2400extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin); 2405extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin);
2401extern loff_t generic_file_llseek_unlocked(struct file *file, loff_t offset,
2402 int origin);
2403extern int generic_file_open(struct inode * inode, struct file * filp); 2406extern int generic_file_open(struct inode * inode, struct file * filp);
2404extern int nonseekable_open(struct inode * inode, struct file * filp); 2407extern int nonseekable_open(struct inode * inode, struct file * filp);
2405 2408