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)
42 FILE_UNIX_BASIC_INFO findData;
43 struct cifsTconInfo *pTcon;
45 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
50 pTcon = cifs_sb->tcon;
51 cFYI(1, (" Getting info on %s ", search_path));
52 /* we could have done a find first instead but this returns more info */
53 rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
55 /* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */
62 strnlen(search_path, MAX_PATHCONF) + 1,
64 if (tmp_path == NULL) {
68 /* have to skip first of the double backslash of UNC name */
69 strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
70 strncat(tmp_path, search_path, MAX_PATHCONF);
71 rc = connect_to_dfs_path(xid, pTcon->ses,
72 /* treename + */ tmp_path,
76 /* BB fix up inode etc. */
83 struct cifsInodeInfo *cifsInfo;
86 if (*pinode == NULL) {
87 *pinode = new_inode(sb);
91 cifsInfo = CIFS_I(inode);
93 cFYI(1, (" Old time %ld ", cifsInfo->time));
94 cifsInfo->time = jiffies;
95 cFYI(1, (" New time %ld ", cifsInfo->time));
96 atomic_set(&cifsInfo->inUse,1); /* ok to set on every refresh of inode */
99 cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime));
101 cifs_NTtimeToUnix(le64_to_cpu
102 (findData.LastModificationTime));
104 cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange));
105 inode->i_mode = le64_to_cpu(findData.Permissions);
106 findData.Type = le32_to_cpu(findData.Type);
107 if (findData.Type == UNIX_FILE) {
108 inode->i_mode |= S_IFREG;
109 } else if (findData.Type == UNIX_SYMLINK) {
110 inode->i_mode |= S_IFLNK;
111 } else if (findData.Type == UNIX_DIR) {
112 inode->i_mode |= S_IFDIR;
113 } else if (findData.Type == UNIX_CHARDEV) {
114 inode->i_mode |= S_IFCHR;
115 } else if (findData.Type == UNIX_BLOCKDEV) {
116 inode->i_mode |= S_IFBLK;
117 } else if (findData.Type == UNIX_FIFO) {
118 inode->i_mode |= S_IFIFO;
119 } else if (findData.Type == UNIX_SOCKET) {
120 inode->i_mode |= S_IFSOCK;
122 inode->i_uid = le64_to_cpu(findData.Uid);
123 inode->i_gid = le64_to_cpu(findData.Gid);
124 inode->i_nlink = le64_to_cpu(findData.Nlinks);
125 findData.NumOfBytes = le64_to_cpu(findData.NumOfBytes);
126 findData.EndOfFile = le64_to_cpu(findData.EndOfFile);
128 if(is_size_safe_to_change(cifsInfo)) {
129 /* can not safely change the file size here if the
130 client is writing to it due to potential races */
132 i_size_write(inode,findData.EndOfFile);
133 /* blksize needs to be multiple of two. So safer to default to blksize
134 and blkbits set in superblock so 2**blkbits and blksize will match */
135 /* inode->i_blksize =
136 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
138 /* This seems incredibly stupid but it turns out that
139 i_blocks is not related to (i_size / i_blksize), instead a
140 size of 512 is required to be used for calculating num blocks */
144 (inode->i_blksize - 1 + findData.NumOfBytes) >> inode->i_blkbits;*/
146 /* 512 bytes (2**9) is the fake blocksize that must be used */
147 /* for this calculation */
148 inode->i_blocks = (512 - 1 + findData.NumOfBytes) >> 9;
151 if (findData.NumOfBytes < findData.EndOfFile)
152 cFYI(1, ("Server inconsistency Error: it says allocation size less than end of file "));
154 ("Size %ld and blocks %ld ",
155 (unsigned long) inode->i_size, inode->i_blocks));
156 if (S_ISREG(inode->i_mode)) {
157 cFYI(1, (" File inode "));
158 inode->i_op = &cifs_file_inode_ops;
159 inode->i_fop = &cifs_file_ops;
160 inode->i_data.a_ops = &cifs_addr_ops;
161 } else if (S_ISDIR(inode->i_mode)) {
162 cFYI(1, (" Directory inode"));
163 inode->i_op = &cifs_dir_inode_ops;
164 inode->i_fop = &cifs_dir_ops;
165 } else if (S_ISLNK(inode->i_mode)) {
166 cFYI(1, (" Symbolic Link inode "));
167 inode->i_op = &cifs_symlink_inode_ops;
168 /* tmp_inode->i_fop = *//* do not need to set to anything */
170 cFYI(1, (" Init special inode "));
171 init_special_inode(inode, inode->i_mode,
180 cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path,
181 FILE_ALL_INFO * pfindData, struct super_block *sb)
185 struct cifsTconInfo *pTcon;
187 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
193 pTcon = cifs_sb->tcon;
194 cFYI(1,("Getting info on %s ", search_path));
196 if((pfindData == NULL) && (*pinode != NULL)) {
197 if(CIFS_I(*pinode)->clientCanCacheRead) {
198 cFYI(1,("No need to revalidate inode sizes on cached file "));
204 /* if file info not passed in then get it from server */
205 if(pfindData == NULL) {
206 buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
207 pfindData = (FILE_ALL_INFO *)buf;
208 /* could do find first instead but this returns more info */
209 rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
212 /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
214 if (rc == -EREMOTE) {
219 strnlen(search_path, MAX_PATHCONF) + 1,
221 if (tmp_path == NULL) {
228 strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
229 strncat(tmp_path, search_path, MAX_PATHCONF);
230 rc = connect_to_dfs_path(xid, pTcon->ses,
231 /* treename + */ tmp_path,
234 /* BB fix up inode etc. */
242 struct cifsInodeInfo *cifsInfo;
245 if (*pinode == NULL) {
246 *pinode = new_inode(sb);
250 cifsInfo = CIFS_I(inode);
251 pfindData->Attributes = le32_to_cpu(pfindData->Attributes);
252 cifsInfo->cifsAttrs = pfindData->Attributes;
253 cFYI(1, (" Old time %ld ", cifsInfo->time));
254 cifsInfo->time = jiffies;
255 cFYI(1, (" New time %ld ", cifsInfo->time));
257 /* blksize needs to be multiple of two. So safer to default to blksize
258 and blkbits set in superblock so 2**blkbits and blksize will match */
259 /* inode->i_blksize =
260 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
262 /* Linux can not store file creation time unfortunately so we ignore it */
264 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
266 cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
268 cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
270 (" Attributes came in as 0x%x ", pfindData->Attributes));
272 /* set default mode. will override for dirs below */
273 if(atomic_read(&cifsInfo->inUse) == 0)
274 /* new inode, can safely set these fields */
275 inode->i_mode = cifs_sb->mnt_file_mode;
277 if (pfindData->Attributes & ATTR_REPARSE) {
278 /* Can IFLNK be set as it basically is on windows with IFREG or IFDIR? */
279 inode->i_mode |= S_IFLNK;
280 } else if (pfindData->Attributes & ATTR_DIRECTORY) {
281 /* override default perms since we do not do byte range locking on dirs */
282 inode->i_mode = cifs_sb->mnt_dir_mode;
283 inode->i_mode |= S_IFDIR;
285 inode->i_mode |= S_IFREG;
286 /* treat the dos attribute of read-only as read-only mode e.g. 555 */
287 if(cifsInfo->cifsAttrs & ATTR_READONLY)
288 inode->i_mode &= ~(S_IWUGO);
289 /* BB add code here - validate if device or weird share or device type? */
291 if(is_size_safe_to_change(cifsInfo)) {
292 /* can not safely change the file size here if the
293 client is writing to it due to potential races */
295 i_size_write(inode,le64_to_cpu(pfindData->EndOfFile));
297 /* 512 bytes (2**9) is the fake blocksize that must be used */
298 /* for this calculation */
299 inode->i_blocks = (512 - 1 + pfindData->AllocationSize)
302 pfindData->AllocationSize = le64_to_cpu(pfindData->AllocationSize);
304 inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
306 /* BB fill in uid and gid here? with help from winbind?
307 or retrieve from NTFS stream extended attribute */
308 if(atomic_read(&cifsInfo->inUse) == 0) {
309 inode->i_uid = cifs_sb->mnt_uid;
310 inode->i_gid = cifs_sb->mnt_gid;
311 /* set so we do not keep refreshing these fields with
312 bad data after user has changed them in memory */
313 atomic_set(&cifsInfo->inUse,1);
316 if (S_ISREG(inode->i_mode)) {
317 cFYI(1, (" File inode "));
318 inode->i_op = &cifs_file_inode_ops;
319 inode->i_fop = &cifs_file_ops;
320 inode->i_data.a_ops = &cifs_addr_ops;
321 } else if (S_ISDIR(inode->i_mode)) {
322 cFYI(1, (" Directory inode "));
323 inode->i_op = &cifs_dir_inode_ops;
324 inode->i_fop = &cifs_dir_ops;
325 } else if (S_ISLNK(inode->i_mode)) {
326 cFYI(1, (" Symbolic Link inode "));
327 inode->i_op = &cifs_symlink_inode_ops;
329 init_special_inode(inode, inode->i_mode,
340 cifs_read_inode(struct inode *inode)
341 { /* gets root inode */
343 struct cifs_sb_info *cifs_sb;
345 cifs_sb = CIFS_SB(inode->i_sb);
347 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
348 cifs_get_inode_info_unix(&inode, "", inode->i_sb);
350 cifs_get_inode_info(&inode, "", NULL, inode->i_sb);
354 cifs_unlink(struct inode *inode, struct dentry *direntry)
358 struct cifs_sb_info *cifs_sb;
359 struct cifsTconInfo *pTcon;
360 char *full_path = NULL;
361 struct cifsInodeInfo *cifsInode;
362 FILE_BASIC_INFO * pinfo_buf;
364 cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode));
368 cifs_sb = CIFS_SB(inode->i_sb);
369 pTcon = cifs_sb->tcon;
371 /* Unlink can be called from rename so we can not grab
372 the sem here since we deadlock otherwise */
373 /* down(&direntry->d_sb->s_vfs_rename_sem);*/
374 full_path = build_path_from_dentry(direntry);
375 /* up(&direntry->d_sb->s_vfs_rename_sem);*/
376 if(full_path == NULL) {
380 rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
383 direntry->d_inode->i_nlink--;
384 } else if (rc == -ENOENT) {
386 } else if (rc == -ETXTBSY) {
390 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
391 CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
392 &netfid, &oplock, NULL, cifs_sb->local_nls);
394 CIFSSMBRenameOpenFile(xid,pTcon,netfid,
395 NULL, cifs_sb->local_nls);
396 CIFSSMBClose(xid, pTcon, netfid);
397 direntry->d_inode->i_nlink--;
399 } else if (rc == -EACCES) {
400 /* try only if r/o attribute set in local lookup data? */
401 pinfo_buf = (FILE_BASIC_INFO *)kmalloc(sizeof(FILE_BASIC_INFO),GFP_KERNEL);
403 memset(pinfo_buf,0,sizeof(FILE_BASIC_INFO));
404 /* ATTRS set to normal clears r/o bit */
405 pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
406 rc = CIFSSMBSetTimes(xid, pTcon, full_path, pinfo_buf,
411 rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
413 direntry->d_inode->i_nlink--;
414 } else if (rc == -ETXTBSY) {
418 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
419 CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
420 &netfid, &oplock, NULL, cifs_sb->local_nls);
422 CIFSSMBRenameOpenFile(xid,pTcon,netfid,NULL,cifs_sb->local_nls);
423 CIFSSMBClose(xid, pTcon, netfid);
424 direntry->d_inode->i_nlink--;
426 /* BB if rc = -ETXTBUSY goto the rename logic BB */
430 cifsInode = CIFS_I(direntry->d_inode);
431 cifsInode->time = 0; /* will force revalidate to get info when needed */
432 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
434 cifsInode = CIFS_I(inode);
435 cifsInode->time = 0; /* force revalidate of dir as well */
444 cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
448 struct cifs_sb_info *cifs_sb;
449 struct cifsTconInfo *pTcon;
450 char *full_path = NULL;
451 struct inode *newinode = NULL;
453 cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode));
457 cifs_sb = CIFS_SB(inode->i_sb);
458 pTcon = cifs_sb->tcon;
460 down(&inode->i_sb->s_vfs_rename_sem);
461 full_path = build_path_from_dentry(direntry);
462 up(&inode->i_sb->s_vfs_rename_sem);
463 if(full_path == NULL) {
467 /* BB add setting the equivalent of mode via CreateX w/ACLs */
468 rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls);
470 cFYI(1, ("cifs_mkdir returned 0x%x ", rc));
474 if (pTcon->ses->capabilities & CAP_UNIX)
475 rc = cifs_get_inode_info_unix(&newinode, full_path,
478 rc = cifs_get_inode_info(&newinode, full_path,NULL,
481 direntry->d_op = &cifs_dentry_ops;
482 d_instantiate(direntry, newinode);
483 if(direntry->d_inode)
484 direntry->d_inode->i_nlink = 2;
485 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
486 CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
491 else { /* BB to be implemented via Windows secrty descriptors*/
492 /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/
503 cifs_rmdir(struct inode *inode, struct dentry *direntry)
507 struct cifs_sb_info *cifs_sb;
508 struct cifsTconInfo *pTcon;
509 char *full_path = NULL;
510 struct cifsInodeInfo *cifsInode;
512 cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode));
516 cifs_sb = CIFS_SB(inode->i_sb);
517 pTcon = cifs_sb->tcon;
519 down(&inode->i_sb->s_vfs_rename_sem);
520 full_path = build_path_from_dentry(direntry);
521 up(&inode->i_sb->s_vfs_rename_sem);
522 if(full_path == NULL) {
527 rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls);
531 i_size_write(direntry->d_inode,0);
532 direntry->d_inode->i_nlink = 0;
535 cifsInode = CIFS_I(direntry->d_inode);
536 cifsInode->time = 0; /* force revalidate to go get info when needed */
537 direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
547 cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
548 struct inode *target_inode, struct dentry *target_direntry)
552 struct cifs_sb_info *cifs_sb_source;
553 struct cifs_sb_info *cifs_sb_target;
554 struct cifsTconInfo *pTcon;
560 cifs_sb_target = CIFS_SB(target_inode->i_sb);
561 cifs_sb_source = CIFS_SB(source_inode->i_sb);
562 pTcon = cifs_sb_source->tcon;
564 if (pTcon != cifs_sb_target->tcon) {
566 return -EXDEV; /* BB actually could be allowed if same server, but
567 different share. Might eventually add support for this */
570 /* we already have the rename sem so we do not need
571 to grab it again here to protect the path integrity */
572 fromName = build_path_from_dentry(source_direntry);
573 toName = build_path_from_dentry(target_direntry);
574 if((fromName == NULL) || (toName == NULL)) {
576 goto cifs_rename_exit;
579 rc = CIFSSMBRename(xid, pTcon, fromName, toName,
580 cifs_sb_source->local_nls);
582 /* check if they are the same file
583 because rename of hardlinked files is a noop */
584 FILE_UNIX_BASIC_INFO * info_buf_source;
585 FILE_UNIX_BASIC_INFO * info_buf_target;
588 kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),GFP_KERNEL);
589 if(info_buf_source != NULL) {
590 info_buf_target = info_buf_source+1;
591 rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
592 info_buf_source, cifs_sb_source->local_nls);
594 rc = CIFSSMBUnixQPathInfo(xid,pTcon,toName,
596 cifs_sb_target->local_nls);
599 (info_buf_source->UniqueId ==
600 info_buf_target->UniqueId)) {
601 /* do not rename since the files are hardlinked
604 /* we either can not tell the files are hardlinked
605 (as with Windows servers) or files are not hardlinked
606 so delete the target manually before renaming to
607 follow POSIX rather than Windows semantics */
608 cifs_unlink(target_inode, target_direntry);
609 rc = CIFSSMBRename(xid, pTcon, fromName, toName,
610 cifs_sb_source->local_nls);
612 kfree(info_buf_source);
613 } /* if we can not get memory just leave rc as EEXIST */
616 if((rc == -EIO)||(rc == -EEXIST)) {
620 rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
622 &netfid, &oplock, NULL, cifs_sb_source->local_nls);
624 CIFSSMBRenameOpenFile(xid,pTcon,netfid,
625 toName, cifs_sb_source->local_nls);
626 CIFSSMBClose(xid, pTcon, netfid);
641 cifs_revalidate(struct dentry *direntry)
646 struct cifs_sb_info *cifs_sb;
647 struct cifsInodeInfo *cifsInode;
649 struct timespec local_mtime;
650 int invalidate_inode = FALSE;
652 if(direntry->d_inode == NULL)
655 cifsInode = CIFS_I(direntry->d_inode);
657 if(cifsInode == NULL)
660 /* no sense revalidating inode info on file that no one can write */
661 if(CIFS_I(direntry->d_inode)->clientCanCacheRead)
666 cifs_sb = CIFS_SB(direntry->d_sb);
668 /* can not safely grab the rename sem here if
669 rename calls revalidate since that would deadlock */
670 full_path = build_path_from_dentry(direntry);
671 if(full_path == NULL) {
676 ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld",
677 full_path, direntry->d_inode,
678 direntry->d_inode->i_count.counter, direntry,
679 direntry->d_time, jiffies));
681 if (cifsInode->time == 0){
682 /* was set to zero previously to force revalidate */
683 } else if (time_before(jiffies, cifsInode->time + HZ) && lookupCacheEnabled) {
684 if((S_ISREG(direntry->d_inode->i_mode) == 0) ||
685 (direntry->d_inode->i_nlink == 1)) {
691 cFYI(1,("Have to revalidate file due to hardlinks"));
695 /* save mtime and size */
696 local_mtime = direntry->d_inode->i_mtime;
697 local_size = direntry->d_inode->i_size;
699 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
700 rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
703 cFYI(1,("error on getting revalidate info %d",rc));
705 rc = 0; */ /* BB should we cache info on certain errors? */
708 rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
711 cFYI(1,("error on getting revalidate info %d",rc));
713 rc = 0; */ /* BB should we cache info on certain errors? */
716 /* should we remap certain errors, access denied?, to zero */
718 /* if not oplocked, we invalidate inode pages if mtime
719 or file size had changed on server */
721 if(timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) &&
722 (local_size == direntry->d_inode->i_size)) {
723 cFYI(1,("cifs_revalidate - inode unchanged"));
725 /* file may have changed on server */
726 if(cifsInode->clientCanCacheRead) {
727 /* no need to invalidate inode pages since we were
728 the only ones who could have modified the file and
729 the server copy is staler than ours */
731 invalidate_inode = TRUE;
735 /* can not grab this sem since kernel filesys locking
736 documentation indicates i_sem may be taken by the kernel
737 on lookup and rename which could deadlock if we grab
738 the i_sem here as well */
739 /* down(&direntry->d_inode->i_sem);*/
740 /* need to write out dirty pages here */
741 if(direntry->d_inode->i_mapping) {
742 /* do we need to lock inode until after invalidate completes below? */
743 filemap_fdatawrite(direntry->d_inode->i_mapping);
745 if(invalidate_inode) {
746 filemap_fdatawait(direntry->d_inode->i_mapping);
747 /* may eventually have to do this for open files too */
748 if(list_empty(&(cifsInode->openFileList))) {
749 /* Has changed on server - flush read ahead pages */
750 cFYI(1,("Invalidating read ahead data on closed file"));
751 invalidate_remote_inode(direntry->d_inode);
754 /* up(&direntry->d_inode->i_sem);*/
763 int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
765 int err = cifs_revalidate(dentry);
767 generic_fillattr(dentry->d_inode, stat);
771 static int cifs_truncate_page(struct address_space *mapping, loff_t from)
773 pgoff_t index = from >> PAGE_CACHE_SHIFT;
774 unsigned offset = from & (PAGE_CACHE_SIZE-1);
779 page = grab_cache_page(mapping, index);
783 kaddr = kmap_atomic(page, KM_USER0);
784 memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
785 flush_dcache_page(page);
786 kunmap_atomic(kaddr, KM_USER0);
788 page_cache_release(page);
793 cifs_setattr(struct dentry *direntry, struct iattr *attrs)
796 struct cifs_sb_info *cifs_sb;
797 struct cifsTconInfo *pTcon;
798 char *full_path = NULL;
801 struct cifsFileInfo *open_file = NULL;
802 FILE_BASIC_INFO time_buf;
803 int set_time = FALSE;
804 __u64 mode = 0xFFFFFFFFFFFFFFFFULL;
805 __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
806 __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
807 struct cifsInodeInfo *cifsInode;
808 struct list_head * tmp;
813 (" In cifs_setattr, name = %s attrs->iavalid 0x%x ",
814 direntry->d_name.name, attrs->ia_valid));
815 cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
816 pTcon = cifs_sb->tcon;
818 down(&direntry->d_sb->s_vfs_rename_sem);
819 full_path = build_path_from_dentry(direntry);
820 up(&direntry->d_sb->s_vfs_rename_sem);
821 if(full_path == NULL) {
825 cifsInode = CIFS_I(direntry->d_inode);
827 /* BB check if we need to refresh inode from server now ? BB */
829 /* need to flush data before changing file size on server */
830 filemap_fdatawrite(direntry->d_inode->i_mapping);
831 filemap_fdatawait(direntry->d_inode->i_mapping);
833 if (attrs->ia_valid & ATTR_SIZE) {
834 read_lock(&GlobalSMBSeslock);
835 /* To avoid spurious oplock breaks from server, in the case
836 of inodes that we already have open, avoid doing path
837 based setting of file size if we can do it by handle.
838 This keeps our caching token (oplock) and avoids
839 timeouts when the local oplock break takes longer to flush
840 writebehind data than the SMB timeout for the SetPathInfo
841 request would allow */
842 list_for_each(tmp, &cifsInode->openFileList) {
843 open_file = list_entry(tmp,struct cifsFileInfo, flist);
844 /* We check if file is open for writing first */
845 if((open_file->pfile) &&
846 ((open_file->pfile->f_flags & O_RDWR) ||
847 (open_file->pfile->f_flags & O_WRONLY))) {
848 if(open_file->invalidHandle == FALSE) {
849 /* we found a valid, writeable network file
850 handle to use to try to set the file size */
851 __u16 nfid = open_file->netfid;
852 __u32 npid = open_file->pid;
853 read_unlock(&GlobalSMBSeslock);
855 rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
857 cFYI(1,("SetFileSize by handle (setattrs) rc = %d",rc));
858 /* Do not need reopen and retry on EAGAIN since we will
859 retry by pathname below */
861 break; /* now that we found one valid file handle no
862 sense continuing to loop trying others */
867 read_unlock(&GlobalSMBSeslock);
872 /* Set file size by pathname rather than by handle either
873 because no valid, writeable file handle for it was found or
874 because there was an error setting it by handle */
875 rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,FALSE,
877 cFYI(1,(" SetEOF by path (setattrs) rc = %d",rc));
880 /* Server is ok setting allocation size implicitly - no need to call: */
881 /*CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE, cifs_sb->local_nls);*/
884 rc = vmtruncate(direntry->d_inode, attrs->ia_size);
885 cifs_truncate_page(direntry->d_inode->i_mapping, direntry->d_inode->i_size);
888 if (attrs->ia_valid & ATTR_UID) {
889 cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid));
891 /* entry->uid = cpu_to_le16(attr->ia_uid); */
893 if (attrs->ia_valid & ATTR_GID) {
894 cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid));
896 /* entry->gid = cpu_to_le16(attr->ia_gid); */
899 time_buf.Attributes = 0;
900 if (attrs->ia_valid & ATTR_MODE) {
901 cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode));
902 mode = attrs->ia_mode;
903 /* entry->mode = cpu_to_le16(attr->ia_mode); */
906 if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
907 && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
908 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
909 0 /* dev_t */, cifs_sb->local_nls);
910 else if (attrs->ia_valid & ATTR_MODE) {
911 if((mode & S_IWUGO) == 0) /* not writeable */ {
912 if((cifsInode->cifsAttrs & ATTR_READONLY) == 0)
913 time_buf.Attributes =
914 cpu_to_le32(cifsInode->cifsAttrs | ATTR_READONLY);
915 } else if((mode & S_IWUGO) == S_IWUGO) {
916 if(cifsInode->cifsAttrs & ATTR_READONLY)
917 time_buf.Attributes =
918 cpu_to_le32(cifsInode->cifsAttrs & (~ATTR_READONLY));
920 /* BB to be implemented - via Windows security descriptors or streams */
921 /* CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,uid,gid,cifs_sb->local_nls);*/
924 if (attrs->ia_valid & ATTR_ATIME) {
926 time_buf.LastAccessTime =
927 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
929 time_buf.LastAccessTime = 0;
931 if (attrs->ia_valid & ATTR_MTIME) {
933 time_buf.LastWriteTime =
934 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
936 time_buf.LastWriteTime = 0;
938 if (attrs->ia_valid & ATTR_CTIME) {
940 cFYI(1, (" CIFS - CTIME changed ")); /* BB probably do not need */
941 time_buf.ChangeTime =
942 cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
944 time_buf.ChangeTime = 0;
946 if (set_time | time_buf.Attributes) {
947 /* BB what if setting one attribute fails
948 (such as size) but time setting works */
949 time_buf.CreationTime = 0; /* do not change */
950 /* In the future we should experiment - try setting timestamps
951 via Handle (SetFileInfo) instead of by path */
952 rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
956 /* do not need local check to inode_check_ok since the server does that */
957 inode_setattr(direntry->d_inode, attrs);
965 cifs_delete_inode(struct inode *inode)
967 cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode));
968 /* may have to add back in if and when safe distributed caching of
969 directories added e.g. via FindNotify */