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"
34 cifs_get_inode_info_unix(struct inode **pinode,
35 const unsigned char *search_path,
36 struct super_block *sb)
40 FILE_UNIX_BASIC_INFO findData;
41 struct cifsTconInfo *pTcon;
43 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
46 /* BB add caching check so we do not go to server to overwrite inode info to cached file
47 where the local file sizes are correct and the server info is stale BB */
51 pTcon = cifs_sb->tcon;
52 cFYI(1, (" Getting info on %s ", search_path));
53 /* we could have done a find first instead but this returns more info */
54 rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
56 /* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */
63 strnlen(search_path, MAX_PATHCONF) + 1,
65 if (tmp_path == NULL) {
69 /* have to skip first of the double backslash of UNC name */
70 strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
71 strncat(tmp_path, search_path, MAX_PATHCONF);
72 rc = connect_to_dfs_path(xid, pTcon->ses,
73 /* treename + */ tmp_path,
77 /* BB fix up inode etc. */
84 struct cifsInodeInfo *cifsInfo;
87 if (*pinode == NULL) {
88 *pinode = new_inode(sb);
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 */
100 cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime));
102 cifs_NTtimeToUnix(le64_to_cpu
103 (findData.LastModificationTime));
105 cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange));
106 inode->i_mode = le64_to_cpu(findData.Permissions);
107 findData.Type = le32_to_cpu(findData.Type);
108 if (findData.Type == UNIX_FILE) {
109 inode->i_mode |= S_IFREG;
110 } else if (findData.Type == UNIX_SYMLINK) {
111 inode->i_mode |= S_IFLNK;
112 } else if (findData.Type == UNIX_DIR) {
113 inode->i_mode |= S_IFDIR;
114 } else if (findData.Type == UNIX_CHARDEV) {
115 inode->i_mode |= S_IFCHR;
116 } else if (findData.Type == UNIX_BLOCKDEV) {
117 inode->i_mode |= S_IFBLK;
118 } else if (findData.Type == UNIX_FIFO) {
119 inode->i_mode |= S_IFIFO;
120 } else if (findData.Type == UNIX_SOCKET) {
121 inode->i_mode |= S_IFSOCK;
123 inode->i_uid = le64_to_cpu(findData.Uid);
124 inode->i_gid = le64_to_cpu(findData.Gid);
125 inode->i_nlink = le64_to_cpu(findData.Nlinks);
126 findData.NumOfBytes = le64_to_cpu(findData.NumOfBytes);
127 findData.EndOfFile = le64_to_cpu(findData.EndOfFile);
128 i_size_write(inode,findData.EndOfFile);
129 /* blksize needs to be multiple of two. So safer to default to blksize
130 and blkbits set in superblock so 2**blkbits and blksize will match */
131 /* inode->i_blksize =
132 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
134 (inode->i_blksize - 1 + findData.NumOfBytes) >> inode->i_blkbits;
136 if (findData.NumOfBytes < findData.EndOfFile)
137 cFYI(1, ("Server inconsistency Error: it says allocation size less than end of file "));
139 ("Size %ld and blocks %ld ",
140 (unsigned long) inode->i_size, inode->i_blocks));
141 if (S_ISREG(inode->i_mode)) {
142 cFYI(1, (" File inode "));
143 inode->i_op = &cifs_file_inode_ops;
144 inode->i_fop = &cifs_file_ops;
145 inode->i_data.a_ops = &cifs_addr_ops;
146 } else if (S_ISDIR(inode->i_mode)) {
147 cFYI(1, (" Directory inode"));
148 inode->i_op = &cifs_dir_inode_ops;
149 inode->i_fop = &cifs_dir_ops;
150 } else if (S_ISLNK(inode->i_mode)) {
151 cFYI(1, (" Symbolic Link inode "));
152 inode->i_op = &cifs_symlink_inode_ops;
153 /* tmp_inode->i_fop = *//* do not need to set to anything */
155 cFYI(1, (" Init special inode "));
156 init_special_inode(inode, inode->i_mode,
165 cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
166 FILE_ALL_INFO * pfindData, struct super_block *sb)
170 struct cifsTconInfo *pTcon;
172 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
178 pTcon = cifs_sb->tcon;
179 cFYI(1,("Getting info on %s ", search_path));
181 if((pfindData == NULL) && (*pinode != NULL)) {
182 if(CIFS_I(*pinode)->clientCanCacheRead) {
183 cFYI(1,("No need to revalidate inode sizes on cached file "));
189 /* if file info not passed in then get it from server */
190 if(pfindData == NULL) {
191 buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
192 pfindData = (FILE_ALL_INFO *)buf;
193 /* could do find first instead but this returns more info */
194 rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
197 /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
199 if (rc == -EREMOTE) {
204 strnlen(search_path, MAX_PATHCONF) + 1,
206 if (tmp_path == NULL) {
213 strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
214 strncat(tmp_path, search_path, MAX_PATHCONF);
215 rc = connect_to_dfs_path(xid, pTcon->ses,
216 /* treename + */ tmp_path,
219 /* BB fix up inode etc. */
227 struct cifsInodeInfo *cifsInfo;
230 if (*pinode == NULL) {
231 *pinode = new_inode(sb);
235 cifsInfo = CIFS_I(inode);
236 pfindData->Attributes = le32_to_cpu(pfindData->Attributes);
237 cifsInfo->cifsAttrs = pfindData->Attributes;
238 cFYI(1, (" Old time %ld ", cifsInfo->time));
239 cifsInfo->time = jiffies;
240 cFYI(1, (" New time %ld ", cifsInfo->time));
242 /* blksize needs to be multiple of two. So safer to default to blksize
243 and blkbits set in superblock so 2**blkbits and blksize will match */
244 /* inode->i_blksize =
245 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
247 /* Linux can not store file creation time unfortunately so we ignore it */
249 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
251 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
253 cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
255 (" Attributes came in as 0x%x ", pfindData->Attributes));
257 /* set default mode. will override for dirs below */
258 if(atomic_read(&cifsInfo->inUse) == 0)
259 /* new inode, can safely set these fields */
260 inode->i_mode = cifs_sb->mnt_file_mode;
262 if (pfindData->Attributes & ATTR_REPARSE) {
263 /* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */
264 inode->i_mode |= S_IFLNK;
265 } else if (pfindData->Attributes & ATTR_DIRECTORY) {
266 /* override default perms since we do not do byte range locking on dirs */
267 inode->i_mode = cifs_sb->mnt_dir_mode;
268 inode->i_mode |= S_IFDIR;
270 inode->i_mode |= S_IFREG;
271 /* treat the dos attribute of read-only as read-only mode e.g. 555 */
272 if(cifsInfo->cifsAttrs & ATTR_READONLY)
273 inode->i_mode &= ~(S_IWUGO);
274 /* BB add code here - validate if device or weird share or device type? */
276 i_size_write(inode,le64_to_cpu(pfindData->EndOfFile));
277 pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize);
279 (inode->i_blksize - 1 + pfindData->AllocationSize) >> inode->i_blkbits;
281 inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
283 /* BB fill in uid and gid here? with help from winbind?
284 or retrieve from NTFS stream extended attribute */
285 if(atomic_read(&cifsInfo->inUse) == 0) {
286 inode->i_uid = cifs_sb->mnt_uid;
287 inode->i_gid = cifs_sb->mnt_gid;
288 /* set so we do not keep refreshing these fields with
289 bad data after user has changed them in memory */
290 atomic_set(&cifsInfo->inUse,1);
293 if (S_ISREG(inode->i_mode)) {
294 cFYI(1, (" File inode "));
295 inode->i_op = &cifs_file_inode_ops;
296 inode->i_fop = &cifs_file_ops;
297 inode->i_data.a_ops = &cifs_addr_ops;
298 } else if (S_ISDIR(inode->i_mode)) {
299 cFYI(1, (" Directory inode "));
300 inode->i_op = &cifs_dir_inode_ops;
301 inode->i_fop = &cifs_dir_ops;
302 } else if (S_ISLNK(inode->i_mode)) {
303 cFYI(1, (" Symbolic Link inode "));
304 inode->i_op = &cifs_symlink_inode_ops;
306 init_special_inode(inode, inode->i_mode,
317 cifs_read_inode(struct inode *inode)
318 { /* gets root inode */
320 struct cifs_sb_info *cifs_sb;
322 cifs_sb = CIFS_SB(inode->i_sb);
324 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
325 cifs_get_inode_info_unix(&inode, "", inode->i_sb);
327 cifs_get_inode_info(&inode, "", NULL, inode->i_sb);
331 cifs_unlink(struct inode *inode, struct dentry *direntry)
335 struct cifs_sb_info *cifs_sb;
336 struct cifsTconInfo *pTcon;
337 char *full_path = NULL;
338 struct cifsInodeInfo *cifsInode;
339 FILE_BASIC_INFO * pinfo_buf;
341 cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode));
345 cifs_sb = CIFS_SB(inode->i_sb);
346 pTcon = cifs_sb->tcon;
348 /* Unlink can be called from rename so we can not grab
349 the sem here since we deadlock otherwise */
350 /* down(&direntry->d_sb->s_vfs_rename_sem);*/
351 full_path = build_path_from_dentry(direntry);
352 /* up(&direntry->d_sb->s_vfs_rename_sem);*/
353 if(full_path == NULL) {
357 rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
360 direntry->d_inode->i_nlink--;
361 } else if (rc == -ENOENT) {
363 } else if (rc == -ETXTBSY) {
367 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
368 CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
369 &netfid, &oplock, NULL, cifs_sb->local_nls);
371 CIFSSMBRenameOpenFile(xid,pTcon,netfid,
372 NULL, cifs_sb->local_nls);
373 CIFSSMBClose(xid, pTcon, netfid);
374 direntry->d_inode->i_nlink--;
376 } else if (rc == -EACCES) {
377 /* try only if r/o attribute set in local lookup data? */
378 pinfo_buf = (FILE_BASIC_INFO *)kmalloc(sizeof(FILE_BASIC_INFO),GFP_KERNEL);
380 memset(pinfo_buf,0,sizeof(FILE_BASIC_INFO));
381 /* ATTRS set to normal clears r/o bit */
382 pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
383 rc = CIFSSMBSetTimes(xid, pTcon, full_path, pinfo_buf,
388 rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
390 direntry->d_inode->i_nlink--;
391 } else if (rc == -ETXTBSY) {
395 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
396 CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
397 &netfid, &oplock, NULL, cifs_sb->local_nls);
399 CIFSSMBRenameOpenFile(xid,pTcon,netfid,NULL,cifs_sb->local_nls);
400 CIFSSMBClose(xid, pTcon, netfid);
401 direntry->d_inode->i_nlink--;
403 /* BB if rc = -ETXTBUSY goto the rename logic BB */
407 cifsInode = CIFS_I(direntry->d_inode);
408 cifsInode->time = 0; /* will force revalidate to get info when needed */
409 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
411 cifsInode = CIFS_I(inode);
412 cifsInode->time = 0; /* force revalidate of dir as well */
421 cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
425 struct cifs_sb_info *cifs_sb;
426 struct cifsTconInfo *pTcon;
427 char *full_path = NULL;
428 struct inode *newinode = NULL;
430 cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode));
434 cifs_sb = CIFS_SB(inode->i_sb);
435 pTcon = cifs_sb->tcon;
437 down(&inode->i_sb->s_vfs_rename_sem);
438 full_path = build_path_from_dentry(direntry);
439 up(&inode->i_sb->s_vfs_rename_sem);
440 if(full_path == NULL) {
444 /* BB add setting the equivalent of mode via CreateX w/ACLs */
445 rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls);
447 cFYI(1, ("cifs_mkdir returned 0x%x ", rc));
451 if (pTcon->ses->capabilities & CAP_UNIX)
452 rc = cifs_get_inode_info_unix(&newinode, full_path,
455 rc = cifs_get_inode_info(&newinode, full_path,NULL,
458 direntry->d_op = &cifs_dentry_ops;
459 d_instantiate(direntry, newinode);
460 if(direntry->d_inode)
461 direntry->d_inode->i_nlink = 2;
462 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
463 CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
468 else { /* BB to be implemented via Windows secrty descriptors*/
469 /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
480 cifs_rmdir(struct inode *inode, struct dentry *direntry)
484 struct cifs_sb_info *cifs_sb;
485 struct cifsTconInfo *pTcon;
486 char *full_path = NULL;
487 struct cifsInodeInfo *cifsInode;
489 cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode));
493 cifs_sb = CIFS_SB(inode->i_sb);
494 pTcon = cifs_sb->tcon;
496 down(&inode->i_sb->s_vfs_rename_sem);
497 full_path = build_path_from_dentry(direntry);
498 up(&inode->i_sb->s_vfs_rename_sem);
499 if(full_path == NULL) {
504 rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls);
508 i_size_write(direntry->d_inode,0);
509 direntry->d_inode->i_nlink = 0;
512 cifsInode = CIFS_I(direntry->d_inode);
513 cifsInode->time = 0; /* force revalidate to go get info when needed */
514 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
524 cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
525 struct inode *target_inode, struct dentry *target_direntry)
529 struct cifs_sb_info *cifs_sb_source;
530 struct cifs_sb_info *cifs_sb_target;
531 struct cifsTconInfo *pTcon;
537 cifs_sb_target = CIFS_SB(target_inode->i_sb);
538 cifs_sb_source = CIFS_SB(source_inode->i_sb);
539 pTcon = cifs_sb_source->tcon;
541 if (pTcon != cifs_sb_target->tcon) {
543 return -EXDEV; /* BB actually could be allowed if same server, but
544 different share. Might eventually add support for this */
547 /* we already have the rename sem so we do not need
548 to grab it again here to protect the path integrity */
549 fromName = build_path_from_dentry(source_direntry);
550 toName = build_path_from_dentry(target_direntry);
551 if((fromName == NULL) || (toName == NULL)) {
553 goto cifs_rename_exit;
556 rc = CIFSSMBRename(xid, pTcon, fromName, toName,
557 cifs_sb_source->local_nls);
559 cifs_unlink(target_inode, target_direntry);
560 rc = CIFSSMBRename(xid, pTcon, fromName, toName,
561 cifs_sb_source->local_nls);
564 if((rc == -EIO)||(rc == -EEXIST)) {
568 rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
570 &netfid, &oplock, NULL, cifs_sb_source->local_nls);
572 CIFSSMBRenameOpenFile(xid,pTcon,netfid,
573 toName, cifs_sb_source->local_nls);
574 CIFSSMBClose(xid, pTcon, netfid);
589 cifs_revalidate(struct dentry *direntry)
594 struct cifs_sb_info *cifs_sb;
595 struct cifsInodeInfo *cifsInode;
597 struct timespec local_mtime;
598 int invalidate_inode = FALSE;
600 if(direntry->d_inode == NULL)
603 cifsInode = CIFS_I(direntry->d_inode);
605 if(cifsInode == NULL)
608 /* no sense revalidating inode info on file that no one can write */
609 if(CIFS_I(direntry->d_inode)->clientCanCacheRead)
614 cifs_sb = CIFS_SB(direntry->d_sb);
616 /* can not safely grab the rename sem here if
617 rename calls revalidate since that would deadlock */
618 full_path = build_path_from_dentry(direntry);
619 if(full_path == NULL) {
624 ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld",
625 full_path, direntry->d_inode,
626 direntry->d_inode->i_count.counter, direntry,
627 direntry->d_time, jiffies));
629 if (cifsInode->time == 0){
630 /* was set to zero previously to force revalidate */
631 } else if (time_before(jiffies, cifsInode->time + HZ) && lookupCacheEnabled) {
632 if((S_ISREG(direntry->d_inode->i_mode) == 0) ||
633 (direntry->d_inode->i_nlink == 1)) {
639 cFYI(1,("Have to revalidate file due to hardlinks"));
643 /* save mtime and size */
644 local_mtime = direntry->d_inode->i_mtime;
645 local_size = direntry->d_inode->i_size;
647 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
648 rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
651 cFYI(1,("error on getting revalidate info %d",rc));
653 rc = 0; */ /* BB should we cache info on certain errors? */
656 rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
659 cFYI(1,("error on getting revalidate info %d",rc));
661 rc = 0; */ /* BB should we cache info on certain errors? */
664 /* should we remap certain errors, access denied?, to zero */
666 /* if not oplocked, we invalidate inode pages if mtime
667 or file size had changed on server */
669 if(timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) &&
670 (local_size == direntry->d_inode->i_size)) {
671 cFYI(1,("cifs_revalidate - inode unchanged"));
673 /* file may have changed on server */
674 if(cifsInode->clientCanCacheRead) {
675 /* no need to invalidate inode pages since we were
676 the only ones who could have modified the file and
677 the server copy is staler than ours */
679 invalidate_inode = TRUE;
683 /* can not grab this sem since kernel filesys locking
684 documentation indicates i_sem may be taken by the kernel
685 on lookup and rename which could deadlock if we grab
686 the i_sem here as well */
687 /* down(&direntry->d_inode->i_sem);*/
688 /* need to write out dirty pages here */
689 if(direntry->d_inode->i_mapping) {
690 /* do we need to lock inode until after invalidate completes below? */
691 filemap_fdatawrite(direntry->d_inode->i_mapping);
693 if(invalidate_inode) {
694 filemap_fdatawait(direntry->d_inode->i_mapping);
695 /* may eventually have to do this for open files too */
696 if(list_empty(&(cifsInode->openFileList))) {
697 /* Has changed on server - flush read ahead pages */
698 cFYI(1,("Invalidating read ahead data on closed file"));
699 invalidate_remote_inode(direntry->d_inode);
702 /* up(&direntry->d_inode->i_sem);*/
711 int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
713 int err = cifs_revalidate(dentry);
715 generic_fillattr(dentry->d_inode, stat);
719 static int cifs_truncate_page(struct address_space *mapping, loff_t from)
721 pgoff_t index = from >> PAGE_CACHE_SHIFT;
722 unsigned offset = from & (PAGE_CACHE_SIZE-1);
727 page = grab_cache_page(mapping, index);
731 kaddr = kmap_atomic(page, KM_USER0);
732 memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
733 flush_dcache_page(page);
734 kunmap_atomic(kaddr, KM_USER0);
736 page_cache_release(page);
741 cifs_setattr(struct dentry *direntry, struct iattr *attrs)
744 struct cifs_sb_info *cifs_sb;
745 struct cifsTconInfo *pTcon;
746 char *full_path = NULL;
749 struct cifsFileInfo *open_file = NULL;
750 FILE_BASIC_INFO time_buf;
751 int set_time = FALSE;
752 __u64 mode = 0xFFFFFFFFFFFFFFFFULL;
753 __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
754 __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
755 struct cifsInodeInfo *cifsInode;
756 struct list_head * tmp;
761 (" In cifs_setattr, name = %s attrs->iavalid 0x%x ",
762 direntry->d_name.name, attrs->ia_valid));
763 cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
764 pTcon = cifs_sb->tcon;
766 down(&direntry->d_sb->s_vfs_rename_sem);
767 full_path = build_path_from_dentry(direntry);
768 up(&direntry->d_sb->s_vfs_rename_sem);
769 if(full_path == NULL) {
773 cifsInode = CIFS_I(direntry->d_inode);
775 /* BB check if we need to refresh inode from server now ? BB */
777 /* need to flush data before changing file size on server */
778 filemap_fdatawrite(direntry->d_inode->i_mapping);
779 filemap_fdatawait(direntry->d_inode->i_mapping);
781 if (attrs->ia_valid & ATTR_SIZE) {
782 read_lock(&GlobalSMBSeslock);
783 /* To avoid spurious oplock breaks from server, in the case
784 of inodes that we already have open, avoid doing path
785 based setting of file size if we can do it by handle.
786 This keeps our caching token (oplock) and avoids
787 timeouts when the local oplock break takes longer to flush
788 writebehind data than the SMB timeout for the SetPathInfo
789 request would allow */
790 list_for_each(tmp, &cifsInode->openFileList) {
791 open_file = list_entry(tmp,struct cifsFileInfo, flist);
792 /* We check if file is open for writing first */
793 if((open_file->pfile) &&
794 ((open_file->pfile->f_flags & O_RDWR) ||
795 (open_file->pfile->f_flags & O_WRONLY))) {
796 if(open_file->invalidHandle == FALSE) {
797 /* we found a valid, writeable network file
798 handle to use to try to set the file size */
799 __u16 nfid = open_file->netfid;
800 __u32 npid = open_file->pid;
801 read_unlock(&GlobalSMBSeslock);
803 rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
805 cFYI(1,("SetFileSize by handle (setattrs) rc = %d",rc));
806 /* Do not need reopen and retry on EAGAIN since we will
807 retry by pathname below */
809 break; /* now that we found one valid file handle no
810 sense continuing to loop trying others */
815 read_unlock(&GlobalSMBSeslock);
820 /* Set file size by pathname rather than by handle either
821 because no valid, writeable file handle for it was found or
822 because there was an error setting it by handle */
823 rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,FALSE,
825 cFYI(1,(" SetEOF by path (setattrs) rc = %d",rc));
828 /* Server is ok setting allocation size implicitly - no need to call: */
829 /*CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE, cifs_sb->local_nls);*/
832 rc = vmtruncate(direntry->d_inode, attrs->ia_size);
833 cifs_truncate_page(direntry->d_inode->i_mapping, direntry->d_inode->i_size);
836 if (attrs->ia_valid & ATTR_UID) {
837 cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid));
839 /* entry->uid = cpu_to_le16(attr->ia_uid); */
841 if (attrs->ia_valid & ATTR_GID) {
842 cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid));
844 /* entry->gid = cpu_to_le16(attr->ia_gid); */
847 time_buf.Attributes = 0;
848 if (attrs->ia_valid & ATTR_MODE) {
849 cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode));
850 mode = attrs->ia_mode;
851 /* entry->mode = cpu_to_le16(attr->ia_mode); */
854 if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
855 && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
856 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
857 0 /* dev_t */, cifs_sb->local_nls);
858 else if (attrs->ia_valid & ATTR_MODE) {
859 if((mode & S_IWUGO) == 0) /* not writeable */ {
860 if((cifsInode->cifsAttrs & ATTR_READONLY) == 0)
861 time_buf.Attributes =
862 cpu_to_le32(cifsInode->cifsAttrs | ATTR_READONLY);
863 } else if((mode & S_IWUGO) == S_IWUGO) {
864 if(cifsInode->cifsAttrs & ATTR_READONLY)
865 time_buf.Attributes =
866 cpu_to_le32(cifsInode->cifsAttrs & (~ATTR_READONLY));
868 /* BB to be implemented - via Windows security descriptors or streams */
869 /* CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,uid,gid,cifs_sb->local_nls);*/
872 if (attrs->ia_valid & ATTR_ATIME) {
874 time_buf.LastAccessTime =
875 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
877 time_buf.LastAccessTime = 0;
879 if (attrs->ia_valid & ATTR_MTIME) {
881 time_buf.LastWriteTime =
882 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
884 time_buf.LastWriteTime = 0;
886 if (attrs->ia_valid & ATTR_CTIME) {
888 cFYI(1, (" CIFS - CTIME changed ")); /* BB probably do not need */
889 time_buf.ChangeTime =
890 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
892 time_buf.ChangeTime = 0;
894 if (set_time | time_buf.Attributes) {
895 /* BB what if setting one attribute fails
896 (such as size) but time setting works */
897 time_buf.CreationTime = 0; /* do not change */
898 /* In the future we should experiment - try setting timestamps
899 via Handle (SetFileInfo) instead of by path */
900 rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
904 /* do not need local check to inode_check_ok since the server does that */
905 inode_setattr(direntry->d_inode, attrs);
913 cifs_delete_inode(struct inode *inode)
915 cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode));
916 /* may have to add back in if and when safe distributed caching of
917 directories added e.g. via FindNotify */