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 CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
489 else { /* BB to be implemented via Windows secrty descriptors*/
490 /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
501 cifs_rmdir(struct inode *inode, struct dentry *direntry)
505 struct cifs_sb_info *cifs_sb;
506 struct cifsTconInfo *pTcon;
507 char *full_path = NULL;
508 struct cifsInodeInfo *cifsInode;
510 cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode));
514 cifs_sb = CIFS_SB(inode->i_sb);
515 pTcon = cifs_sb->tcon;
517 down(&inode->i_sb->s_vfs_rename_sem);
518 full_path = build_path_from_dentry(direntry);
519 up(&inode->i_sb->s_vfs_rename_sem);
520 if(full_path == NULL) {
525 rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls);
529 i_size_write(direntry->d_inode,0);
530 direntry->d_inode->i_nlink = 0;
533 cifsInode = CIFS_I(direntry->d_inode);
534 cifsInode->time = 0; /* force revalidate to go get info when needed */
535 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
545 cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
546 struct inode *target_inode, struct dentry *target_direntry)
550 struct cifs_sb_info *cifs_sb_source;
551 struct cifs_sb_info *cifs_sb_target;
552 struct cifsTconInfo *pTcon;
558 cifs_sb_target = CIFS_SB(target_inode->i_sb);
559 cifs_sb_source = CIFS_SB(source_inode->i_sb);
560 pTcon = cifs_sb_source->tcon;
562 if (pTcon != cifs_sb_target->tcon) {
564 return -EXDEV; /* BB actually could be allowed if same server, but
565 different share. Might eventually add support for this */
568 /* we already have the rename sem so we do not need
569 to grab it again here to protect the path integrity */
570 fromName = build_path_from_dentry(source_direntry);
571 toName = build_path_from_dentry(target_direntry);
572 if((fromName == NULL) || (toName == NULL)) {
574 goto cifs_rename_exit;
577 rc = CIFSSMBRename(xid, pTcon, fromName, toName,
578 cifs_sb_source->local_nls);
580 /* check if they are the same file
581 because rename of hardlinked files is a noop */
582 FILE_UNIX_BASIC_INFO * info_buf_source;
583 FILE_UNIX_BASIC_INFO * info_buf_target;
586 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),GFP_KERNEL);
587 if(info_buf_source != NULL) {
588 info_buf_target = info_buf_source+1;
589 rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
590 info_buf_source, cifs_sb_source->local_nls);
592 rc = CIFSSMBUnixQPathInfo(xid,pTcon,toName,
594 cifs_sb_target->local_nls);
597 (info_buf_source->UniqueId ==
598 info_buf_target->UniqueId)) {
599 /* do not rename since the files are hardlinked
602 /* we either can not tell the files are hardlinked
603 (as with Windows servers) or files are not hardlinked
604 so delete the target manually before renaming to
605 follow POSIX rather than Windows semantics */
606 cifs_unlink(target_inode, target_direntry);
607 rc = CIFSSMBRename(xid, pTcon, fromName, toName,
608 cifs_sb_source->local_nls);
610 kfree(info_buf_source);
611 } /* if we can not get memory just leave rc as EEXIST */
614 if((rc == -EIO)||(rc == -EEXIST)) {
618 rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
620 &netfid, &oplock, NULL, cifs_sb_source->local_nls);
622 CIFSSMBRenameOpenFile(xid,pTcon,netfid,
623 toName, cifs_sb_source->local_nls);
624 CIFSSMBClose(xid, pTcon, netfid);
639 cifs_revalidate(struct dentry *direntry)
644 struct cifs_sb_info *cifs_sb;
645 struct cifsInodeInfo *cifsInode;
647 struct timespec local_mtime;
648 int invalidate_inode = FALSE;
650 if(direntry->d_inode == NULL)
653 cifsInode = CIFS_I(direntry->d_inode);
655 if(cifsInode == NULL)
658 /* no sense revalidating inode info on file that no one can write */
659 if(CIFS_I(direntry->d_inode)->clientCanCacheRead)
664 cifs_sb = CIFS_SB(direntry->d_sb);
666 /* can not safely grab the rename sem here if
667 rename calls revalidate since that would deadlock */
668 full_path = build_path_from_dentry(direntry);
669 if(full_path == NULL) {
674 ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld",
675 full_path, direntry->d_inode,
676 direntry->d_inode->i_count.counter, direntry,
677 direntry->d_time, jiffies));
679 if (cifsInode->time == 0){
680 /* was set to zero previously to force revalidate */
681 } else if (time_before(jiffies, cifsInode->time + HZ) && lookupCacheEnabled) {
682 if((S_ISREG(direntry->d_inode->i_mode) == 0) ||
683 (direntry->d_inode->i_nlink == 1)) {
689 cFYI(1,("Have to revalidate file due to hardlinks"));
693 /* save mtime and size */
694 local_mtime = direntry->d_inode->i_mtime;
695 local_size = direntry->d_inode->i_size;
697 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
698 rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
701 cFYI(1,("error on getting revalidate info %d",rc));
703 rc = 0; */ /* BB should we cache info on certain errors? */
706 rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
709 cFYI(1,("error on getting revalidate info %d",rc));
711 rc = 0; */ /* BB should we cache info on certain errors? */
714 /* should we remap certain errors, access denied?, to zero */
716 /* if not oplocked, we invalidate inode pages if mtime
717 or file size had changed on server */
719 if(timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) &&
720 (local_size == direntry->d_inode->i_size)) {
721 cFYI(1,("cifs_revalidate - inode unchanged"));
723 /* file may have changed on server */
724 if(cifsInode->clientCanCacheRead) {
725 /* no need to invalidate inode pages since we were
726 the only ones who could have modified the file and
727 the server copy is staler than ours */
729 invalidate_inode = TRUE;
733 /* can not grab this sem since kernel filesys locking
734 documentation indicates i_sem may be taken by the kernel
735 on lookup and rename which could deadlock if we grab
736 the i_sem here as well */
737 /* down(&direntry->d_inode->i_sem);*/
738 /* need to write out dirty pages here */
739 if(direntry->d_inode->i_mapping) {
740 /* do we need to lock inode until after invalidate completes below? */
741 filemap_fdatawrite(direntry->d_inode->i_mapping);
743 if(invalidate_inode) {
744 filemap_fdatawait(direntry->d_inode->i_mapping);
745 /* may eventually have to do this for open files too */
746 if(list_empty(&(cifsInode->openFileList))) {
747 /* Has changed on server - flush read ahead pages */
748 cFYI(1,("Invalidating read ahead data on closed file"));
749 invalidate_remote_inode(direntry->d_inode);
752 /* up(&direntry->d_inode->i_sem);*/
761 int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
763 int err = cifs_revalidate(dentry);
765 generic_fillattr(dentry->d_inode, stat);
769 static int cifs_truncate_page(struct address_space *mapping, loff_t from)
771 pgoff_t index = from >> PAGE_CACHE_SHIFT;
772 unsigned offset = from & (PAGE_CACHE_SIZE-1);
777 page = grab_cache_page(mapping, index);
781 kaddr = kmap_atomic(page, KM_USER0);
782 memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
783 flush_dcache_page(page);
784 kunmap_atomic(kaddr, KM_USER0);
786 page_cache_release(page);
791 cifs_setattr(struct dentry *direntry, struct iattr *attrs)
794 struct cifs_sb_info *cifs_sb;
795 struct cifsTconInfo *pTcon;
796 char *full_path = NULL;
799 struct cifsFileInfo *open_file = NULL;
800 FILE_BASIC_INFO time_buf;
801 int set_time = FALSE;
802 __u64 mode = 0xFFFFFFFFFFFFFFFFULL;
803 __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
804 __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
805 struct cifsInodeInfo *cifsInode;
806 struct list_head * tmp;
811 (" In cifs_setattr, name = %s attrs->iavalid 0x%x ",
812 direntry->d_name.name, attrs->ia_valid));
813 cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
814 pTcon = cifs_sb->tcon;
816 down(&direntry->d_sb->s_vfs_rename_sem);
817 full_path = build_path_from_dentry(direntry);
818 up(&direntry->d_sb->s_vfs_rename_sem);
819 if(full_path == NULL) {
823 cifsInode = CIFS_I(direntry->d_inode);
825 /* BB check if we need to refresh inode from server now ? BB */
827 /* need to flush data before changing file size on server */
828 filemap_fdatawrite(direntry->d_inode->i_mapping);
829 filemap_fdatawait(direntry->d_inode->i_mapping);
831 if (attrs->ia_valid & ATTR_SIZE) {
832 read_lock(&GlobalSMBSeslock);
833 /* To avoid spurious oplock breaks from server, in the case
834 of inodes that we already have open, avoid doing path
835 based setting of file size if we can do it by handle.
836 This keeps our caching token (oplock) and avoids
837 timeouts when the local oplock break takes longer to flush
838 writebehind data than the SMB timeout for the SetPathInfo
839 request would allow */
840 list_for_each(tmp, &cifsInode->openFileList) {
841 open_file = list_entry(tmp,struct cifsFileInfo, flist);
842 /* We check if file is open for writing first */
843 if((open_file->pfile) &&
844 ((open_file->pfile->f_flags & O_RDWR) ||
845 (open_file->pfile->f_flags & O_WRONLY))) {
846 if(open_file->invalidHandle == FALSE) {
847 /* we found a valid, writeable network file
848 handle to use to try to set the file size */
849 __u16 nfid = open_file->netfid;
850 __u32 npid = open_file->pid;
851 read_unlock(&GlobalSMBSeslock);
853 rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
855 cFYI(1,("SetFileSize by handle (setattrs) rc = %d",rc));
856 /* Do not need reopen and retry on EAGAIN since we will
857 retry by pathname below */
859 break; /* now that we found one valid file handle no
860 sense continuing to loop trying others */
865 read_unlock(&GlobalSMBSeslock);
870 /* Set file size by pathname rather than by handle either
871 because no valid, writeable file handle for it was found or
872 because there was an error setting it by handle */
873 rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,FALSE,
875 cFYI(1,(" SetEOF by path (setattrs) rc = %d",rc));
878 /* Server is ok setting allocation size implicitly - no need to call: */
879 /*CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE, cifs_sb->local_nls);*/
882 rc = vmtruncate(direntry->d_inode, attrs->ia_size);
883 cifs_truncate_page(direntry->d_inode->i_mapping, direntry->d_inode->i_size);
886 if (attrs->ia_valid & ATTR_UID) {
887 cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid));
889 /* entry->uid = cpu_to_le16(attr->ia_uid); */
891 if (attrs->ia_valid & ATTR_GID) {
892 cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid));
894 /* entry->gid = cpu_to_le16(attr->ia_gid); */
897 time_buf.Attributes = 0;
898 if (attrs->ia_valid & ATTR_MODE) {
899 cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode));
900 mode = attrs->ia_mode;
901 /* entry->mode = cpu_to_le16(attr->ia_mode); */
904 if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
905 && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
906 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
907 0 /* dev_t */, cifs_sb->local_nls);
908 else if (attrs->ia_valid & ATTR_MODE) {
909 if((mode & S_IWUGO) == 0) /* not writeable */ {
910 if((cifsInode->cifsAttrs & ATTR_READONLY) == 0)
911 time_buf.Attributes =
912 cpu_to_le32(cifsInode->cifsAttrs | ATTR_READONLY);
913 } else if((mode & S_IWUGO) == S_IWUGO) {
914 if(cifsInode->cifsAttrs & ATTR_READONLY)
915 time_buf.Attributes =
916 cpu_to_le32(cifsInode->cifsAttrs & (~ATTR_READONLY));
918 /* BB to be implemented - via Windows security descriptors or streams */
919 /* CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,uid,gid,cifs_sb->local_nls);*/
922 if (attrs->ia_valid & ATTR_ATIME) {
924 time_buf.LastAccessTime =
925 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
927 time_buf.LastAccessTime = 0;
929 if (attrs->ia_valid & ATTR_MTIME) {
931 time_buf.LastWriteTime =
932 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
934 time_buf.LastWriteTime = 0;
936 if (attrs->ia_valid & ATTR_CTIME) {
938 cFYI(1, (" CIFS - CTIME changed ")); /* BB probably do not need */
939 time_buf.ChangeTime =
940 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
942 time_buf.ChangeTime = 0;
944 if (set_time | time_buf.Attributes) {
945 /* BB what if setting one attribute fails
946 (such as size) but time setting works */
947 time_buf.CreationTime = 0; /* do not change */
948 /* In the future we should experiment - try setting timestamps
949 via Handle (SetFileInfo) instead of by path */
950 rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
954 /* do not need local check to inode_check_ok since the server does that */
956 rc = inode_setattr(direntry->d_inode, attrs);
964 cifs_delete_inode(struct inode *inode)
966 cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode));
967 /* may have to add back in if and when safe distributed caching of
968 directories added e.g. via FindNotify */