aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2010-10-15 15:33:56 -0400
committerSteve French <sfrench@us.ibm.com>2010-10-17 20:34:29 -0400
commit608712fe8609492a8670638ea86b97fafe49ebba (patch)
treeb175e2ac5e71ab8d6541a82d496d5dc6cc812acf /fs
parent2f4f26fcf393ef4a44abe10e79c1966e64e86055 (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.h2
-rw-r--r--fs/cifs/dir.c99
-rw-r--r--fs/cifs/file.c113
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);
112extern int cifs_posix_open(char *full_path, struct inode **pinode, 112extern 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);
116void cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr); 116void cifs_fill_uniqueid(struct super_block *sb, struct cifs_fattr *fattr);
117extern void cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, 117extern 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
184int 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
266posix_open_ret:
267 kfree(presp_data);
268 return rc;
269}
270
271static void setup_cifs_dentry(struct cifsTconInfo *tcon, 184static 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
63static inline fmode_t cifs_posix_convert_flags(unsigned int flags) 63static 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
160int 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
217posix_open_ret:
218 kfree(presp_data);
219 return rc;
220}
221
162int cifs_open(struct inode *inode, struct file *file) 222int 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);