diff options
author | Jeff Layton <jlayton@redhat.com> | 2010-10-15 15:33:56 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2010-10-17 20:34:29 -0400 |
commit | 608712fe8609492a8670638ea86b97fafe49ebba (patch) | |
tree | b175e2ac5e71ab8d6541a82d496d5dc6cc812acf /fs | |
parent | 2f4f26fcf393ef4a44abe10e79c1966e64e86055 (diff) |
cifs: fix flags handling in cifs_posix_open
The way flags are passed and converted for cifs_posix_open is rather
non-sensical. Some callers call cifs_posix_convert_flags on the flags
before they pass them to cifs_posix_open, whereas some don't. Two flag
conversion steps is just confusing though.
Change the function instead to clearly expect input in f_flags format,
and fix the callers to pass that in. Then, have cifs_posix_open call
cifs_convert_posix_flags to do the conversion. Move cifs_posix_open to
file.c as well so we can keep cifs_convert_posix_flags as a static
function.
Fix it also to not ignore O_CREAT, O_EXCL and O_TRUNC, and instead have
cifs_reopen_file mask those bits off before calling cifs_posix_open.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Reviewed-by: Suresh Jayaraman <sjayaraman@suse.de>
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cifs/cifsproto.h | 2 | ||||
-rw-r--r-- | fs/cifs/dir.c | 99 | ||||
-rw-r--r-- | fs/cifs/file.c | 113 |
3 files changed, 95 insertions, 119 deletions
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 7f416abd34cf..4f7edbaf0118 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -111,7 +111,7 @@ extern struct cifsFileInfo *cifs_new_fileinfo(struct inode *newinode, | |||
111 | unsigned int oflags, __u32 oplock); | 111 | unsigned int oflags, __u32 oplock); |
112 | extern int cifs_posix_open(char *full_path, struct inode **pinode, | 112 | extern int cifs_posix_open(char *full_path, struct inode **pinode, |
113 | struct super_block *sb, | 113 | struct super_block *sb, |
114 | int mode, int oflags, | 114 | int mode, unsigned int f_flags, |
115 | __u32 *poplock, __u16 *pnetfid, int xid); | 115 | __u32 *poplock, __u16 *pnetfid, int xid); |
116 | void cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr); | 116 | void cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr); |
117 | extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, | 117 | extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index c205ec9293ea..8c1af7128384 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -181,93 +181,6 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, struct file *file, | |||
181 | return pCifsFile; | 181 | return pCifsFile; |
182 | } | 182 | } |
183 | 183 | ||
184 | int cifs_posix_open(char *full_path, struct inode **pinode, | ||
185 | struct super_block *sb, int mode, int oflags, | ||
186 | __u32 *poplock, __u16 *pnetfid, int xid) | ||
187 | { | ||
188 | int rc; | ||
189 | FILE_UNIX_BASIC_INFO *presp_data; | ||
190 | __u32 posix_flags = 0; | ||
191 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | ||
192 | struct cifs_fattr fattr; | ||
193 | struct tcon_link *tlink; | ||
194 | struct cifsTconInfo *tcon; | ||
195 | |||
196 | cFYI(1, "posix open %s", full_path); | ||
197 | |||
198 | presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); | ||
199 | if (presp_data == NULL) | ||
200 | return -ENOMEM; | ||
201 | |||
202 | /* So far cifs posix extensions can only map the following flags. | ||
203 | There are other valid fmode oflags such as FMODE_LSEEK, FMODE_PREAD, but | ||
204 | so far we do not seem to need them, and we can treat them as local only */ | ||
205 | if ((oflags & (FMODE_READ | FMODE_WRITE)) == | ||
206 | (FMODE_READ | FMODE_WRITE)) | ||
207 | posix_flags = SMB_O_RDWR; | ||
208 | else if (oflags & FMODE_READ) | ||
209 | posix_flags = SMB_O_RDONLY; | ||
210 | else if (oflags & FMODE_WRITE) | ||
211 | posix_flags = SMB_O_WRONLY; | ||
212 | if (oflags & O_CREAT) | ||
213 | posix_flags |= SMB_O_CREAT; | ||
214 | if (oflags & O_EXCL) | ||
215 | posix_flags |= SMB_O_EXCL; | ||
216 | if (oflags & O_TRUNC) | ||
217 | posix_flags |= SMB_O_TRUNC; | ||
218 | /* be safe and imply O_SYNC for O_DSYNC */ | ||
219 | if (oflags & O_DSYNC) | ||
220 | posix_flags |= SMB_O_SYNC; | ||
221 | if (oflags & O_DIRECTORY) | ||
222 | posix_flags |= SMB_O_DIRECTORY; | ||
223 | if (oflags & O_NOFOLLOW) | ||
224 | posix_flags |= SMB_O_NOFOLLOW; | ||
225 | if (oflags & O_DIRECT) | ||
226 | posix_flags |= SMB_O_DIRECT; | ||
227 | |||
228 | mode &= ~current_umask(); | ||
229 | |||
230 | tlink = cifs_sb_tlink(cifs_sb); | ||
231 | if (IS_ERR(tlink)) { | ||
232 | rc = PTR_ERR(tlink); | ||
233 | goto posix_open_ret; | ||
234 | } | ||
235 | |||
236 | tcon = tlink_tcon(tlink); | ||
237 | rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data, | ||
238 | poplock, full_path, cifs_sb->local_nls, | ||
239 | cifs_sb->mnt_cifs_flags & | ||
240 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
241 | cifs_put_tlink(tlink); | ||
242 | |||
243 | if (rc) | ||
244 | goto posix_open_ret; | ||
245 | |||
246 | if (presp_data->Type == cpu_to_le32(-1)) | ||
247 | goto posix_open_ret; /* open ok, caller does qpathinfo */ | ||
248 | |||
249 | if (!pinode) | ||
250 | goto posix_open_ret; /* caller does not need info */ | ||
251 | |||
252 | cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb); | ||
253 | |||
254 | /* get new inode and set it up */ | ||
255 | if (*pinode == NULL) { | ||
256 | cifs_fill_uniqueid(sb, &fattr); | ||
257 | *pinode = cifs_iget(sb, &fattr); | ||
258 | if (!*pinode) { | ||
259 | rc = -ENOMEM; | ||
260 | goto posix_open_ret; | ||
261 | } | ||
262 | } else { | ||
263 | cifs_fattr_to_inode(*pinode, &fattr); | ||
264 | } | ||
265 | |||
266 | posix_open_ret: | ||
267 | kfree(presp_data); | ||
268 | return rc; | ||
269 | } | ||
270 | |||
271 | static void setup_cifs_dentry(struct cifsTconInfo *tcon, | 184 | static void setup_cifs_dentry(struct cifsTconInfo *tcon, |
272 | struct dentry *direntry, | 185 | struct dentry *direntry, |
273 | struct inode *newinode) | 186 | struct inode *newinode) |
@@ -321,9 +234,9 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
321 | oplock = REQ_OPLOCK; | 234 | oplock = REQ_OPLOCK; |
322 | 235 | ||
323 | if (nd && (nd->flags & LOOKUP_OPEN)) | 236 | if (nd && (nd->flags & LOOKUP_OPEN)) |
324 | oflags = nd->intent.open.flags; | 237 | oflags = nd->intent.open.file->f_flags; |
325 | else | 238 | else |
326 | oflags = FMODE_READ | SMB_O_CREAT; | 239 | oflags = O_RDONLY | O_CREAT; |
327 | 240 | ||
328 | full_path = build_path_from_dentry(direntry); | 241 | full_path = build_path_from_dentry(direntry); |
329 | if (full_path == NULL) { | 242 | if (full_path == NULL) { |
@@ -359,9 +272,9 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
359 | /* if the file is going to stay open, then we | 272 | /* if the file is going to stay open, then we |
360 | need to set the desired access properly */ | 273 | need to set the desired access properly */ |
361 | desiredAccess = 0; | 274 | desiredAccess = 0; |
362 | if (oflags & FMODE_READ) | 275 | if (OPEN_FMODE(oflags) & FMODE_READ) |
363 | desiredAccess |= GENERIC_READ; /* is this too little? */ | 276 | desiredAccess |= GENERIC_READ; /* is this too little? */ |
364 | if (oflags & FMODE_WRITE) | 277 | if (OPEN_FMODE(oflags) & FMODE_WRITE) |
365 | desiredAccess |= GENERIC_WRITE; | 278 | desiredAccess |= GENERIC_WRITE; |
366 | 279 | ||
367 | if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) | 280 | if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) |
@@ -716,11 +629,11 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
716 | if (pTcon->unix_ext) { | 629 | if (pTcon->unix_ext) { |
717 | if (nd && !(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && | 630 | if (nd && !(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && |
718 | (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open && | 631 | (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open && |
719 | (nd->intent.open.flags & O_CREAT)) { | 632 | (nd->intent.open.file->f_flags & O_CREAT)) { |
720 | rc = cifs_posix_open(full_path, &newInode, | 633 | rc = cifs_posix_open(full_path, &newInode, |
721 | parent_dir_inode->i_sb, | 634 | parent_dir_inode->i_sb, |
722 | nd->intent.open.create_mode, | 635 | nd->intent.open.create_mode, |
723 | nd->intent.open.flags, &oplock, | 636 | nd->intent.open.file->f_flags, &oplock, |
724 | &fileHandle, xid); | 637 | &fileHandle, xid); |
725 | /* | 638 | /* |
726 | * The check below works around a bug in POSIX | 639 | * The check below works around a bug in POSIX |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index c10f0851cd21..b1ca6a43ac1a 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -60,34 +60,32 @@ static inline int cifs_convert_flags(unsigned int flags) | |||
60 | FILE_READ_DATA); | 60 | FILE_READ_DATA); |
61 | } | 61 | } |
62 | 62 | ||
63 | static inline fmode_t cifs_posix_convert_flags(unsigned int flags) | 63 | static u32 cifs_posix_convert_flags(unsigned int flags) |
64 | { | 64 | { |
65 | fmode_t posix_flags = 0; | 65 | u32 posix_flags = 0; |
66 | 66 | ||
67 | if ((flags & O_ACCMODE) == O_RDONLY) | 67 | if ((flags & O_ACCMODE) == O_RDONLY) |
68 | posix_flags = FMODE_READ; | 68 | posix_flags = SMB_O_RDONLY; |
69 | else if ((flags & O_ACCMODE) == O_WRONLY) | 69 | else if ((flags & O_ACCMODE) == O_WRONLY) |
70 | posix_flags = FMODE_WRITE; | 70 | posix_flags = SMB_O_WRONLY; |
71 | else if ((flags & O_ACCMODE) == O_RDWR) { | 71 | else if ((flags & O_ACCMODE) == O_RDWR) |
72 | /* GENERIC_ALL is too much permission to request | 72 | posix_flags = SMB_O_RDWR; |
73 | can cause unnecessary access denied on create */ | 73 | |
74 | /* return GENERIC_ALL; */ | 74 | if (flags & O_CREAT) |
75 | posix_flags = FMODE_READ | FMODE_WRITE; | 75 | posix_flags |= SMB_O_CREAT; |
76 | } | 76 | if (flags & O_EXCL) |
77 | /* can not map O_CREAT or O_EXCL or O_TRUNC flags when | 77 | posix_flags |= SMB_O_EXCL; |
78 | reopening a file. They had their effect on the original open */ | 78 | if (flags & O_TRUNC) |
79 | if (flags & O_APPEND) | 79 | posix_flags |= SMB_O_TRUNC; |
80 | posix_flags |= (fmode_t)O_APPEND; | 80 | /* be safe and imply O_SYNC for O_DSYNC */ |
81 | if (flags & O_DSYNC) | 81 | if (flags & O_DSYNC) |
82 | posix_flags |= (fmode_t)O_DSYNC; | 82 | posix_flags |= SMB_O_SYNC; |
83 | if (flags & __O_SYNC) | ||
84 | posix_flags |= (fmode_t)__O_SYNC; | ||
85 | if (flags & O_DIRECTORY) | 83 | if (flags & O_DIRECTORY) |
86 | posix_flags |= (fmode_t)O_DIRECTORY; | 84 | posix_flags |= SMB_O_DIRECTORY; |
87 | if (flags & O_NOFOLLOW) | 85 | if (flags & O_NOFOLLOW) |
88 | posix_flags |= (fmode_t)O_NOFOLLOW; | 86 | posix_flags |= SMB_O_NOFOLLOW; |
89 | if (flags & O_DIRECT) | 87 | if (flags & O_DIRECT) |
90 | posix_flags |= (fmode_t)O_DIRECT; | 88 | posix_flags |= SMB_O_DIRECT; |
91 | 89 | ||
92 | return posix_flags; | 90 | return posix_flags; |
93 | } | 91 | } |
@@ -159,6 +157,68 @@ client_can_cache: | |||
159 | return rc; | 157 | return rc; |
160 | } | 158 | } |
161 | 159 | ||
160 | int cifs_posix_open(char *full_path, struct inode **pinode, | ||
161 | struct super_block *sb, int mode, unsigned int f_flags, | ||
162 | __u32 *poplock, __u16 *pnetfid, int xid) | ||
163 | { | ||
164 | int rc; | ||
165 | FILE_UNIX_BASIC_INFO *presp_data; | ||
166 | __u32 posix_flags = 0; | ||
167 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | ||
168 | struct cifs_fattr fattr; | ||
169 | struct tcon_link *tlink; | ||
170 | struct cifsTconInfo *tcon; | ||
171 | |||
172 | cFYI(1, "posix open %s", full_path); | ||
173 | |||
174 | presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL); | ||
175 | if (presp_data == NULL) | ||
176 | return -ENOMEM; | ||
177 | |||
178 | tlink = cifs_sb_tlink(cifs_sb); | ||
179 | if (IS_ERR(tlink)) { | ||
180 | rc = PTR_ERR(tlink); | ||
181 | goto posix_open_ret; | ||
182 | } | ||
183 | |||
184 | tcon = tlink_tcon(tlink); | ||
185 | mode &= ~current_umask(); | ||
186 | |||
187 | posix_flags = cifs_posix_convert_flags(f_flags); | ||
188 | rc = CIFSPOSIXCreate(xid, tcon, posix_flags, mode, pnetfid, presp_data, | ||
189 | poplock, full_path, cifs_sb->local_nls, | ||
190 | cifs_sb->mnt_cifs_flags & | ||
191 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
192 | cifs_put_tlink(tlink); | ||
193 | |||
194 | if (rc) | ||
195 | goto posix_open_ret; | ||
196 | |||
197 | if (presp_data->Type == cpu_to_le32(-1)) | ||
198 | goto posix_open_ret; /* open ok, caller does qpathinfo */ | ||
199 | |||
200 | if (!pinode) | ||
201 | goto posix_open_ret; /* caller does not need info */ | ||
202 | |||
203 | cifs_unix_basic_to_fattr(&fattr, presp_data, cifs_sb); | ||
204 | |||
205 | /* get new inode and set it up */ | ||
206 | if (*pinode == NULL) { | ||
207 | cifs_fill_uniqueid(sb, &fattr); | ||
208 | *pinode = cifs_iget(sb, &fattr); | ||
209 | if (!*pinode) { | ||
210 | rc = -ENOMEM; | ||
211 | goto posix_open_ret; | ||
212 | } | ||
213 | } else { | ||
214 | cifs_fattr_to_inode(*pinode, &fattr); | ||
215 | } | ||
216 | |||
217 | posix_open_ret: | ||
218 | kfree(presp_data); | ||
219 | return rc; | ||
220 | } | ||
221 | |||
162 | int cifs_open(struct inode *inode, struct file *file) | 222 | int cifs_open(struct inode *inode, struct file *file) |
163 | { | 223 | { |
164 | int rc = -EACCES; | 224 | int rc = -EACCES; |
@@ -205,12 +265,10 @@ int cifs_open(struct inode *inode, struct file *file) | |||
205 | (tcon->ses->capabilities & CAP_UNIX) && | 265 | (tcon->ses->capabilities & CAP_UNIX) && |
206 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & | 266 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & |
207 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | 267 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { |
208 | int oflags = (int) cifs_posix_convert_flags(file->f_flags); | ||
209 | oflags |= SMB_O_CREAT; | ||
210 | /* can not refresh inode info since size could be stale */ | 268 | /* can not refresh inode info since size could be stale */ |
211 | rc = cifs_posix_open(full_path, &inode, inode->i_sb, | 269 | rc = cifs_posix_open(full_path, &inode, inode->i_sb, |
212 | cifs_sb->mnt_file_mode /* ignored */, | 270 | cifs_sb->mnt_file_mode /* ignored */, |
213 | oflags, &oplock, &netfid, xid); | 271 | file->f_flags, &oplock, &netfid, xid); |
214 | if (rc == 0) { | 272 | if (rc == 0) { |
215 | cFYI(1, "posix open succeeded"); | 273 | cFYI(1, "posix open succeeded"); |
216 | 274 | ||
@@ -426,8 +484,13 @@ reopen_error_exit: | |||
426 | if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && | 484 | if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && |
427 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & | 485 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & |
428 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | 486 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { |
429 | int oflags = (int) cifs_posix_convert_flags(file->f_flags); | 487 | |
430 | /* can not refresh inode info since size could be stale */ | 488 | /* |
489 | * O_CREAT, O_EXCL and O_TRUNC already had their effect on the | ||
490 | * original open. Must mask them off for a reopen. | ||
491 | */ | ||
492 | unsigned int oflags = file->f_flags & ~(O_CREAT|O_EXCL|O_TRUNC); | ||
493 | |||
431 | rc = cifs_posix_open(full_path, NULL, inode->i_sb, | 494 | rc = cifs_posix_open(full_path, NULL, inode->i_sb, |
432 | cifs_sb->mnt_file_mode /* ignored */, | 495 | cifs_sb->mnt_file_mode /* ignored */, |
433 | oflags, &oplock, &netfid, xid); | 496 | oflags, &oplock, &netfid, xid); |