initial commit with v2.6.9
[linux-2.6.9-moxart.git] / fs / cifs / inode.c
blob84d09d9f1a2d773bfbecf600e9c95f03c40d7318
1 /*
2 * fs/cifs/inode.c
4 * Copyright (C) International Business Machines Corp., 2002,2003
5 * Author(s): Steve French (sfrench@us.ibm.com)
7 * This library is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
15 * the GNU Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <linux/fs.h>
22 #include <linux/buffer_head.h>
23 #include <linux/stat.h>
24 #include <linux/pagemap.h>
25 #include <asm/div64.h>
26 #include "cifsfs.h"
27 #include "cifspdu.h"
28 #include "cifsglob.h"
29 #include "cifsproto.h"
30 #include "cifs_debug.h"
31 #include "cifs_fs_sb.h"
33 extern int is_size_safe_to_change(struct cifsInodeInfo *);
35 int
36 cifs_get_inode_info_unix(struct inode **pinode,
37 const unsigned char *search_path,
38 struct super_block *sb,int xid)
40 int rc = 0;
41 FILE_UNIX_BASIC_INFO findData;
42 struct cifsTconInfo *pTcon;
43 struct inode *inode;
44 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
45 char *tmp_path;
47 pTcon = cifs_sb->tcon;
48 cFYI(1, (" Getting info on %s ", search_path));
49 /* we could have done a find first instead but this returns more info */
50 rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
51 cifs_sb->local_nls);
52 /* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */
53 if (rc) {
54 if (rc == -EREMOTE) {
55 tmp_path =
56 kmalloc(strnlen
57 (pTcon->treeName,
58 MAX_TREE_SIZE + 1) +
59 strnlen(search_path, MAX_PATHCONF) + 1,
60 GFP_KERNEL);
61 if (tmp_path == NULL) {
62 return -ENOMEM;
64 /* have to skip first of the double backslash of UNC name */
65 strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
66 strncat(tmp_path, search_path, MAX_PATHCONF);
67 rc = connect_to_dfs_path(xid, pTcon->ses,
68 /* treename + */ tmp_path,
69 cifs_sb->local_nls);
70 kfree(tmp_path);
72 /* BB fix up inode etc. */
73 } else if (rc) {
74 return rc;
77 } else {
78 struct cifsInodeInfo *cifsInfo;
79 __u32 type = le32_to_cpu(findData.Type);
80 __u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes);
81 __u64 end_of_file = le64_to_cpu(findData.EndOfFile);
83 /* get new inode */
84 if (*pinode == NULL) {
85 *pinode = new_inode(sb);
86 if(*pinode == NULL)
87 return -ENOMEM;
88 insert_inode_hash(*pinode);
91 inode = *pinode;
92 cifsInfo = CIFS_I(inode);
94 cFYI(1, (" Old time %ld ", cifsInfo->time));
95 cifsInfo->time = jiffies;
96 cFYI(1, (" New time %ld ", cifsInfo->time));
97 atomic_set(&cifsInfo->inUse,1); /* ok to set on every refresh of inode */
99 inode->i_atime =
100 cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime));
101 inode->i_mtime =
102 cifs_NTtimeToUnix(le64_to_cpu
103 (findData.LastModificationTime));
104 inode->i_ctime =
105 cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange));
106 inode->i_mode = le64_to_cpu(findData.Permissions);
107 if (type == UNIX_FILE) {
108 inode->i_mode |= S_IFREG;
109 } else if (type == UNIX_SYMLINK) {
110 inode->i_mode |= S_IFLNK;
111 } else if (type == UNIX_DIR) {
112 inode->i_mode |= S_IFDIR;
113 } else if (type == UNIX_CHARDEV) {
114 inode->i_mode |= S_IFCHR;
115 inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor),
116 le64_to_cpu(findData.DevMinor) & MINORMASK);
117 } else if (type == UNIX_BLOCKDEV) {
118 inode->i_mode |= S_IFBLK;
119 inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor),
120 le64_to_cpu(findData.DevMinor) & MINORMASK);
121 } else if (type == UNIX_FIFO) {
122 inode->i_mode |= S_IFIFO;
123 } else if (type == UNIX_SOCKET) {
124 inode->i_mode |= S_IFSOCK;
126 inode->i_uid = le64_to_cpu(findData.Uid);
127 inode->i_gid = le64_to_cpu(findData.Gid);
128 inode->i_nlink = le64_to_cpu(findData.Nlinks);
130 if(is_size_safe_to_change(cifsInfo)) {
131 /* can not safely change the file size here if the
132 client is writing to it due to potential races */
134 i_size_write(inode, end_of_file);
135 /* blksize needs to be multiple of two. So safer to default to blksize
136 and blkbits set in superblock so 2**blkbits and blksize will match */
137 /* inode->i_blksize =
138 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
140 /* This seems incredibly stupid but it turns out that
141 i_blocks is not related to (i_size / i_blksize), instead a
142 size of 512 is required to be used for calculating num blocks */
145 /* inode->i_blocks =
146 (inode->i_blksize - 1 + num_of_bytes) >> inode->i_blkbits;*/
148 /* 512 bytes (2**9) is the fake blocksize that must be used */
149 /* for this calculation */
150 inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
153 if (num_of_bytes < end_of_file)
154 cFYI(1, ("Server inconsistency Error: it says allocation size less than end of file "));
155 cFYI(1,
156 ("Size %ld and blocks %ld ",
157 (unsigned long) inode->i_size, inode->i_blocks));
158 if (S_ISREG(inode->i_mode)) {
159 cFYI(1, (" File inode "));
160 inode->i_op = &cifs_file_inode_ops;
161 inode->i_fop = &cifs_file_ops;
162 inode->i_data.a_ops = &cifs_addr_ops;
163 } else if (S_ISDIR(inode->i_mode)) {
164 cFYI(1, (" Directory inode"));
165 inode->i_op = &cifs_dir_inode_ops;
166 inode->i_fop = &cifs_dir_ops;
167 } else if (S_ISLNK(inode->i_mode)) {
168 cFYI(1, (" Symbolic Link inode "));
169 inode->i_op = &cifs_symlink_inode_ops;
170 /* tmp_inode->i_fop = *//* do not need to set to anything */
171 } else {
172 cFYI(1, (" Init special inode "));
173 init_special_inode(inode, inode->i_mode,
174 inode->i_rdev);
177 return rc;
181 cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
182 FILE_ALL_INFO * pfindData, struct super_block *sb, int xid)
184 int rc = 0;
185 struct cifsTconInfo *pTcon;
186 struct inode *inode;
187 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
188 char *tmp_path;
189 char *buf = NULL;
191 pTcon = cifs_sb->tcon;
192 cFYI(1,("Getting info on %s ", search_path));
194 if((pfindData == NULL) && (*pinode != NULL)) {
195 if(CIFS_I(*pinode)->clientCanCacheRead) {
196 cFYI(1,("No need to revalidate inode sizes on cached file "));
197 return rc;
201 /* if file info not passed in then get it from server */
202 if(pfindData == NULL) {
203 buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
204 if(buf == NULL)
205 return -ENOMEM;
206 pfindData = (FILE_ALL_INFO *)buf;
207 /* could do find first instead but this returns more info */
208 rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
209 cifs_sb->local_nls);
211 /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
212 if (rc) {
213 if (rc == -EREMOTE) {
214 tmp_path =
215 kmalloc(strnlen
216 (pTcon->treeName,
217 MAX_TREE_SIZE + 1) +
218 strnlen(search_path, MAX_PATHCONF) + 1,
219 GFP_KERNEL);
220 if (tmp_path == NULL) {
221 if(buf)
222 kfree(buf);
223 return -ENOMEM;
226 strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
227 strncat(tmp_path, search_path, MAX_PATHCONF);
228 rc = connect_to_dfs_path(xid, pTcon->ses,
229 /* treename + */ tmp_path,
230 cifs_sb->local_nls);
231 kfree(tmp_path);
232 /* BB fix up inode etc. */
233 } else if (rc) {
234 if(buf)
235 kfree(buf);
236 return rc;
238 } else {
239 struct cifsInodeInfo *cifsInfo;
240 __u32 attr = le32_to_cpu(pfindData->Attributes);
242 /* get new inode */
243 if (*pinode == NULL) {
244 *pinode = new_inode(sb);
245 if(*pinode == NULL)
246 return -ENOMEM;
247 insert_inode_hash(*pinode);
249 inode = *pinode;
250 cifsInfo = CIFS_I(inode);
251 cifsInfo->cifsAttrs = attr;
252 cFYI(1, (" Old time %ld ", cifsInfo->time));
253 cifsInfo->time = jiffies;
254 cFYI(1, (" New time %ld ", cifsInfo->time));
256 /* blksize needs to be multiple of two. So safer to default to blksize
257 and blkbits set in superblock so 2**blkbits and blksize will match */
258 /* inode->i_blksize =
259 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
261 /* Linux can not store file creation time unfortunately so we ignore it */
262 inode->i_atime =
263 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
264 inode->i_mtime =
265 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
266 inode->i_ctime =
267 cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
268 cFYI(0,
269 (" Attributes came in as 0x%x ", attr));
271 /* set default mode. will override for dirs below */
272 if(atomic_read(&cifsInfo->inUse) == 0)
273 /* new inode, can safely set these fields */
274 inode->i_mode = cifs_sb->mnt_file_mode;
276 if (attr & ATTR_REPARSE) {
277 /* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */
278 inode->i_mode |= S_IFLNK;
279 } else if (attr & ATTR_DIRECTORY) {
280 /* override default perms since we do not do byte range locking on dirs */
281 inode->i_mode = cifs_sb->mnt_dir_mode;
282 inode->i_mode |= S_IFDIR;
283 } else {
284 inode->i_mode |= S_IFREG;
285 /* treat the dos attribute of read-only as read-only mode e.g. 555 */
286 if(cifsInfo->cifsAttrs & ATTR_READONLY)
287 inode->i_mode &= ~(S_IWUGO);
288 /* BB add code here - validate if device or weird share or device type? */
290 if(is_size_safe_to_change(cifsInfo)) {
291 /* can not safely change the file size here if the
292 client is writing to it due to potential races */
294 i_size_write(inode,le64_to_cpu(pfindData->EndOfFile));
296 /* 512 bytes (2**9) is the fake blocksize that must be used */
297 /* for this calculation */
298 inode->i_blocks = (512 - 1 + le64_to_cpu(pfindData->AllocationSize))
299 >> 9;
302 inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
304 /* BB fill in uid and gid here? with help from winbind?
305 or retrieve from NTFS stream extended attribute */
306 if(atomic_read(&cifsInfo->inUse) == 0) {
307 inode->i_uid = cifs_sb->mnt_uid;
308 inode->i_gid = cifs_sb->mnt_gid;
309 /* set so we do not keep refreshing these fields with
310 bad data after user has changed them in memory */
311 atomic_set(&cifsInfo->inUse,1);
314 if (S_ISREG(inode->i_mode)) {
315 cFYI(1, (" File inode "));
316 inode->i_op = &cifs_file_inode_ops;
317 inode->i_fop = &cifs_file_ops;
318 inode->i_data.a_ops = &cifs_addr_ops;
319 } else if (S_ISDIR(inode->i_mode)) {
320 cFYI(1, (" Directory inode "));
321 inode->i_op = &cifs_dir_inode_ops;
322 inode->i_fop = &cifs_dir_ops;
323 } else if (S_ISLNK(inode->i_mode)) {
324 cFYI(1, (" Symbolic Link inode "));
325 inode->i_op = &cifs_symlink_inode_ops;
326 } else {
327 init_special_inode(inode, inode->i_mode,
328 inode->i_rdev);
331 if(buf)
332 kfree(buf);
333 return rc;
336 void
337 cifs_read_inode(struct inode *inode)
338 { /* gets root inode */
339 int xid;
340 struct cifs_sb_info *cifs_sb;
342 cifs_sb = CIFS_SB(inode->i_sb);
343 xid = GetXid();
344 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
345 cifs_get_inode_info_unix(&inode, "", inode->i_sb,xid);
346 else
347 cifs_get_inode_info(&inode, "", NULL, inode->i_sb,xid);
348 /* can not call macro FreeXid here since in a void func */
349 _FreeXid(xid);
353 cifs_unlink(struct inode *inode, struct dentry *direntry)
355 int rc = 0;
356 int xid;
357 struct cifs_sb_info *cifs_sb;
358 struct cifsTconInfo *pTcon;
359 char *full_path = NULL;
360 struct cifsInodeInfo *cifsInode;
361 FILE_BASIC_INFO * pinfo_buf;
363 cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode));
365 xid = GetXid();
367 cifs_sb = CIFS_SB(inode->i_sb);
368 pTcon = cifs_sb->tcon;
370 /* Unlink can be called from rename so we can not grab
371 the sem here since we deadlock otherwise */
372 /* down(&direntry->d_sb->s_vfs_rename_sem);*/
373 full_path = build_path_from_dentry(direntry);
374 /* up(&direntry->d_sb->s_vfs_rename_sem);*/
375 if(full_path == NULL) {
376 FreeXid(xid);
377 return -ENOMEM;
379 rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
381 if (!rc) {
382 direntry->d_inode->i_nlink--;
383 } else if (rc == -ENOENT) {
384 d_drop(direntry);
385 } else if (rc == -ETXTBSY) {
386 int oplock = FALSE;
387 __u16 netfid;
389 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
390 CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
391 &netfid, &oplock, NULL, cifs_sb->local_nls);
392 if(rc==0) {
393 CIFSSMBRenameOpenFile(xid,pTcon,netfid,
394 NULL, cifs_sb->local_nls);
395 CIFSSMBClose(xid, pTcon, netfid);
396 direntry->d_inode->i_nlink--;
398 } else if (rc == -EACCES) {
399 /* try only if r/o attribute set in local lookup data? */
400 pinfo_buf = (FILE_BASIC_INFO *)kmalloc(sizeof(FILE_BASIC_INFO),GFP_KERNEL);
401 if(pinfo_buf) {
402 memset(pinfo_buf,0,sizeof(FILE_BASIC_INFO));
403 /* ATTRS set to normal clears r/o bit */
404 pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
405 rc = CIFSSMBSetTimes(xid, pTcon, full_path, pinfo_buf,
406 cifs_sb->local_nls);
407 kfree(pinfo_buf);
409 if(rc==0) {
410 rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
411 if (!rc) {
412 direntry->d_inode->i_nlink--;
413 } else if (rc == -ETXTBSY) {
414 int oplock = FALSE;
415 __u16 netfid;
417 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
418 CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
419 &netfid, &oplock, NULL, cifs_sb->local_nls);
420 if(rc==0) {
421 CIFSSMBRenameOpenFile(xid,pTcon,netfid,NULL,cifs_sb->local_nls);
422 CIFSSMBClose(xid, pTcon, netfid);
423 direntry->d_inode->i_nlink--;
425 /* BB if rc = -ETXTBUSY goto the rename logic BB */
429 cifsInode = CIFS_I(direntry->d_inode);
430 cifsInode->time = 0; /* will force revalidate to get info when needed */
431 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
432 CURRENT_TIME;
433 cifsInode = CIFS_I(inode);
434 cifsInode->time = 0; /* force revalidate of dir as well */
436 if (full_path)
437 kfree(full_path);
438 FreeXid(xid);
439 return rc;
443 cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
445 int rc = 0;
446 int xid;
447 struct cifs_sb_info *cifs_sb;
448 struct cifsTconInfo *pTcon;
449 char *full_path = NULL;
450 struct inode *newinode = NULL;
452 cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode));
454 xid = GetXid();
456 cifs_sb = CIFS_SB(inode->i_sb);
457 pTcon = cifs_sb->tcon;
459 down(&inode->i_sb->s_vfs_rename_sem);
460 full_path = build_path_from_dentry(direntry);
461 up(&inode->i_sb->s_vfs_rename_sem);
462 if(full_path == NULL) {
463 FreeXid(xid);
464 return -ENOMEM;
466 /* BB add setting the equivalent of mode via CreateX w/ACLs */
467 rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls);
468 if (rc) {
469 cFYI(1, ("cifs_mkdir returned 0x%x ", rc));
470 d_drop(direntry);
471 } else {
472 inode->i_nlink++;
473 if (pTcon->ses->capabilities & CAP_UNIX)
474 rc = cifs_get_inode_info_unix(&newinode, full_path,
475 inode->i_sb,xid);
476 else
477 rc = cifs_get_inode_info(&newinode, full_path,NULL,
478 inode->i_sb,xid);
480 direntry->d_op = &cifs_dentry_ops;
481 d_instantiate(direntry, newinode);
482 if(direntry->d_inode)
483 direntry->d_inode->i_nlink = 2;
484 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
485 if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
486 CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
487 (__u64)current->euid,
488 (__u64)current->egid,
489 0 /* dev_t */,
490 cifs_sb->local_nls);
491 } else {
492 CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
493 (__u64)-1,
494 (__u64)-1,
495 0 /* dev_t */,
496 cifs_sb->local_nls);
498 else { /* BB to be implemented via Windows secrty descriptors*/
499 /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
502 if (full_path)
503 kfree(full_path);
504 FreeXid(xid);
506 return rc;
510 cifs_rmdir(struct inode *inode, struct dentry *direntry)
512 int rc = 0;
513 int xid;
514 struct cifs_sb_info *cifs_sb;
515 struct cifsTconInfo *pTcon;
516 char *full_path = NULL;
517 struct cifsInodeInfo *cifsInode;
519 cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode));
521 xid = GetXid();
523 cifs_sb = CIFS_SB(inode->i_sb);
524 pTcon = cifs_sb->tcon;
526 down(&inode->i_sb->s_vfs_rename_sem);
527 full_path = build_path_from_dentry(direntry);
528 up(&inode->i_sb->s_vfs_rename_sem);
529 if(full_path == NULL) {
530 FreeXid(xid);
531 return -ENOMEM;
534 rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls);
536 if (!rc) {
537 inode->i_nlink--;
538 i_size_write(direntry->d_inode,0);
539 direntry->d_inode->i_nlink = 0;
542 cifsInode = CIFS_I(direntry->d_inode);
543 cifsInode->time = 0; /* force revalidate to go get info when needed */
544 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
545 CURRENT_TIME;
547 if (full_path)
548 kfree(full_path);
549 FreeXid(xid);
550 return rc;
554 cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
555 struct inode *target_inode, struct dentry *target_direntry)
557 char *fromName;
558 char *toName;
559 struct cifs_sb_info *cifs_sb_source;
560 struct cifs_sb_info *cifs_sb_target;
561 struct cifsTconInfo *pTcon;
562 int xid;
563 int rc = 0;
565 xid = GetXid();
567 cifs_sb_target = CIFS_SB(target_inode->i_sb);
568 cifs_sb_source = CIFS_SB(source_inode->i_sb);
569 pTcon = cifs_sb_source->tcon;
571 if (pTcon != cifs_sb_target->tcon) {
572 FreeXid(xid);
573 return -EXDEV; /* BB actually could be allowed if same server, but
574 different share. Might eventually add support for this */
577 /* we already have the rename sem so we do not need
578 to grab it again here to protect the path integrity */
579 fromName = build_path_from_dentry(source_direntry);
580 toName = build_path_from_dentry(target_direntry);
581 if((fromName == NULL) || (toName == NULL)) {
582 rc = -ENOMEM;
583 goto cifs_rename_exit;
586 rc = CIFSSMBRename(xid, pTcon, fromName, toName,
587 cifs_sb_source->local_nls);
588 if(rc == -EEXIST) {
589 /* check if they are the same file
590 because rename of hardlinked files is a noop */
591 FILE_UNIX_BASIC_INFO * info_buf_source;
592 FILE_UNIX_BASIC_INFO * info_buf_target;
594 info_buf_source =
595 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),GFP_KERNEL);
596 if(info_buf_source != NULL) {
597 info_buf_target = info_buf_source+1;
598 rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
599 info_buf_source, cifs_sb_source->local_nls);
600 if(rc == 0) {
601 rc = CIFSSMBUnixQPathInfo(xid,pTcon,toName,
602 info_buf_target,
603 cifs_sb_target->local_nls);
605 if((rc == 0) &&
606 (info_buf_source->UniqueId ==
607 info_buf_target->UniqueId)) {
608 /* do not rename since the files are hardlinked
609 which is a noop */
610 } else {
611 /* we either can not tell the files are hardlinked
612 (as with Windows servers) or files are not hardlinked
613 so delete the target manually before renaming to
614 follow POSIX rather than Windows semantics */
615 cifs_unlink(target_inode, target_direntry);
616 rc = CIFSSMBRename(xid, pTcon, fromName, toName,
617 cifs_sb_source->local_nls);
619 kfree(info_buf_source);
620 } /* if we can not get memory just leave rc as EEXIST */
623 if((rc == -EIO)||(rc == -EEXIST)) {
624 int oplock = FALSE;
625 __u16 netfid;
627 rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
628 CREATE_NOT_DIR,
629 &netfid, &oplock, NULL, cifs_sb_source->local_nls);
630 if(rc==0) {
631 CIFSSMBRenameOpenFile(xid,pTcon,netfid,
632 toName, cifs_sb_source->local_nls);
633 CIFSSMBClose(xid, pTcon, netfid);
637 cifs_rename_exit:
638 if (fromName)
639 kfree(fromName);
640 if (toName)
641 kfree(toName);
643 FreeXid(xid);
644 return rc;
648 cifs_revalidate(struct dentry *direntry)
650 int xid;
651 int rc = 0;
652 char *full_path;
653 struct cifs_sb_info *cifs_sb;
654 struct cifsInodeInfo *cifsInode;
655 loff_t local_size;
656 struct timespec local_mtime;
657 int invalidate_inode = FALSE;
659 if(direntry->d_inode == NULL)
660 return -ENOENT;
662 cifsInode = CIFS_I(direntry->d_inode);
664 if(cifsInode == NULL)
665 return -ENOENT;
667 /* no sense revalidating inode info on file that no one can write */
668 if(CIFS_I(direntry->d_inode)->clientCanCacheRead)
669 return rc;
671 xid = GetXid();
673 cifs_sb = CIFS_SB(direntry->d_sb);
675 /* can not safely grab the rename sem here if
676 rename calls revalidate since that would deadlock */
677 full_path = build_path_from_dentry(direntry);
678 if(full_path == NULL) {
679 FreeXid(xid);
680 return -ENOMEM;
682 cFYI(1,
683 ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld",
684 full_path, direntry->d_inode,
685 direntry->d_inode->i_count.counter, direntry,
686 direntry->d_time, jiffies));
688 if (cifsInode->time == 0){
689 /* was set to zero previously to force revalidate */
690 } else if (time_before(jiffies, cifsInode->time + HZ) && lookupCacheEnabled) {
691 if((S_ISREG(direntry->d_inode->i_mode) == 0) ||
692 (direntry->d_inode->i_nlink == 1)) {
693 if (full_path)
694 kfree(full_path);
695 FreeXid(xid);
696 return rc;
697 } else {
698 cFYI(1,("Have to revalidate file due to hardlinks"));
702 /* save mtime and size */
703 local_mtime = direntry->d_inode->i_mtime;
704 local_size = direntry->d_inode->i_size;
706 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
707 rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
708 direntry->d_sb,xid);
709 if(rc) {
710 cFYI(1,("error on getting revalidate info %d",rc));
711 /* if(rc != -ENOENT)
712 rc = 0; */ /* BB should we cache info on certain errors? */
714 } else {
715 rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
716 direntry->d_sb,xid);
717 if(rc) {
718 cFYI(1,("error on getting revalidate info %d",rc));
719 /* if(rc != -ENOENT)
720 rc = 0; */ /* BB should we cache info on certain errors? */
723 /* should we remap certain errors, access denied?, to zero */
725 /* if not oplocked, we invalidate inode pages if mtime
726 or file size had changed on server */
728 if(timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) &&
729 (local_size == direntry->d_inode->i_size)) {
730 cFYI(1,("cifs_revalidate - inode unchanged"));
731 } else {
732 /* file may have changed on server */
733 if(cifsInode->clientCanCacheRead) {
734 /* no need to invalidate inode pages since we were
735 the only ones who could have modified the file and
736 the server copy is staler than ours */
737 } else {
738 invalidate_inode = TRUE;
742 /* can not grab this sem since kernel filesys locking
743 documentation indicates i_sem may be taken by the kernel
744 on lookup and rename which could deadlock if we grab
745 the i_sem here as well */
746 /* down(&direntry->d_inode->i_sem);*/
747 /* need to write out dirty pages here */
748 if(direntry->d_inode->i_mapping) {
749 /* do we need to lock inode until after invalidate completes below? */
750 filemap_fdatawrite(direntry->d_inode->i_mapping);
752 if(invalidate_inode) {
753 filemap_fdatawait(direntry->d_inode->i_mapping);
754 /* may eventually have to do this for open files too */
755 if(list_empty(&(cifsInode->openFileList))) {
756 /* Has changed on server - flush read ahead pages */
757 cFYI(1,("Invalidating read ahead data on closed file"));
758 invalidate_remote_inode(direntry->d_inode);
761 /* up(&direntry->d_inode->i_sem);*/
763 if (full_path)
764 kfree(full_path);
765 FreeXid(xid);
767 return rc;
770 int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
772 int err = cifs_revalidate(dentry);
773 if (!err)
774 generic_fillattr(dentry->d_inode, stat);
775 return err;
778 static int cifs_truncate_page(struct address_space *mapping, loff_t from)
780 pgoff_t index = from >> PAGE_CACHE_SHIFT;
781 unsigned offset = from & (PAGE_CACHE_SIZE-1);
782 struct page *page;
783 char *kaddr;
784 int rc = 0;
786 page = grab_cache_page(mapping, index);
787 if (!page)
788 return -ENOMEM;
790 kaddr = kmap_atomic(page, KM_USER0);
791 memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
792 flush_dcache_page(page);
793 kunmap_atomic(kaddr, KM_USER0);
794 unlock_page(page);
795 page_cache_release(page);
796 return rc;
800 cifs_setattr(struct dentry *direntry, struct iattr *attrs)
802 int xid;
803 struct cifs_sb_info *cifs_sb;
804 struct cifsTconInfo *pTcon;
805 char *full_path = NULL;
806 int rc = -EACCES;
807 int found = FALSE;
808 struct cifsFileInfo *open_file = NULL;
809 FILE_BASIC_INFO time_buf;
810 int set_time = FALSE;
811 __u64 mode = 0xFFFFFFFFFFFFFFFFULL;
812 __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
813 __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
814 struct cifsInodeInfo *cifsInode;
815 struct list_head * tmp;
817 xid = GetXid();
819 cFYI(1,
820 (" In cifs_setattr, name = %s attrs->iavalid 0x%x ",
821 direntry->d_name.name, attrs->ia_valid));
822 cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
823 pTcon = cifs_sb->tcon;
825 down(&direntry->d_sb->s_vfs_rename_sem);
826 full_path = build_path_from_dentry(direntry);
827 up(&direntry->d_sb->s_vfs_rename_sem);
828 if(full_path == NULL) {
829 FreeXid(xid);
830 return -ENOMEM;
832 cifsInode = CIFS_I(direntry->d_inode);
834 /* BB check if we need to refresh inode from server now ? BB */
836 /* need to flush data before changing file size on server */
837 filemap_fdatawrite(direntry->d_inode->i_mapping);
838 filemap_fdatawait(direntry->d_inode->i_mapping);
840 if (attrs->ia_valid & ATTR_SIZE) {
841 read_lock(&GlobalSMBSeslock);
842 /* To avoid spurious oplock breaks from server, in the case
843 of inodes that we already have open, avoid doing path
844 based setting of file size if we can do it by handle.
845 This keeps our caching token (oplock) and avoids
846 timeouts when the local oplock break takes longer to flush
847 writebehind data than the SMB timeout for the SetPathInfo
848 request would allow */
849 list_for_each(tmp, &cifsInode->openFileList) {
850 open_file = list_entry(tmp,struct cifsFileInfo, flist);
851 /* We check if file is open for writing first */
852 if((open_file->pfile) &&
853 ((open_file->pfile->f_flags & O_RDWR) ||
854 (open_file->pfile->f_flags & O_WRONLY))) {
855 if(open_file->invalidHandle == FALSE) {
856 /* we found a valid, writeable network file
857 handle to use to try to set the file size */
858 __u16 nfid = open_file->netfid;
859 __u32 npid = open_file->pid;
860 read_unlock(&GlobalSMBSeslock);
861 found = TRUE;
862 rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
863 nfid,npid,FALSE);
864 cFYI(1,("SetFileSize by handle (setattrs) rc = %d",rc));
865 /* Do not need reopen and retry on EAGAIN since we will
866 retry by pathname below */
868 break; /* now that we found one valid file handle no
869 sense continuing to loop trying others */
873 if(found == FALSE) {
874 read_unlock(&GlobalSMBSeslock);
878 if(rc != 0) {
879 /* Set file size by pathname rather than by handle either
880 because no valid, writeable file handle for it was found or
881 because there was an error setting it by handle */
882 rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,FALSE,
883 cifs_sb->local_nls);
884 cFYI(1,(" SetEOF by path (setattrs) rc = %d",rc));
887 /* Server is ok setting allocation size implicitly - no need to call: */
888 /*CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE, cifs_sb->local_nls);*/
890 if (rc == 0) {
891 rc = vmtruncate(direntry->d_inode, attrs->ia_size);
892 cifs_truncate_page(direntry->d_inode->i_mapping, direntry->d_inode->i_size);
895 if (attrs->ia_valid & ATTR_UID) {
896 cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid));
897 uid = attrs->ia_uid;
898 /* entry->uid = cpu_to_le16(attr->ia_uid); */
900 if (attrs->ia_valid & ATTR_GID) {
901 cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid));
902 gid = attrs->ia_gid;
903 /* entry->gid = cpu_to_le16(attr->ia_gid); */
906 time_buf.Attributes = 0;
907 if (attrs->ia_valid & ATTR_MODE) {
908 cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode));
909 mode = attrs->ia_mode;
910 /* entry->mode = cpu_to_le16(attr->ia_mode); */
913 if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
914 && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
915 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
916 0 /* dev_t */, cifs_sb->local_nls);
917 else if (attrs->ia_valid & ATTR_MODE) {
918 if((mode & S_IWUGO) == 0) /* not writeable */ {
919 if((cifsInode->cifsAttrs & ATTR_READONLY) == 0)
920 time_buf.Attributes =
921 cpu_to_le32(cifsInode->cifsAttrs | ATTR_READONLY);
922 } else if((mode & S_IWUGO) == S_IWUGO) {
923 if(cifsInode->cifsAttrs & ATTR_READONLY)
924 time_buf.Attributes =
925 cpu_to_le32(cifsInode->cifsAttrs & (~ATTR_READONLY));
927 /* BB to be implemented - via Windows security descriptors or streams */
928 /* CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,uid,gid,cifs_sb->local_nls);*/
931 if (attrs->ia_valid & ATTR_ATIME) {
932 set_time = TRUE;
933 time_buf.LastAccessTime =
934 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
935 } else
936 time_buf.LastAccessTime = 0;
938 if (attrs->ia_valid & ATTR_MTIME) {
939 set_time = TRUE;
940 time_buf.LastWriteTime =
941 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
942 } else
943 time_buf.LastWriteTime = 0;
945 if (attrs->ia_valid & ATTR_CTIME) {
946 set_time = TRUE;
947 cFYI(1, (" CIFS - CTIME changed ")); /* BB probably do not need */
948 time_buf.ChangeTime =
949 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
950 } else
951 time_buf.ChangeTime = 0;
953 if (set_time || time_buf.Attributes) {
954 /* BB what if setting one attribute fails
955 (such as size) but time setting works */
956 time_buf.CreationTime = 0; /* do not change */
957 /* In the future we should experiment - try setting timestamps
958 via Handle (SetFileInfo) instead of by path */
959 rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
960 cifs_sb->local_nls);
963 /* do not need local check to inode_check_ok since the server does that */
964 if (!rc)
965 rc = inode_setattr(direntry->d_inode, attrs);
966 if (full_path)
967 kfree(full_path);
968 FreeXid(xid);
969 return rc;
972 void
973 cifs_delete_inode(struct inode *inode)
975 cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode));
976 /* may have to add back in if and when safe distributed caching of
977 directories added e.g. via FindNotify */