diff options
| -rw-r--r-- | fs/btrfs/file.c | 2 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.c | 2 | ||||
| -rw-r--r-- | fs/gfs2/file.c | 4 | ||||
| -rw-r--r-- | fs/nfs/file.c | 5 | ||||
| -rw-r--r-- | fs/read_write.c | 85 | ||||
| -rw-r--r-- | include/linux/fs.h | 9 |
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 | ||
| 729 | static int cifs_setlease(struct file *file, long arg, struct file_lock **lease) | 729 | static 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 | ||
| 38 | static 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 | */ |
| 47 | loff_t | 69 | loff_t |
| 48 | generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin) | 70 | generic_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 | } | ||
| 99 | EXPORT_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 | */ | ||
| 111 | loff_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 | } |
| 121 | EXPORT_SYMBOL(generic_file_llseek); | 118 | EXPORT_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); | |||
| 2398 | extern loff_t noop_llseek(struct file *file, loff_t offset, int origin); | 2403 | extern loff_t noop_llseek(struct file *file, loff_t offset, int origin); |
| 2399 | extern loff_t no_llseek(struct file *file, loff_t offset, int origin); | 2404 | extern loff_t no_llseek(struct file *file, loff_t offset, int origin); |
| 2400 | extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin); | 2405 | extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin); |
| 2401 | extern loff_t generic_file_llseek_unlocked(struct file *file, loff_t offset, | ||
| 2402 | int origin); | ||
| 2403 | extern int generic_file_open(struct inode * inode, struct file * filp); | 2406 | extern int generic_file_open(struct inode * inode, struct file * filp); |
| 2404 | extern int nonseekable_open(struct inode * inode, struct file * filp); | 2407 | extern int nonseekable_open(struct inode * inode, struct file * filp); |
| 2405 | 2408 | ||
