diff options
| -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); |
