diff options
author | Steve French <sfrench@us.ibm.com> | 2009-03-03 13:00:34 -0500 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2009-03-11 21:36:21 -0400 |
commit | 276a74a4835ad86d6da42f3a084b060afc5656e8 (patch) | |
tree | a2ef2452e2b0a24710b2298688e3beed4e353b5c /fs/cifs/file.c | |
parent | fcc7c09d94be7b75c9ea2beb22d0fae191c6b4b9 (diff) |
[CIFS] Use posix open on file open when server supports it
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/file.c')
-rw-r--r-- | fs/cifs/file.c | 124 |
1 files changed, 111 insertions, 13 deletions
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index e4ecb1cb0b13..7bef4cce572a 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -125,6 +125,80 @@ static inline int cifs_get_disposition(unsigned int flags) | |||
125 | } | 125 | } |
126 | 126 | ||
127 | /* all arguments to this function must be checked for validity in caller */ | 127 | /* all arguments to this function must be checked for validity in caller */ |
128 | static inline int cifs_posix_open_inode_helper(struct inode *inode, | ||
129 | struct file *file, struct cifsInodeInfo *pCifsInode, | ||
130 | struct cifsFileInfo *pCifsFile, int oplock, u16 netfid) | ||
131 | { | ||
132 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
133 | /* struct timespec temp; */ /* BB REMOVEME BB */ | ||
134 | |||
135 | file->private_data = kmalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | ||
136 | if (file->private_data == NULL) | ||
137 | return -ENOMEM; | ||
138 | pCifsFile = cifs_init_private(file->private_data, inode, file, netfid); | ||
139 | write_lock(&GlobalSMBSeslock); | ||
140 | list_add(&pCifsFile->tlist, &cifs_sb->tcon->openFileList); | ||
141 | |||
142 | pCifsInode = CIFS_I(file->f_path.dentry->d_inode); | ||
143 | if (pCifsInode == NULL) { | ||
144 | write_unlock(&GlobalSMBSeslock); | ||
145 | return -EINVAL; | ||
146 | } | ||
147 | |||
148 | /* want handles we can use to read with first | ||
149 | in the list so we do not have to walk the | ||
150 | list to search for one in write_begin */ | ||
151 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) { | ||
152 | list_add_tail(&pCifsFile->flist, | ||
153 | &pCifsInode->openFileList); | ||
154 | } else { | ||
155 | list_add(&pCifsFile->flist, | ||
156 | &pCifsInode->openFileList); | ||
157 | } | ||
158 | |||
159 | if (pCifsInode->clientCanCacheRead) { | ||
160 | /* we have the inode open somewhere else | ||
161 | no need to discard cache data */ | ||
162 | goto psx_client_can_cache; | ||
163 | } | ||
164 | |||
165 | /* BB FIXME need to fix this check to move it earlier into posix_open | ||
166 | BB fIX following section BB FIXME */ | ||
167 | |||
168 | /* if not oplocked, invalidate inode pages if mtime or file | ||
169 | size changed */ | ||
170 | /* temp = cifs_NTtimeToUnix(le64_to_cpu(buf->LastWriteTime)); | ||
171 | if (timespec_equal(&file->f_path.dentry->d_inode->i_mtime, &temp) && | ||
172 | (file->f_path.dentry->d_inode->i_size == | ||
173 | (loff_t)le64_to_cpu(buf->EndOfFile))) { | ||
174 | cFYI(1, ("inode unchanged on server")); | ||
175 | } else { | ||
176 | if (file->f_path.dentry->d_inode->i_mapping) { | ||
177 | rc = filemap_write_and_wait(file->f_path.dentry->d_inode->i_mapping); | ||
178 | if (rc != 0) | ||
179 | CIFS_I(file->f_path.dentry->d_inode)->write_behind_rc = rc; | ||
180 | } | ||
181 | cFYI(1, ("invalidating remote inode since open detected it " | ||
182 | "changed")); | ||
183 | invalidate_remote_inode(file->f_path.dentry->d_inode); | ||
184 | } */ | ||
185 | |||
186 | psx_client_can_cache: | ||
187 | if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) { | ||
188 | pCifsInode->clientCanCacheAll = true; | ||
189 | pCifsInode->clientCanCacheRead = true; | ||
190 | cFYI(1, ("Exclusive Oplock granted on inode %p", | ||
191 | file->f_path.dentry->d_inode)); | ||
192 | } else if ((oplock & 0xF) == OPLOCK_READ) | ||
193 | pCifsInode->clientCanCacheRead = true; | ||
194 | |||
195 | /* will have to change the unlock if we reenable the | ||
196 | filemap_fdatawrite (which does not seem necessary */ | ||
197 | write_unlock(&GlobalSMBSeslock); | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | /* all arguments to this function must be checked for validity in caller */ | ||
128 | static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, | 202 | static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, |
129 | struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile, | 203 | struct cifsInodeInfo *pCifsInode, struct cifsFileInfo *pCifsFile, |
130 | struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf, | 204 | struct cifsTconInfo *pTcon, int *oplock, FILE_ALL_INFO *buf, |
@@ -195,7 +269,7 @@ int cifs_open(struct inode *inode, struct file *file) | |||
195 | int rc = -EACCES; | 269 | int rc = -EACCES; |
196 | int xid, oplock; | 270 | int xid, oplock; |
197 | struct cifs_sb_info *cifs_sb; | 271 | struct cifs_sb_info *cifs_sb; |
198 | struct cifsTconInfo *pTcon; | 272 | struct cifsTconInfo *tcon; |
199 | struct cifsFileInfo *pCifsFile; | 273 | struct cifsFileInfo *pCifsFile; |
200 | struct cifsInodeInfo *pCifsInode; | 274 | struct cifsInodeInfo *pCifsInode; |
201 | struct list_head *tmp; | 275 | struct list_head *tmp; |
@@ -208,7 +282,7 @@ int cifs_open(struct inode *inode, struct file *file) | |||
208 | xid = GetXid(); | 282 | xid = GetXid(); |
209 | 283 | ||
210 | cifs_sb = CIFS_SB(inode->i_sb); | 284 | cifs_sb = CIFS_SB(inode->i_sb); |
211 | pTcon = cifs_sb->tcon; | 285 | tcon = cifs_sb->tcon; |
212 | 286 | ||
213 | if (file->f_flags & O_CREAT) { | 287 | if (file->f_flags & O_CREAT) { |
214 | /* search inode for this file and fill in file->private_data */ | 288 | /* search inode for this file and fill in file->private_data */ |
@@ -248,6 +322,35 @@ int cifs_open(struct inode *inode, struct file *file) | |||
248 | 322 | ||
249 | cFYI(1, ("inode = 0x%p file flags are 0x%x for %s", | 323 | cFYI(1, ("inode = 0x%p file flags are 0x%x for %s", |
250 | inode, file->f_flags, full_path)); | 324 | inode, file->f_flags, full_path)); |
325 | |||
326 | if (oplockEnabled) | ||
327 | oplock = REQ_OPLOCK; | ||
328 | else | ||
329 | oplock = 0; | ||
330 | |||
331 | if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) && | ||
332 | (CIFS_UNIX_POSIX_PATH_OPS_CAP & | ||
333 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | ||
334 | int oflags = (int) cifs_posix_convert_flags(file->f_flags); | ||
335 | /* can not refresh inode info since size could be stale */ | ||
336 | rc = cifs_posix_open(full_path, &inode, inode->i_sb, | ||
337 | cifs_sb->mnt_file_mode /* ignored */, | ||
338 | oflags, &oplock, &netfid, xid); | ||
339 | if (rc == 0) { | ||
340 | cFYI(1, ("posix open succeeded")); | ||
341 | /* no need for special case handling of setting mode | ||
342 | on read only files needed here */ | ||
343 | |||
344 | cifs_posix_open_inode_helper(inode, file, pCifsInode, | ||
345 | pCifsFile, oplock, netfid); | ||
346 | goto out; | ||
347 | } else if ((rc != -EIO) && (rc != -EREMOTE) && | ||
348 | (rc != -EOPNOTSUPP)) /* path not found or net err */ | ||
349 | goto out; | ||
350 | /* fallthrough to retry open the old way on operation | ||
351 | not supported or DFS errors */ | ||
352 | } | ||
353 | |||
251 | desiredAccess = cifs_convert_flags(file->f_flags); | 354 | desiredAccess = cifs_convert_flags(file->f_flags); |
252 | 355 | ||
253 | /********************************************************************* | 356 | /********************************************************************* |
@@ -276,11 +379,6 @@ int cifs_open(struct inode *inode, struct file *file) | |||
276 | 379 | ||
277 | disposition = cifs_get_disposition(file->f_flags); | 380 | disposition = cifs_get_disposition(file->f_flags); |
278 | 381 | ||
279 | if (oplockEnabled) | ||
280 | oplock = REQ_OPLOCK; | ||
281 | else | ||
282 | oplock = 0; | ||
283 | |||
284 | /* BB pass O_SYNC flag through on file attributes .. BB */ | 382 | /* BB pass O_SYNC flag through on file attributes .. BB */ |
285 | 383 | ||
286 | /* Also refresh inode by passing in file_info buf returned by SMBOpen | 384 | /* Also refresh inode by passing in file_info buf returned by SMBOpen |
@@ -297,7 +395,7 @@ int cifs_open(struct inode *inode, struct file *file) | |||
297 | } | 395 | } |
298 | 396 | ||
299 | if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) | 397 | if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) |
300 | rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, | 398 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, |
301 | desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, | 399 | desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, |
302 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | 400 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags |
303 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | 401 | & CIFS_MOUNT_MAP_SPECIAL_CHR); |
@@ -306,7 +404,7 @@ int cifs_open(struct inode *inode, struct file *file) | |||
306 | 404 | ||
307 | if (rc == -EIO) { | 405 | if (rc == -EIO) { |
308 | /* Old server, try legacy style OpenX */ | 406 | /* Old server, try legacy style OpenX */ |
309 | rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, | 407 | rc = SMBLegacyOpen(xid, tcon, full_path, disposition, |
310 | desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, | 408 | desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, |
311 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | 409 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags |
312 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | 410 | & CIFS_MOUNT_MAP_SPECIAL_CHR); |
@@ -323,12 +421,12 @@ int cifs_open(struct inode *inode, struct file *file) | |||
323 | } | 421 | } |
324 | pCifsFile = cifs_init_private(file->private_data, inode, file, netfid); | 422 | pCifsFile = cifs_init_private(file->private_data, inode, file, netfid); |
325 | write_lock(&GlobalSMBSeslock); | 423 | write_lock(&GlobalSMBSeslock); |
326 | list_add(&pCifsFile->tlist, &pTcon->openFileList); | 424 | list_add(&pCifsFile->tlist, &tcon->openFileList); |
327 | 425 | ||
328 | pCifsInode = CIFS_I(file->f_path.dentry->d_inode); | 426 | pCifsInode = CIFS_I(file->f_path.dentry->d_inode); |
329 | if (pCifsInode) { | 427 | if (pCifsInode) { |
330 | rc = cifs_open_inode_helper(inode, file, pCifsInode, | 428 | rc = cifs_open_inode_helper(inode, file, pCifsInode, |
331 | pCifsFile, pTcon, | 429 | pCifsFile, tcon, |
332 | &oplock, buf, full_path, xid); | 430 | &oplock, buf, full_path, xid); |
333 | } else { | 431 | } else { |
334 | write_unlock(&GlobalSMBSeslock); | 432 | write_unlock(&GlobalSMBSeslock); |
@@ -337,7 +435,7 @@ int cifs_open(struct inode *inode, struct file *file) | |||
337 | if (oplock & CIFS_CREATE_ACTION) { | 435 | if (oplock & CIFS_CREATE_ACTION) { |
338 | /* time to set mode which we can not set earlier due to | 436 | /* time to set mode which we can not set earlier due to |
339 | problems creating new read-only files */ | 437 | problems creating new read-only files */ |
340 | if (pTcon->unix_ext) { | 438 | if (tcon->unix_ext) { |
341 | struct cifs_unix_set_info_args args = { | 439 | struct cifs_unix_set_info_args args = { |
342 | .mode = inode->i_mode, | 440 | .mode = inode->i_mode, |
343 | .uid = NO_CHANGE_64, | 441 | .uid = NO_CHANGE_64, |
@@ -347,7 +445,7 @@ int cifs_open(struct inode *inode, struct file *file) | |||
347 | .mtime = NO_CHANGE_64, | 445 | .mtime = NO_CHANGE_64, |
348 | .device = 0, | 446 | .device = 0, |
349 | }; | 447 | }; |
350 | CIFSSMBUnixSetInfo(xid, pTcon, full_path, &args, | 448 | CIFSSMBUnixSetInfo(xid, tcon, full_path, &args, |
351 | cifs_sb->local_nls, | 449 | cifs_sb->local_nls, |
352 | cifs_sb->mnt_cifs_flags & | 450 | cifs_sb->mnt_cifs_flags & |
353 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 451 | CIFS_MOUNT_MAP_SPECIAL_CHR); |