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
22 #include <linux/buffer_head.h>
23 #include <linux/stat.h>
24 #include <linux/pagemap.h>
25 #include <asm/div64.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 *);
36 cifs_get_inode_info_unix(struct inode **pinode,
37 const unsigned char *search_path,
38 struct super_block *sb,int xid)
41 FILE_UNIX_BASIC_INFO findData;
42 struct cifsTconInfo *pTcon;
44 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
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,
52 /* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */
59 strnlen(search_path, MAX_PATHCONF) + 1,
61 if (tmp_path == NULL) {
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,
72 /* BB fix up inode etc. */
78 struct cifsInodeInfo *cifsInfo;
81 if (*pinode == NULL) {
82 *pinode = new_inode(sb);
85 insert_inode_hash(*pinode);
89 cifsInfo = CIFS_I(inode);
91 cFYI(1, (" Old time %ld ", cifsInfo->time));
92 cifsInfo->time = jiffies;
93 cFYI(1, (" New time %ld ", cifsInfo->time));
94 atomic_set(&cifsInfo->inUse,1); /* ok to set on every refresh of inode */
97 cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime));
99 cifs_NTtimeToUnix(le64_to_cpu
100 (findData.LastModificationTime));
102 cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange));
103 inode->i_mode = le64_to_cpu(findData.Permissions);
104 findData.Type = le32_to_cpu(findData.Type);
105 if (findData.Type == UNIX_FILE) {
106 inode->i_mode |= S_IFREG;
107 } else if (findData.Type == UNIX_SYMLINK) {
108 inode->i_mode |= S_IFLNK;
109 } else if (findData.Type == UNIX_DIR) {
110 inode->i_mode |= S_IFDIR;
111 } else if (findData.Type == UNIX_CHARDEV) {
112 inode->i_mode |= S_IFCHR;
113 inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor),
114 le64_to_cpu(findData.DevMinor) & MINORMASK);
115 } else if (findData.Type == UNIX_BLOCKDEV) {
116 inode->i_mode |= S_IFBLK;
117 inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor),
118 le64_to_cpu(findData.DevMinor) & MINORMASK);
119 } else if (findData.Type == UNIX_FIFO) {
120 inode->i_mode |= S_IFIFO;
121 } else if (findData.Type == UNIX_SOCKET) {
122 inode->i_mode |= S_IFSOCK;
124 inode->i_uid = le64_to_cpu(findData.Uid);
125 inode->i_gid = le64_to_cpu(findData.Gid);
126 inode->i_nlink = le64_to_cpu(findData.Nlinks);
127 findData.NumOfBytes = le64_to_cpu(findData.NumOfBytes);
128 findData.EndOfFile = le64_to_cpu(findData.EndOfFile);
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,findData.EndOfFile);
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 */
146 (inode->i_blksize - 1 + findData.NumOfBytes) >> 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 + findData.NumOfBytes) >> 9;
153 if (findData.NumOfBytes < findData.EndOfFile)
154 cFYI(1, ("Server inconsistency Error: it says allocation size less than end of file "));
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 */
172 cFYI(1, (" Init special inode "));
173 init_special_inode(inode, inode->i_mode,
181 cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
182 FILE_ALL_INFO * pfindData, struct super_block *sb, int xid)
185 struct cifsTconInfo *pTcon;
187 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
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 "));
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 pfindData = (FILE_ALL_INFO *)buf;
205 /* could do find first instead but this returns more info */
206 rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
209 /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
211 if (rc == -EREMOTE) {
216 strnlen(search_path, MAX_PATHCONF) + 1,
218 if (tmp_path == NULL) {
224 strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
225 strncat(tmp_path, search_path, MAX_PATHCONF);
226 rc = connect_to_dfs_path(xid, pTcon->ses,
227 /* treename + */ tmp_path,
230 /* BB fix up inode etc. */
237 struct cifsInodeInfo *cifsInfo;
240 if (*pinode == NULL) {
241 *pinode = new_inode(sb);
244 insert_inode_hash(*pinode);
247 cifsInfo = CIFS_I(inode);
248 pfindData->Attributes = le32_to_cpu(pfindData->Attributes);
249 cifsInfo->cifsAttrs = pfindData->Attributes;
250 cFYI(1, (" Old time %ld ", cifsInfo->time));
251 cifsInfo->time = jiffies;
252 cFYI(1, (" New time %ld ", cifsInfo->time));
254 /* blksize needs to be multiple of two. So safer to default to blksize
255 and blkbits set in superblock so 2**blkbits and blksize will match */
256 /* inode->i_blksize =
257 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
259 /* Linux can not store file creation time unfortunately so we ignore it */
261 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
263 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
265 cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
267 (" Attributes came in as 0x%x ", pfindData->Attributes));
269 /* set default mode. will override for dirs below */
270 if(atomic_read(&cifsInfo->inUse) == 0)
271 /* new inode, can safely set these fields */
272 inode->i_mode = cifs_sb->mnt_file_mode;
274 if (pfindData->Attributes & ATTR_REPARSE) {
275 /* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */
276 inode->i_mode |= S_IFLNK;
277 } else if (pfindData->Attributes & ATTR_DIRECTORY) {
278 /* override default perms since we do not do byte range locking on dirs */
279 inode->i_mode = cifs_sb->mnt_dir_mode;
280 inode->i_mode |= S_IFDIR;
282 inode->i_mode |= S_IFREG;
283 /* treat the dos attribute of read-only as read-only mode e.g. 555 */
284 if(cifsInfo->cifsAttrs & ATTR_READONLY)
285 inode->i_mode &= ~(S_IWUGO);
286 /* BB add code here - validate if device or weird share or device type? */
288 if(is_size_safe_to_change(cifsInfo)) {
289 /* can not safely change the file size here if the
290 client is writing to it due to potential races */
292 i_size_write(inode,le64_to_cpu(pfindData->EndOfFile));
294 /* 512 bytes (2**9) is the fake blocksize that must be used */
295 /* for this calculation */
296 inode->i_blocks = (512 - 1 + pfindData->AllocationSize)
299 pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize);
301 inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
303 /* BB fill in uid and gid here? with help from winbind?
304 or retrieve from NTFS stream extended attribute */
305 if(atomic_read(&cifsInfo->inUse) == 0) {
306 inode->i_uid = cifs_sb->mnt_uid;
307 inode->i_gid = cifs_sb->mnt_gid;
308 /* set so we do not keep refreshing these fields with
309 bad data after user has changed them in memory */
310 atomic_set(&cifsInfo->inUse,1);
313 if (S_ISREG(inode->i_mode)) {
314 cFYI(1, (" File inode "));
315 inode->i_op = &cifs_file_inode_ops;
316 inode->i_fop = &cifs_file_ops;
317 inode->i_data.a_ops = &cifs_addr_ops;
318 } else if (S_ISDIR(inode->i_mode)) {
319 cFYI(1, (" Directory inode "));
320 inode->i_op = &cifs_dir_inode_ops;
321 inode->i_fop = &cifs_dir_ops;
322 } else if (S_ISLNK(inode->i_mode)) {
323 cFYI(1, (" Symbolic Link inode "));
324 inode->i_op = &cifs_symlink_inode_ops;
326 init_special_inode(inode, inode->i_mode,
336 cifs_read_inode(struct inode *inode)
337 { /* gets root inode */
339 struct cifs_sb_info *cifs_sb;
341 cifs_sb = CIFS_SB(inode->i_sb);
343 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
344 cifs_get_inode_info_unix(&inode, "", inode->i_sb,xid);
346 cifs_get_inode_info(&inode, "", NULL, inode->i_sb,xid);
347 /* can not call macro FreeXid here since in a void func */
352 cifs_unlink(struct inode *inode, struct dentry *direntry)
356 struct cifs_sb_info *cifs_sb;
357 struct cifsTconInfo *pTcon;
358 char *full_path = NULL;
359 struct cifsInodeInfo *cifsInode;
360 FILE_BASIC_INFO * pinfo_buf;
362 cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode));
366 cifs_sb = CIFS_SB(inode->i_sb);
367 pTcon = cifs_sb->tcon;
369 /* Unlink can be called from rename so we can not grab
370 the sem here since we deadlock otherwise */
371 /* down(&direntry->d_sb->s_vfs_rename_sem);*/
372 full_path = build_path_from_dentry(direntry);
373 /* up(&direntry->d_sb->s_vfs_rename_sem);*/
374 if(full_path == NULL) {
378 rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
381 direntry->d_inode->i_nlink--;
382 } else if (rc == -ENOENT) {
384 } else if (rc == -ETXTBSY) {
388 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
389 CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
390 &netfid, &oplock, NULL, cifs_sb->local_nls);
392 CIFSSMBRenameOpenFile(xid,pTcon,netfid,
393 NULL, cifs_sb->local_nls);
394 CIFSSMBClose(xid, pTcon, netfid);
395 direntry->d_inode->i_nlink--;
397 } else if (rc == -EACCES) {
398 /* try only if r/o attribute set in local lookup data? */
399 pinfo_buf = (FILE_BASIC_INFO *)kmalloc(sizeof(FILE_BASIC_INFO),GFP_KERNEL);
401 memset(pinfo_buf,0,sizeof(FILE_BASIC_INFO));
402 /* ATTRS set to normal clears r/o bit */
403 pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
404 rc = CIFSSMBSetTimes(xid, pTcon, full_path, pinfo_buf,
409 rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
411 direntry->d_inode->i_nlink--;
412 } else if (rc == -ETXTBSY) {
416 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
417 CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
418 &netfid, &oplock, NULL, cifs_sb->local_nls);
420 CIFSSMBRenameOpenFile(xid,pTcon,netfid,NULL,cifs_sb->local_nls);
421 CIFSSMBClose(xid, pTcon, netfid);
422 direntry->d_inode->i_nlink--;
424 /* BB if rc = -ETXTBUSY goto the rename logic BB */
428 cifsInode = CIFS_I(direntry->d_inode);
429 cifsInode->time = 0; /* will force revalidate to get info when needed */
430 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
432 cifsInode = CIFS_I(inode);
433 cifsInode->time = 0; /* force revalidate of dir as well */
442 cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
446 struct cifs_sb_info *cifs_sb;
447 struct cifsTconInfo *pTcon;
448 char *full_path = NULL;
449 struct inode *newinode = NULL;
451 cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode));
455 cifs_sb = CIFS_SB(inode->i_sb);
456 pTcon = cifs_sb->tcon;
458 down(&inode->i_sb->s_vfs_rename_sem);
459 full_path = build_path_from_dentry(direntry);
460 up(&inode->i_sb->s_vfs_rename_sem);
461 if(full_path == NULL) {
465 /* BB add setting the equivalent of mode via CreateX w/ACLs */
466 rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls);
468 cFYI(1, ("cifs_mkdir returned 0x%x ", rc));
472 if (pTcon->ses->capabilities & CAP_UNIX)
473 rc = cifs_get_inode_info_unix(&newinode, full_path,
476 rc = cifs_get_inode_info(&newinode, full_path,NULL,
479 direntry->d_op = &cifs_dentry_ops;
480 d_instantiate(direntry, newinode);
481 if(direntry->d_inode)
482 direntry->d_inode->i_nlink = 2;
483 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
484 if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
485 CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
486 (__u64)current->euid,
487 (__u64)current->egid,
491 CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
497 else { /* BB to be implemented via Windows secrty descriptors*/
498 /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
509 cifs_rmdir(struct inode *inode, struct dentry *direntry)
513 struct cifs_sb_info *cifs_sb;
514 struct cifsTconInfo *pTcon;
515 char *full_path = NULL;
516 struct cifsInodeInfo *cifsInode;
518 cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode));
522 cifs_sb = CIFS_SB(inode->i_sb);
523 pTcon = cifs_sb->tcon;
525 down(&inode->i_sb->s_vfs_rename_sem);
526 full_path = build_path_from_dentry(direntry);
527 up(&inode->i_sb->s_vfs_rename_sem);
528 if(full_path == NULL) {
533 rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls);
537 i_size_write(direntry->d_inode,0);
538 direntry->d_inode->i_nlink = 0;
541 cifsInode = CIFS_I(direntry->d_inode);
542 cifsInode->time = 0; /* force revalidate to go get info when needed */
543 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
553 cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
554 struct inode *target_inode, struct dentry *target_direntry)
558 struct cifs_sb_info *cifs_sb_source;
559 struct cifs_sb_info *cifs_sb_target;
560 struct cifsTconInfo *pTcon;
566 cifs_sb_target = CIFS_SB(target_inode->i_sb);
567 cifs_sb_source = CIFS_SB(source_inode->i_sb);
568 pTcon = cifs_sb_source->tcon;
570 if (pTcon != cifs_sb_target->tcon) {
572 return -EXDEV; /* BB actually could be allowed if same server, but
573 different share. Might eventually add support for this */
576 /* we already have the rename sem so we do not need
577 to grab it again here to protect the path integrity */
578 fromName = build_path_from_dentry(source_direntry);
579 toName = build_path_from_dentry(target_direntry);
580 if((fromName == NULL) || (toName == NULL)) {
582 goto cifs_rename_exit;
585 rc = CIFSSMBRename(xid, pTcon, fromName, toName,
586 cifs_sb_source->local_nls);
588 /* check if they are the same file
589 because rename of hardlinked files is a noop */
590 FILE_UNIX_BASIC_INFO * info_buf_source;
591 FILE_UNIX_BASIC_INFO * info_buf_target;
594 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),GFP_KERNEL);
595 if(info_buf_source != NULL) {
596 info_buf_target = info_buf_source+1;
597 rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
598 info_buf_source, cifs_sb_source->local_nls);
600 rc = CIFSSMBUnixQPathInfo(xid,pTcon,toName,
602 cifs_sb_target->local_nls);
605 (info_buf_source->UniqueId ==
606 info_buf_target->UniqueId)) {
607 /* do not rename since the files are hardlinked
610 /* we either can not tell the files are hardlinked
611 (as with Windows servers) or files are not hardlinked
612 so delete the target manually before renaming to
613 follow POSIX rather than Windows semantics */
614 cifs_unlink(target_inode, target_direntry);
615 rc = CIFSSMBRename(xid, pTcon, fromName, toName,
616 cifs_sb_source->local_nls);
618 kfree(info_buf_source);
619 } /* if we can not get memory just leave rc as EEXIST */
622 if((rc == -EIO)||(rc == -EEXIST)) {
626 rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
628 &netfid, &oplock, NULL, cifs_sb_source->local_nls);
630 CIFSSMBRenameOpenFile(xid,pTcon,netfid,
631 toName, cifs_sb_source->local_nls);
632 CIFSSMBClose(xid, pTcon, netfid);
647 cifs_revalidate(struct dentry *direntry)
652 struct cifs_sb_info *cifs_sb;
653 struct cifsInodeInfo *cifsInode;
655 struct timespec local_mtime;
656 int invalidate_inode = FALSE;
658 if(direntry->d_inode == NULL)
661 cifsInode = CIFS_I(direntry->d_inode);
663 if(cifsInode == NULL)
666 /* no sense revalidating inode info on file that no one can write */
667 if(CIFS_I(direntry->d_inode)->clientCanCacheRead)
672 cifs_sb = CIFS_SB(direntry->d_sb);
674 /* can not safely grab the rename sem here if
675 rename calls revalidate since that would deadlock */
676 full_path = build_path_from_dentry(direntry);
677 if(full_path == NULL) {
682 ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld",
683 full_path, direntry->d_inode,
684 direntry->d_inode->i_count.counter, direntry,
685 direntry->d_time, jiffies));
687 if (cifsInode->time == 0){
688 /* was set to zero previously to force revalidate */
689 } else if (time_before(jiffies, cifsInode->time + HZ) && lookupCacheEnabled) {
690 if((S_ISREG(direntry->d_inode->i_mode) == 0) ||
691 (direntry->d_inode->i_nlink == 1)) {
697 cFYI(1,("Have to revalidate file due to hardlinks"));
701 /* save mtime and size */
702 local_mtime = direntry->d_inode->i_mtime;
703 local_size = direntry->d_inode->i_size;
705 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
706 rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
709 cFYI(1,("error on getting revalidate info %d",rc));
711 rc = 0; */ /* BB should we cache info on certain errors? */
714 rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
717 cFYI(1,("error on getting revalidate info %d",rc));
719 rc = 0; */ /* BB should we cache info on certain errors? */
722 /* should we remap certain errors, access denied?, to zero */
724 /* if not oplocked, we invalidate inode pages if mtime
725 or file size had changed on server */
727 if(timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) &&
728 (local_size == direntry->d_inode->i_size)) {
729 cFYI(1,("cifs_revalidate - inode unchanged"));
731 /* file may have changed on server */
732 if(cifsInode->clientCanCacheRead) {
733 /* no need to invalidate inode pages since we were
734 the only ones who could have modified the file and
735 the server copy is staler than ours */
737 invalidate_inode = TRUE;
741 /* can not grab this sem since kernel filesys locking
742 documentation indicates i_sem may be taken by the kernel
743 on lookup and rename which could deadlock if we grab
744 the i_sem here as well */
745 /* down(&direntry->d_inode->i_sem);*/
746 /* need to write out dirty pages here */
747 if(direntry->d_inode->i_mapping) {
748 /* do we need to lock inode until after invalidate completes below? */
749 filemap_fdatawrite(direntry->d_inode->i_mapping);
751 if(invalidate_inode) {
752 filemap_fdatawait(direntry->d_inode->i_mapping);
753 /* may eventually have to do this for open files too */
754 if(list_empty(&(cifsInode->openFileList))) {
755 /* Has changed on server - flush read ahead pages */
756 cFYI(1,("Invalidating read ahead data on closed file"));
757 invalidate_remote_inode(direntry->d_inode);
760 /* up(&direntry->d_inode->i_sem);*/
769 int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
771 int err = cifs_revalidate(dentry);
773 generic_fillattr(dentry->d_inode, stat);
777 static int cifs_truncate_page(struct address_space *mapping, loff_t from)
779 pgoff_t index = from >> PAGE_CACHE_SHIFT;
780 unsigned offset = from & (PAGE_CACHE_SIZE-1);
785 page = grab_cache_page(mapping, index);
789 kaddr = kmap_atomic(page, KM_USER0);
790 memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
791 flush_dcache_page(page);
792 kunmap_atomic(kaddr, KM_USER0);
794 page_cache_release(page);
799 cifs_setattr(struct dentry *direntry, struct iattr *attrs)
802 struct cifs_sb_info *cifs_sb;
803 struct cifsTconInfo *pTcon;
804 char *full_path = NULL;
807 struct cifsFileInfo *open_file = NULL;
808 FILE_BASIC_INFO time_buf;
809 int set_time = FALSE;
810 __u64 mode = 0xFFFFFFFFFFFFFFFFULL;
811 __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
812 __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
813 struct cifsInodeInfo *cifsInode;
814 struct list_head * tmp;
819 (" In cifs_setattr, name = %s attrs->iavalid 0x%x ",
820 direntry->d_name.name, attrs->ia_valid));
821 cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
822 pTcon = cifs_sb->tcon;
824 down(&direntry->d_sb->s_vfs_rename_sem);
825 full_path = build_path_from_dentry(direntry);
826 up(&direntry->d_sb->s_vfs_rename_sem);
827 if(full_path == NULL) {
831 cifsInode = CIFS_I(direntry->d_inode);
833 /* BB check if we need to refresh inode from server now ? BB */
835 /* need to flush data before changing file size on server */
836 filemap_fdatawrite(direntry->d_inode->i_mapping);
837 filemap_fdatawait(direntry->d_inode->i_mapping);
839 if (attrs->ia_valid & ATTR_SIZE) {
840 read_lock(&GlobalSMBSeslock);
841 /* To avoid spurious oplock breaks from server, in the case
842 of inodes that we already have open, avoid doing path
843 based setting of file size if we can do it by handle.
844 This keeps our caching token (oplock) and avoids
845 timeouts when the local oplock break takes longer to flush
846 writebehind data than the SMB timeout for the SetPathInfo
847 request would allow */
848 list_for_each(tmp, &cifsInode->openFileList) {
849 open_file = list_entry(tmp,struct cifsFileInfo, flist);
850 /* We check if file is open for writing first */
851 if((open_file->pfile) &&
852 ((open_file->pfile->f_flags & O_RDWR) ||
853 (open_file->pfile->f_flags & O_WRONLY))) {
854 if(open_file->invalidHandle == FALSE) {
855 /* we found a valid, writeable network file
856 handle to use to try to set the file size */
857 __u16 nfid = open_file->netfid;
858 __u32 npid = open_file->pid;
859 read_unlock(&GlobalSMBSeslock);
861 rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
863 cFYI(1,("SetFileSize by handle (setattrs) rc = %d",rc));
864 /* Do not need reopen and retry on EAGAIN since we will
865 retry by pathname below */
867 break; /* now that we found one valid file handle no
868 sense continuing to loop trying others */
873 read_unlock(&GlobalSMBSeslock);
878 /* Set file size by pathname rather than by handle either
879 because no valid, writeable file handle for it was found or
880 because there was an error setting it by handle */
881 rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,FALSE,
883 cFYI(1,(" SetEOF by path (setattrs) rc = %d",rc));
886 /* Server is ok setting allocation size implicitly - no need to call: */
887 /*CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE, cifs_sb->local_nls);*/
890 rc = vmtruncate(direntry->d_inode, attrs->ia_size);
891 cifs_truncate_page(direntry->d_inode->i_mapping, direntry->d_inode->i_size);
894 if (attrs->ia_valid & ATTR_UID) {
895 cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid));
897 /* entry->uid = cpu_to_le16(attr->ia_uid); */
899 if (attrs->ia_valid & ATTR_GID) {
900 cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid));
902 /* entry->gid = cpu_to_le16(attr->ia_gid); */
905 time_buf.Attributes = 0;
906 if (attrs->ia_valid & ATTR_MODE) {
907 cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode));
908 mode = attrs->ia_mode;
909 /* entry->mode = cpu_to_le16(attr->ia_mode); */
912 if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
913 && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
914 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
915 0 /* dev_t */, cifs_sb->local_nls);
916 else if (attrs->ia_valid & ATTR_MODE) {
917 if((mode & S_IWUGO) == 0) /* not writeable */ {
918 if((cifsInode->cifsAttrs & ATTR_READONLY) == 0)
919 time_buf.Attributes =
920 cpu_to_le32(cifsInode->cifsAttrs | ATTR_READONLY);
921 } else if((mode & S_IWUGO) == S_IWUGO) {
922 if(cifsInode->cifsAttrs & ATTR_READONLY)
923 time_buf.Attributes =
924 cpu_to_le32(cifsInode->cifsAttrs & (~ATTR_READONLY));
926 /* BB to be implemented - via Windows security descriptors or streams */
927 /* CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,uid,gid,cifs_sb->local_nls);*/
930 if (attrs->ia_valid & ATTR_ATIME) {
932 time_buf.LastAccessTime =
933 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
935 time_buf.LastAccessTime = 0;
937 if (attrs->ia_valid & ATTR_MTIME) {
939 time_buf.LastWriteTime =
940 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
942 time_buf.LastWriteTime = 0;
944 if (attrs->ia_valid & ATTR_CTIME) {
946 cFYI(1, (" CIFS - CTIME changed ")); /* BB probably do not need */
947 time_buf.ChangeTime =
948 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
950 time_buf.ChangeTime = 0;
952 if (set_time | time_buf.Attributes) {
953 /* BB what if setting one attribute fails
954 (such as size) but time setting works */
955 time_buf.CreationTime = 0; /* do not change */
956 /* In the future we should experiment - try setting timestamps
957 via Handle (SetFileInfo) instead of by path */
958 rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
962 /* do not need local check to inode_check_ok since the server does that */
964 rc = inode_setattr(direntry->d_inode, attrs);
972 cifs_delete_inode(struct inode *inode)
974 cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode));
975 /* may have to add back in if and when safe distributed caching of
976 directories added e.g. via FindNotify */