Merge git://git.infradead.org/mtd-2.6
[linux-2.6] / fs / cifs / inode.c
1 /*
2  *   fs/cifs/inode.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2005
5  *   Author(s): Steve French (sfrench@us.ibm.com)
6  *
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.
11  *
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.
16  *
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
20  */
21 #include <linux/fs.h>
22 #include <linux/stat.h>
23 #include <linux/pagemap.h>
24 #include <asm/div64.h>
25 #include "cifsfs.h"
26 #include "cifspdu.h"
27 #include "cifsglob.h"
28 #include "cifsproto.h"
29 #include "cifs_debug.h"
30 #include "cifs_fs_sb.h"
31
32 int cifs_get_inode_info_unix(struct inode **pinode,
33         const unsigned char *search_path, struct super_block *sb, int xid)
34 {
35         int rc = 0;
36         FILE_UNIX_BASIC_INFO findData;
37         struct cifsTconInfo *pTcon;
38         struct inode *inode;
39         struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
40         char *tmp_path;
41
42         pTcon = cifs_sb->tcon;
43         cFYI(1, ("Getting info on %s", search_path));
44         /* could have done a find first instead but this returns more info */
45         rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
46                                   cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
47                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
48 /*      dump_mem("\nUnixQPathInfo return data", &findData,
49                  sizeof(findData)); */
50         if (rc) {
51                 if (rc == -EREMOTE) {
52                         tmp_path =
53                             kmalloc(strnlen(pTcon->treeName,
54                                             MAX_TREE_SIZE + 1) +
55                                     strnlen(search_path, MAX_PATHCONF) + 1,
56                                     GFP_KERNEL);
57                         if (tmp_path == NULL) {
58                                 return -ENOMEM;
59                         }
60                         /* have to skip first of the double backslash of
61                            UNC name */
62                         strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
63                         strncat(tmp_path, search_path, MAX_PATHCONF);
64                         rc = connect_to_dfs_path(xid, pTcon->ses,
65                                                  /* treename + */ tmp_path,
66                                                  cifs_sb->local_nls, 
67                                                  cifs_sb->mnt_cifs_flags & 
68                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
69                         kfree(tmp_path);
70
71                         /* BB fix up inode etc. */
72                 } else if (rc) {
73                         return rc;
74                 }
75         } else {
76                 struct cifsInodeInfo *cifsInfo;
77                 __u32 type = le32_to_cpu(findData.Type);
78                 __u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes);
79                 __u64 end_of_file = le64_to_cpu(findData.EndOfFile);
80
81                 /* get new inode */
82                 if (*pinode == NULL) {
83                         *pinode = new_inode(sb);
84                         if (*pinode == NULL) 
85                                 return -ENOMEM;
86                         /* Is an i_ino of zero legal? */
87                         /* Are there sanity checks we can use to ensure that
88                            the server is really filling in that field? */
89                         if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
90                                 (*pinode)->i_ino =
91                                         (unsigned long)findData.UniqueId;
92                         } /* note ino incremented to unique num in new_inode */
93                         if(sb->s_flags & MS_NOATIME)
94                                 (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
95                                 
96                         insert_inode_hash(*pinode);
97                 }
98
99                 inode = *pinode;
100                 cifsInfo = CIFS_I(inode);
101
102                 cFYI(1, ("Old time %ld", cifsInfo->time));
103                 cifsInfo->time = jiffies;
104                 cFYI(1, ("New time %ld", cifsInfo->time));
105                 /* this is ok to set on every inode revalidate */
106                 atomic_set(&cifsInfo->inUse,1);
107
108                 inode->i_atime =
109                     cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime));
110                 inode->i_mtime =
111                     cifs_NTtimeToUnix(le64_to_cpu
112                                 (findData.LastModificationTime));
113                 inode->i_ctime =
114                     cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange));
115                 inode->i_mode = le64_to_cpu(findData.Permissions);
116                 /* since we set the inode type below we need to mask off
117                    to avoid strange results if bits set above */
118                         inode->i_mode &= ~S_IFMT;
119                 if (type == UNIX_FILE) {
120                         inode->i_mode |= S_IFREG;
121                 } else if (type == UNIX_SYMLINK) {
122                         inode->i_mode |= S_IFLNK;
123                 } else if (type == UNIX_DIR) {
124                         inode->i_mode |= S_IFDIR;
125                 } else if (type == UNIX_CHARDEV) {
126                         inode->i_mode |= S_IFCHR;
127                         inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor),
128                                 le64_to_cpu(findData.DevMinor) & MINORMASK);
129                 } else if (type == UNIX_BLOCKDEV) {
130                         inode->i_mode |= S_IFBLK;
131                         inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor),
132                                 le64_to_cpu(findData.DevMinor) & MINORMASK);
133                 } else if (type == UNIX_FIFO) {
134                         inode->i_mode |= S_IFIFO;
135                 } else if (type == UNIX_SOCKET) {
136                         inode->i_mode |= S_IFSOCK;
137                 } else {
138                         /* safest to call it a file if we do not know */
139                         inode->i_mode |= S_IFREG;
140                         cFYI(1,("unknown type %d",type));
141                 }
142                 inode->i_uid = le64_to_cpu(findData.Uid);
143                 inode->i_gid = le64_to_cpu(findData.Gid);
144                 inode->i_nlink = le64_to_cpu(findData.Nlinks);
145
146                 spin_lock(&inode->i_lock);
147                 if (is_size_safe_to_change(cifsInfo, end_of_file)) {
148                 /* can not safely change the file size here if the
149                    client is writing to it due to potential races */
150                         i_size_write(inode, end_of_file);
151
152                 /* blksize needs to be multiple of two. So safer to default to
153                 blksize and blkbits set in superblock so 2**blkbits and blksize
154                 will match rather than setting to:
155                 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
156
157                 /* This seems incredibly stupid but it turns out that i_blocks
158                    is not related to (i_size / i_blksize), instead 512 byte size
159                    is required for calculating num blocks */
160
161                 /* 512 bytes (2**9) is the fake blocksize that must be used */
162                 /* for this calculation */
163                         inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
164                 }
165                 spin_unlock(&inode->i_lock);
166
167                 if (num_of_bytes < end_of_file)
168                         cFYI(1, ("allocation size less than end of file"));
169                 cFYI(1, ("Size %ld and blocks %llu",
170                         (unsigned long) inode->i_size,
171                         (unsigned long long)inode->i_blocks));
172                 if (S_ISREG(inode->i_mode)) {
173                         cFYI(1, ("File inode"));
174                         inode->i_op = &cifs_file_inode_ops;
175                         if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
176                                 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
177                                         inode->i_fop = 
178                                                 &cifs_file_direct_nobrl_ops;
179                                 else
180                                         inode->i_fop = &cifs_file_direct_ops;
181                         } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
182                                 inode->i_fop = &cifs_file_nobrl_ops;
183                         else /* not direct, send byte range locks */ 
184                                 inode->i_fop = &cifs_file_ops;
185
186                         /* check if server can support readpages */
187                         if(pTcon->ses->server->maxBuf < 
188                             PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
189                                 inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
190                         else
191                                 inode->i_data.a_ops = &cifs_addr_ops;
192                 } else if (S_ISDIR(inode->i_mode)) {
193                         cFYI(1, ("Directory inode"));
194                         inode->i_op = &cifs_dir_inode_ops;
195                         inode->i_fop = &cifs_dir_ops;
196                 } else if (S_ISLNK(inode->i_mode)) {
197                         cFYI(1, ("Symbolic Link inode"));
198                         inode->i_op = &cifs_symlink_inode_ops;
199                 /* tmp_inode->i_fop = */ /* do not need to set to anything */
200                 } else {
201                         cFYI(1, ("Init special inode"));
202                         init_special_inode(inode, inode->i_mode,
203                                            inode->i_rdev);
204                 }
205         }
206         return rc;
207 }
208
209 static int decode_sfu_inode(struct inode * inode, __u64 size,
210                             const unsigned char *path,
211                             struct cifs_sb_info *cifs_sb, int xid)
212 {
213         int rc;
214         int oplock = FALSE;
215         __u16 netfid;
216         struct cifsTconInfo *pTcon = cifs_sb->tcon;
217         char buf[24];
218         unsigned int bytes_read;
219         char * pbuf;
220
221         pbuf = buf;
222
223         if(size == 0) {
224                 inode->i_mode |= S_IFIFO;
225                 return 0;
226         } else if (size < 8) {
227                 return -EINVAL;  /* EOPNOTSUPP? */
228         }
229                 
230         rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ,
231                          CREATE_NOT_DIR, &netfid, &oplock, NULL,
232                          cifs_sb->local_nls,
233                          cifs_sb->mnt_cifs_flags &
234                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
235         if (rc==0) {
236                 int buf_type = CIFS_NO_BUFFER;
237                         /* Read header */
238                 rc = CIFSSMBRead(xid, pTcon,
239                                  netfid,
240                                  24 /* length */, 0 /* offset */,
241                                  &bytes_read, &pbuf, &buf_type);
242                 if((rc == 0) && (bytes_read >= 8)) {
243                         if(memcmp("IntxBLK", pbuf, 8) == 0) {
244                                 cFYI(1,("Block device"));
245                                 inode->i_mode |= S_IFBLK;
246                                 if(bytes_read == 24) {
247                                         /* we have enough to decode dev num */
248                                         __u64 mjr; /* major */
249                                         __u64 mnr; /* minor */
250                                         mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
251                                         mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
252                                         inode->i_rdev = MKDEV(mjr, mnr);
253                                 }
254                         } else if(memcmp("IntxCHR", pbuf, 8) == 0) {
255                                 cFYI(1,("Char device"));
256                                 inode->i_mode |= S_IFCHR;
257                                 if(bytes_read == 24) {
258                                         /* we have enough to decode dev num */
259                                         __u64 mjr; /* major */
260                                         __u64 mnr; /* minor */
261                                         mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
262                                         mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
263                                         inode->i_rdev = MKDEV(mjr, mnr);
264                                 }
265                         } else if(memcmp("IntxLNK", pbuf, 7) == 0) {
266                                 cFYI(1,("Symlink"));
267                                 inode->i_mode |= S_IFLNK;
268                         } else {
269                                 inode->i_mode |= S_IFREG; /* file? */
270                                 rc = -EOPNOTSUPP; 
271                         }
272                 } else {
273                         inode->i_mode |= S_IFREG; /* then it is a file */
274                         rc = -EOPNOTSUPP; /* or some unknown SFU type */        
275                 }               
276                 CIFSSMBClose(xid, pTcon, netfid);
277         }
278         return rc;
279         
280 }
281
282 #define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID)  /* SETFILEBITS valid bits */
283
284 static int get_sfu_uid_mode(struct inode * inode,
285                         const unsigned char *path,
286                         struct cifs_sb_info *cifs_sb, int xid)
287 {
288 #ifdef CONFIG_CIFS_XATTR
289         ssize_t rc;
290         char ea_value[4];
291         __u32 mode;
292
293         rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS",
294                         ea_value, 4 /* size of buf */, cifs_sb->local_nls,
295                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
296         if(rc < 0)
297                 return (int)rc;
298         else if (rc > 3) {
299                 mode = le32_to_cpu(*((__le32 *)ea_value));
300                 inode->i_mode &= ~SFBITS_MASK; 
301                 cFYI(1,("special bits 0%o org mode 0%o", mode, inode->i_mode));
302                 inode->i_mode = (mode &  SFBITS_MASK) | inode->i_mode;
303                 cFYI(1,("special mode bits 0%o", mode));
304                 return 0;
305         } else {
306                 return 0;
307         }
308 #else
309         return -EOPNOTSUPP;
310 #endif
311
312                 
313 }
314
315 int cifs_get_inode_info(struct inode **pinode,
316         const unsigned char *search_path, FILE_ALL_INFO *pfindData,
317         struct super_block *sb, int xid)
318 {
319         int rc = 0;
320         struct cifsTconInfo *pTcon;
321         struct inode *inode;
322         struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
323         char *tmp_path;
324         char *buf = NULL;
325         int adjustTZ = FALSE;
326
327         pTcon = cifs_sb->tcon;
328         cFYI(1,("Getting info on %s", search_path));
329
330         if ((pfindData == NULL) && (*pinode != NULL)) {
331                 if (CIFS_I(*pinode)->clientCanCacheRead) {
332                         cFYI(1,("No need to revalidate cached inode sizes"));
333                         return rc;
334                 }
335         }
336
337         /* if file info not passed in then get it from server */
338         if (pfindData == NULL) {
339                 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
340                 if (buf == NULL)
341                         return -ENOMEM;
342                 pfindData = (FILE_ALL_INFO *)buf;
343                 /* could do find first instead but this returns more info */
344                 rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
345                               0 /* not legacy */,
346                               cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
347                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
348                 /* BB optimize code so we do not make the above call
349                 when server claims no NT SMB support and the above call
350                 failed at least once - set flag in tcon or mount */
351                 if((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
352                         rc = SMBQueryInformation(xid, pTcon, search_path,
353                                         pfindData, cifs_sb->local_nls, 
354                                         cifs_sb->mnt_cifs_flags &
355                                           CIFS_MOUNT_MAP_SPECIAL_CHR);
356                         adjustTZ = TRUE;
357                 }
358                 
359         }
360         /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
361         if (rc) {
362                 if (rc == -EREMOTE) {
363                         tmp_path =
364                             kmalloc(strnlen
365                                     (pTcon->treeName,
366                                      MAX_TREE_SIZE + 1) +
367                                     strnlen(search_path, MAX_PATHCONF) + 1,
368                                     GFP_KERNEL);
369                         if (tmp_path == NULL) {
370                                 kfree(buf);
371                                 return -ENOMEM;
372                         }
373
374                         strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
375                         strncat(tmp_path, search_path, MAX_PATHCONF);
376                         rc = connect_to_dfs_path(xid, pTcon->ses,
377                                                  /* treename + */ tmp_path,
378                                                  cifs_sb->local_nls, 
379                                                  cifs_sb->mnt_cifs_flags & 
380                                                    CIFS_MOUNT_MAP_SPECIAL_CHR);
381                         kfree(tmp_path);
382                         /* BB fix up inode etc. */
383                 } else if (rc) {
384                         kfree(buf);
385                         return rc;
386                 }
387         } else {
388                 struct cifsInodeInfo *cifsInfo;
389                 __u32 attr = le32_to_cpu(pfindData->Attributes);
390
391                 /* get new inode */
392                 if (*pinode == NULL) {
393                         *pinode = new_inode(sb);
394                         if (*pinode == NULL) {
395                                 kfree(buf);
396                                 return -ENOMEM;
397                         }
398                         /* Is an i_ino of zero legal? Can we use that to check
399                            if the server supports returning inode numbers?  Are
400                            there other sanity checks we can use to ensure that
401                            the server is really filling in that field? */
402
403                         /* We can not use the IndexNumber field by default from
404                            Windows or Samba (in ALL_INFO buf) but we can request
405                            it explicitly.  It may not be unique presumably if
406                            the server has multiple devices mounted under one
407                            share */
408
409                         /* There may be higher info levels that work but are
410                            there Windows server or network appliances for which
411                            IndexNumber field is not guaranteed unique? */
412
413                         if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM){
414                                 int rc1 = 0;
415                                 __u64 inode_num;
416
417                                 rc1 = CIFSGetSrvInodeNumber(xid, pTcon, 
418                                         search_path, &inode_num, 
419                                         cifs_sb->local_nls,
420                                         cifs_sb->mnt_cifs_flags &
421                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
422                                 if (rc1) {
423                                         cFYI(1,("GetSrvInodeNum rc %d", rc1));
424                                         /* BB EOPNOSUPP disable SERVER_INUM? */
425                                 } else /* do we need cast or hash to ino? */
426                                         (*pinode)->i_ino = inode_num;
427                         } /* else ino incremented to unique num in new_inode*/
428                         if(sb->s_flags & MS_NOATIME)
429                                 (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
430                         insert_inode_hash(*pinode);
431                 }
432                 inode = *pinode;
433                 cifsInfo = CIFS_I(inode);
434                 cifsInfo->cifsAttrs = attr;
435                 cFYI(1, ("Old time %ld", cifsInfo->time));
436                 cifsInfo->time = jiffies;
437                 cFYI(1, ("New time %ld", cifsInfo->time));
438
439                 /* blksize needs to be multiple of two. So safer to default to
440                 blksize and blkbits set in superblock so 2**blkbits and blksize
441                 will match rather than setting to:
442                 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
443
444                 /* Linux can not store file creation time so ignore it */
445                 if(pfindData->LastAccessTime)
446                         inode->i_atime = cifs_NTtimeToUnix
447                                 (le64_to_cpu(pfindData->LastAccessTime));
448                 else /* do not need to use current_fs_time - time not stored */
449                         inode->i_atime = CURRENT_TIME;
450                 inode->i_mtime =
451                     cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
452                 inode->i_ctime =
453                     cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
454                 cFYI(0, ("Attributes came in as 0x%x", attr));
455                 if(adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
456                         inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj;
457                         inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
458                 }
459
460                 /* set default mode. will override for dirs below */
461                 if (atomic_read(&cifsInfo->inUse) == 0)
462                         /* new inode, can safely set these fields */
463                         inode->i_mode = cifs_sb->mnt_file_mode;
464                 else /* since we set the inode type below we need to mask off
465                      to avoid strange results if type changes and both get orred in */ 
466                         inode->i_mode &= ~S_IFMT; 
467 /*              if (attr & ATTR_REPARSE)  */
468                 /* We no longer handle these as symlinks because we could not
469                    follow them due to the absolute path with drive letter */
470                 if (attr & ATTR_DIRECTORY) {
471                 /* override default perms since we do not do byte range locking
472                    on dirs */
473                         inode->i_mode = cifs_sb->mnt_dir_mode;
474                         inode->i_mode |= S_IFDIR;
475                 } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
476                            (cifsInfo->cifsAttrs & ATTR_SYSTEM) &&
477                            /* No need to le64 convert size of zero */
478                            (pfindData->EndOfFile == 0)) {
479                         inode->i_mode = cifs_sb->mnt_file_mode;
480                         inode->i_mode |= S_IFIFO;
481 /* BB Finish for SFU style symlinks and devices */
482                 } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
483                            (cifsInfo->cifsAttrs & ATTR_SYSTEM)) {
484                         if (decode_sfu_inode(inode, 
485                                          le64_to_cpu(pfindData->EndOfFile),
486                                          search_path,
487                                          cifs_sb, xid)) {
488                                 cFYI(1,("Unrecognized sfu inode type"));
489                         }
490                         cFYI(1,("sfu mode 0%o",inode->i_mode));
491                 } else {
492                         inode->i_mode |= S_IFREG;
493                         /* treat the dos attribute of read-only as read-only
494                            mode e.g. 555 */
495                         if (cifsInfo->cifsAttrs & ATTR_READONLY)
496                                 inode->i_mode &= ~(S_IWUGO);
497                 /* BB add code here -
498                    validate if device or weird share or device type? */
499                 }
500                 
501                 spin_lock(&inode->i_lock);
502                 if (is_size_safe_to_change(cifsInfo, le64_to_cpu(pfindData->EndOfFile))) {
503                         /* can not safely shrink the file size here if the
504                            client is writing to it due to potential races */
505                         i_size_write(inode,le64_to_cpu(pfindData->EndOfFile));
506
507                         /* 512 bytes (2**9) is the fake blocksize that must be
508                            used for this calculation */
509                         inode->i_blocks = (512 - 1 + le64_to_cpu(
510                                            pfindData->AllocationSize)) >> 9;
511                 }
512                 spin_unlock(&inode->i_lock);
513
514                 inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
515
516                 /* BB fill in uid and gid here? with help from winbind? 
517                    or retrieve from NTFS stream extended attribute */
518                 if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
519                         /* fill in uid, gid, mode from server ACL */
520                         get_sfu_uid_mode(inode, search_path, cifs_sb, xid);
521                 } else if (atomic_read(&cifsInfo->inUse) == 0) {
522                         inode->i_uid = cifs_sb->mnt_uid;
523                         inode->i_gid = cifs_sb->mnt_gid;
524                         /* set so we do not keep refreshing these fields with
525                            bad data after user has changed them in memory */
526                         atomic_set(&cifsInfo->inUse,1);
527                 }
528
529                 if (S_ISREG(inode->i_mode)) {
530                         cFYI(1, ("File inode"));
531                         inode->i_op = &cifs_file_inode_ops;
532                         if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
533                                 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
534                                         inode->i_fop =
535                                                 &cifs_file_direct_nobrl_ops;
536                                 else
537                                         inode->i_fop = &cifs_file_direct_ops;
538                         } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
539                                 inode->i_fop = &cifs_file_nobrl_ops;
540                         else /* not direct, send byte range locks */
541                                 inode->i_fop = &cifs_file_ops;
542
543                         if(pTcon->ses->server->maxBuf < 
544                              PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
545                                 inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
546                         else
547                                 inode->i_data.a_ops = &cifs_addr_ops;
548                 } else if (S_ISDIR(inode->i_mode)) {
549                         cFYI(1, ("Directory inode"));
550                         inode->i_op = &cifs_dir_inode_ops;
551                         inode->i_fop = &cifs_dir_ops;
552                 } else if (S_ISLNK(inode->i_mode)) {
553                         cFYI(1, ("Symbolic Link inode"));
554                         inode->i_op = &cifs_symlink_inode_ops;
555                 } else {
556                         init_special_inode(inode, inode->i_mode,
557                                            inode->i_rdev);
558                 }
559         }
560         kfree(buf);
561         return rc;
562 }
563
564 /* gets root inode */
565 void cifs_read_inode(struct inode *inode)
566 {
567         int xid;
568         struct cifs_sb_info *cifs_sb;
569
570         cifs_sb = CIFS_SB(inode->i_sb);
571         xid = GetXid();
572         if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
573                 cifs_get_inode_info_unix(&inode, "", inode->i_sb,xid);
574         else
575                 cifs_get_inode_info(&inode, "", NULL, inode->i_sb,xid);
576         /* can not call macro FreeXid here since in a void func */
577         _FreeXid(xid);
578 }
579
580 int cifs_unlink(struct inode *inode, struct dentry *direntry)
581 {
582         int rc = 0;
583         int xid;
584         struct cifs_sb_info *cifs_sb;
585         struct cifsTconInfo *pTcon;
586         char *full_path = NULL;
587         struct cifsInodeInfo *cifsInode;
588         FILE_BASIC_INFO *pinfo_buf;
589
590         cFYI(1, ("cifs_unlink, inode = 0x%p", inode));
591
592         xid = GetXid();
593
594         if(inode)
595                 cifs_sb = CIFS_SB(inode->i_sb);
596         else
597                 cifs_sb = CIFS_SB(direntry->d_sb);
598         pTcon = cifs_sb->tcon;
599
600         /* Unlink can be called from rename so we can not grab the sem here
601            since we deadlock otherwise */
602 /*      mutex_lock(&direntry->d_sb->s_vfs_rename_mutex);*/
603         full_path = build_path_from_dentry(direntry);
604 /*      mutex_unlock(&direntry->d_sb->s_vfs_rename_mutex);*/
605         if (full_path == NULL) {
606                 FreeXid(xid);
607                 return -ENOMEM;
608         }
609         rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls,
610                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
611
612         if (!rc) {
613                 if (direntry->d_inode)
614                         drop_nlink(direntry->d_inode);
615         } else if (rc == -ENOENT) {
616                 d_drop(direntry);
617         } else if (rc == -ETXTBSY) {
618                 int oplock = FALSE;
619                 __u16 netfid;
620
621                 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
622                                  CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
623                                  &netfid, &oplock, NULL, cifs_sb->local_nls,
624                                  cifs_sb->mnt_cifs_flags & 
625                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
626                 if (rc==0) {
627                         CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL,
628                                               cifs_sb->local_nls, 
629                                               cifs_sb->mnt_cifs_flags & 
630                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
631                         CIFSSMBClose(xid, pTcon, netfid);
632                         if (direntry->d_inode)
633                                 drop_nlink(direntry->d_inode);
634                 }
635         } else if (rc == -EACCES) {
636                 /* try only if r/o attribute set in local lookup data? */
637                 pinfo_buf = kzalloc(sizeof(FILE_BASIC_INFO), GFP_KERNEL);
638                 if (pinfo_buf) {
639                         /* ATTRS set to normal clears r/o bit */
640                         pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
641                         if (!(pTcon->ses->flags & CIFS_SES_NT4))
642                                 rc = CIFSSMBSetTimes(xid, pTcon, full_path,
643                                                      pinfo_buf,
644                                                      cifs_sb->local_nls,
645                                                      cifs_sb->mnt_cifs_flags & 
646                                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
647                         else
648                                 rc = -EOPNOTSUPP;
649
650                         if (rc == -EOPNOTSUPP) {
651                                 int oplock = FALSE;
652                                 __u16 netfid;
653                         /*      rc = CIFSSMBSetAttrLegacy(xid, pTcon,
654                                                           full_path,
655                                                           (__u16)ATTR_NORMAL,
656                                                           cifs_sb->local_nls); 
657                            For some strange reason it seems that NT4 eats the
658                            old setattr call without actually setting the
659                            attributes so on to the third attempted workaround
660                            */
661
662                         /* BB could scan to see if we already have it open
663                            and pass in pid of opener to function */
664                                 rc = CIFSSMBOpen(xid, pTcon, full_path,
665                                                  FILE_OPEN, SYNCHRONIZE |
666                                                  FILE_WRITE_ATTRIBUTES, 0,
667                                                  &netfid, &oplock, NULL,
668                                                  cifs_sb->local_nls,
669                                                  cifs_sb->mnt_cifs_flags & 
670                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
671                                 if (rc==0) {
672                                         rc = CIFSSMBSetFileTimes(xid, pTcon,
673                                                                  pinfo_buf,
674                                                                  netfid);
675                                         CIFSSMBClose(xid, pTcon, netfid);
676                                 }
677                         }
678                         kfree(pinfo_buf);
679                 }
680                 if (rc==0) {
681                         rc = CIFSSMBDelFile(xid, pTcon, full_path, 
682                                             cifs_sb->local_nls, 
683                                             cifs_sb->mnt_cifs_flags & 
684                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
685                         if (!rc) {
686                                 if (direntry->d_inode)
687                                         drop_nlink(direntry->d_inode);
688                         } else if (rc == -ETXTBSY) {
689                                 int oplock = FALSE;
690                                 __u16 netfid;
691
692                                 rc = CIFSSMBOpen(xid, pTcon, full_path,
693                                                  FILE_OPEN, DELETE,
694                                                  CREATE_NOT_DIR |
695                                                  CREATE_DELETE_ON_CLOSE,
696                                                  &netfid, &oplock, NULL,
697                                                  cifs_sb->local_nls, 
698                                                  cifs_sb->mnt_cifs_flags & 
699                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
700                                 if (rc==0) {
701                                         CIFSSMBRenameOpenFile(xid, pTcon,
702                                                 netfid, NULL,
703                                                 cifs_sb->local_nls,
704                                                 cifs_sb->mnt_cifs_flags &
705                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
706                                         CIFSSMBClose(xid, pTcon, netfid);
707                                         if (direntry->d_inode)
708                                                 drop_nlink(direntry->d_inode);
709                                 }
710                         /* BB if rc = -ETXTBUSY goto the rename logic BB */
711                         }
712                 }
713         }
714         if (direntry->d_inode) {
715                 cifsInode = CIFS_I(direntry->d_inode);
716                 cifsInode->time = 0;    /* will force revalidate to get info
717                                            when needed */
718                 direntry->d_inode->i_ctime = current_fs_time(inode->i_sb);
719         }
720         if(inode) {
721                 inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb);
722                 cifsInode = CIFS_I(inode);
723                 cifsInode->time = 0;    /* force revalidate of dir as well */
724         }
725
726         kfree(full_path);
727         FreeXid(xid);
728         return rc;
729 }
730
731 int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
732 {
733         int rc = 0;
734         int xid;
735         struct cifs_sb_info *cifs_sb;
736         struct cifsTconInfo *pTcon;
737         char *full_path = NULL;
738         struct inode *newinode = NULL;
739
740         cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode));
741
742         xid = GetXid();
743
744         cifs_sb = CIFS_SB(inode->i_sb);
745         pTcon = cifs_sb->tcon;
746
747         full_path = build_path_from_dentry(direntry);
748         if (full_path == NULL) {
749                 FreeXid(xid);
750                 return -ENOMEM;
751         }
752         /* BB add setting the equivalent of mode via CreateX w/ACLs */
753         rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
754                           cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
755         if (rc) {
756                 cFYI(1, ("cifs_mkdir returned 0x%x", rc));
757                 d_drop(direntry);
758         } else {
759                 inc_nlink(inode);
760                 if (pTcon->ses->capabilities & CAP_UNIX)
761                         rc = cifs_get_inode_info_unix(&newinode, full_path,
762                                                       inode->i_sb,xid);
763                 else
764                         rc = cifs_get_inode_info(&newinode, full_path, NULL,
765                                                  inode->i_sb,xid);
766
767                 if (pTcon->nocase)
768                         direntry->d_op = &cifs_ci_dentry_ops;
769                 else
770                         direntry->d_op = &cifs_dentry_ops;
771                 d_instantiate(direntry, newinode);
772                 if (direntry->d_inode)
773                         direntry->d_inode->i_nlink = 2;
774                 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
775                         if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
776                                 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
777                                                     mode,
778                                                     (__u64)current->fsuid,
779                                                     (__u64)current->fsgid,
780                                                     0 /* dev_t */,
781                                                     cifs_sb->local_nls,
782                                                     cifs_sb->mnt_cifs_flags &
783                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
784                         } else {
785                                 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
786                                                     mode, (__u64)-1,
787                                                     (__u64)-1, 0 /* dev_t */,
788                                                     cifs_sb->local_nls,
789                                                     cifs_sb->mnt_cifs_flags & 
790                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
791                         }
792                 else {
793                         /* BB to be implemented via Windows secrty descriptors
794                            eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
795                                                  -1, -1, local_nls); */
796                         if(direntry->d_inode) {
797                                 direntry->d_inode->i_mode = mode;
798                                 direntry->d_inode->i_mode |= S_IFDIR;
799                                 if(cifs_sb->mnt_cifs_flags & 
800                                      CIFS_MOUNT_SET_UID) {
801                                         direntry->d_inode->i_uid = 
802                                                 current->fsuid;
803                                         direntry->d_inode->i_gid = 
804                                                 current->fsgid;
805                                 }
806                         }
807                 }
808         }
809         kfree(full_path);
810         FreeXid(xid);
811         return rc;
812 }
813
814 int cifs_rmdir(struct inode *inode, struct dentry *direntry)
815 {
816         int rc = 0;
817         int xid;
818         struct cifs_sb_info *cifs_sb;
819         struct cifsTconInfo *pTcon;
820         char *full_path = NULL;
821         struct cifsInodeInfo *cifsInode;
822
823         cFYI(1, ("cifs_rmdir, inode = 0x%p", inode));
824
825         xid = GetXid();
826
827         cifs_sb = CIFS_SB(inode->i_sb);
828         pTcon = cifs_sb->tcon;
829
830         full_path = build_path_from_dentry(direntry);
831         if (full_path == NULL) {
832                 FreeXid(xid);
833                 return -ENOMEM;
834         }
835
836         rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls,
837                           cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
838
839         if (!rc) {
840                 drop_nlink(inode);
841                 spin_lock(&direntry->d_inode->i_lock);
842                 i_size_write(direntry->d_inode,0);
843                 clear_nlink(direntry->d_inode);
844                 spin_unlock(&direntry->d_inode->i_lock);
845         }
846
847         cifsInode = CIFS_I(direntry->d_inode);
848         cifsInode->time = 0;    /* force revalidate to go get info when
849                                    needed */
850         direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
851                 current_fs_time(inode->i_sb);
852
853         kfree(full_path);
854         FreeXid(xid);
855         return rc;
856 }
857
858 int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
859         struct inode *target_inode, struct dentry *target_direntry)
860 {
861         char *fromName;
862         char *toName;
863         struct cifs_sb_info *cifs_sb_source;
864         struct cifs_sb_info *cifs_sb_target;
865         struct cifsTconInfo *pTcon;
866         int xid;
867         int rc = 0;
868
869         xid = GetXid();
870
871         cifs_sb_target = CIFS_SB(target_inode->i_sb);
872         cifs_sb_source = CIFS_SB(source_inode->i_sb);
873         pTcon = cifs_sb_source->tcon;
874
875         if (pTcon != cifs_sb_target->tcon) {
876                 FreeXid(xid);
877                 return -EXDEV;  /* BB actually could be allowed if same server,
878                                    but different share.
879                                    Might eventually add support for this */
880         }
881
882         /* we already  have the rename sem so we do not need to grab it again
883            here to protect the path integrity */
884         fromName = build_path_from_dentry(source_direntry);
885         toName = build_path_from_dentry(target_direntry);
886         if ((fromName == NULL) || (toName == NULL)) {
887                 rc = -ENOMEM;
888                 goto cifs_rename_exit;
889         }
890
891         rc = CIFSSMBRename(xid, pTcon, fromName, toName,
892                            cifs_sb_source->local_nls,
893                            cifs_sb_source->mnt_cifs_flags &
894                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
895         if (rc == -EEXIST) {
896                 /* check if they are the same file because rename of hardlinked
897                    files is a noop */
898                 FILE_UNIX_BASIC_INFO *info_buf_source;
899                 FILE_UNIX_BASIC_INFO *info_buf_target;
900
901                 info_buf_source =
902                         kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
903                 if (info_buf_source != NULL) {
904                         info_buf_target = info_buf_source + 1;
905                         if (pTcon->ses->capabilities & CAP_UNIX)
906                                 rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
907                                         info_buf_source, 
908                                         cifs_sb_source->local_nls,
909                                         cifs_sb_source->mnt_cifs_flags &
910                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
911                         /* else rc is still EEXIST so will fall through to
912                            unlink the target and retry rename */
913                         if (rc == 0) {
914                                 rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName,
915                                                 info_buf_target,
916                                                 cifs_sb_target->local_nls,
917                                                 /* remap based on source sb */
918                                                 cifs_sb_source->mnt_cifs_flags &
919                                                     CIFS_MOUNT_MAP_SPECIAL_CHR);
920                         }
921                         if ((rc == 0) &&
922                             (info_buf_source->UniqueId ==
923                              info_buf_target->UniqueId)) {
924                         /* do not rename since the files are hardlinked which
925                            is a noop */
926                         } else {
927                         /* we either can not tell the files are hardlinked
928                            (as with Windows servers) or files are not
929                            hardlinked so delete the target manually before
930                            renaming to follow POSIX rather than Windows
931                            semantics */
932                                 cifs_unlink(target_inode, target_direntry);
933                                 rc = CIFSSMBRename(xid, pTcon, fromName,
934                                                    toName,
935                                                    cifs_sb_source->local_nls,
936                                                    cifs_sb_source->mnt_cifs_flags
937                                                    & CIFS_MOUNT_MAP_SPECIAL_CHR);
938                         }
939                         kfree(info_buf_source);
940                 } /* if we can not get memory just leave rc as EEXIST */
941         }
942
943         if (rc) {
944                 cFYI(1, ("rename rc %d", rc));
945         }
946
947         if ((rc == -EIO) || (rc == -EEXIST)) {
948                 int oplock = FALSE;
949                 __u16 netfid;
950
951                 /* BB FIXME Is Generic Read correct for rename? */
952                 /* if renaming directory - we should not say CREATE_NOT_DIR,
953                    need to test renaming open directory, also GENERIC_READ
954                    might not right be right access to request */
955                 rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
956                                  CREATE_NOT_DIR, &netfid, &oplock, NULL,
957                                  cifs_sb_source->local_nls, 
958                                  cifs_sb_source->mnt_cifs_flags & 
959                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
960                 if (rc==0) {
961                         rc = CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName,
962                                               cifs_sb_source->local_nls, 
963                                               cifs_sb_source->mnt_cifs_flags &
964                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
965                         CIFSSMBClose(xid, pTcon, netfid);
966                 }
967         }
968
969 cifs_rename_exit:
970         kfree(fromName);
971         kfree(toName);
972         FreeXid(xid);
973         return rc;
974 }
975
976 int cifs_revalidate(struct dentry *direntry)
977 {
978         int xid;
979         int rc = 0;
980         char *full_path;
981         struct cifs_sb_info *cifs_sb;
982         struct cifsInodeInfo *cifsInode;
983         loff_t local_size;
984         struct timespec local_mtime;
985         int invalidate_inode = FALSE;
986
987         if (direntry->d_inode == NULL)
988                 return -ENOENT;
989
990         cifsInode = CIFS_I(direntry->d_inode);
991
992         if (cifsInode == NULL)
993                 return -ENOENT;
994
995         /* no sense revalidating inode info on file that no one can write */
996         if (CIFS_I(direntry->d_inode)->clientCanCacheRead)
997                 return rc;
998
999         xid = GetXid();
1000
1001         cifs_sb = CIFS_SB(direntry->d_sb);
1002
1003         /* can not safely grab the rename sem here if rename calls revalidate
1004            since that would deadlock */
1005         full_path = build_path_from_dentry(direntry);
1006         if (full_path == NULL) {
1007                 FreeXid(xid);
1008                 return -ENOMEM;
1009         }
1010         cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld "
1011                  "jiffies %ld", full_path, direntry->d_inode,
1012                  direntry->d_inode->i_count.counter, direntry,
1013                  direntry->d_time, jiffies));
1014
1015         if (cifsInode->time == 0) {
1016                 /* was set to zero previously to force revalidate */
1017         } else if (time_before(jiffies, cifsInode->time + HZ) &&
1018                    lookupCacheEnabled) {
1019                 if ((S_ISREG(direntry->d_inode->i_mode) == 0) ||
1020                     (direntry->d_inode->i_nlink == 1)) {
1021                         kfree(full_path);
1022                         FreeXid(xid);
1023                         return rc;
1024                 } else {
1025                         cFYI(1, ("Have to revalidate file due to hardlinks"));
1026                 }
1027         }
1028
1029         /* save mtime and size */
1030         local_mtime = direntry->d_inode->i_mtime;
1031         local_size = direntry->d_inode->i_size;
1032
1033         if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
1034                 rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
1035                                               direntry->d_sb,xid);
1036                 if (rc) {
1037                         cFYI(1, ("error on getting revalidate info %d", rc));
1038 /*                      if (rc != -ENOENT)
1039                                 rc = 0; */      /* BB should we cache info on
1040                                                    certain errors? */
1041                 }
1042         } else {
1043                 rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
1044                                          direntry->d_sb,xid);
1045                 if (rc) {
1046                         cFYI(1, ("error on getting revalidate info %d", rc));
1047 /*                      if (rc != -ENOENT)
1048                                 rc = 0; */      /* BB should we cache info on
1049                                                    certain errors? */
1050                 }
1051         }
1052         /* should we remap certain errors, access denied?, to zero */
1053
1054         /* if not oplocked, we invalidate inode pages if mtime or file size
1055            had changed on server */
1056
1057         if (timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) && 
1058             (local_size == direntry->d_inode->i_size)) {
1059                 cFYI(1, ("cifs_revalidate - inode unchanged"));
1060         } else {
1061                 /* file may have changed on server */
1062                 if (cifsInode->clientCanCacheRead) {
1063                         /* no need to invalidate inode pages since we were the
1064                            only ones who could have modified the file and the
1065                            server copy is staler than ours */
1066                 } else {
1067                         invalidate_inode = TRUE;
1068                 }
1069         }
1070
1071         /* can not grab this sem since kernel filesys locking documentation
1072            indicates i_mutex may be taken by the kernel on lookup and rename
1073            which could deadlock if we grab the i_mutex here as well */
1074 /*      mutex_lock(&direntry->d_inode->i_mutex);*/
1075         /* need to write out dirty pages here  */
1076         if (direntry->d_inode->i_mapping) {
1077                 /* do we need to lock inode until after invalidate completes
1078                    below? */
1079                 filemap_fdatawrite(direntry->d_inode->i_mapping);
1080         }
1081         if (invalidate_inode) {
1082         /* shrink_dcache not necessary now that cifs dentry ops
1083         are exported for negative dentries */
1084 /*              if(S_ISDIR(direntry->d_inode->i_mode)) 
1085                         shrink_dcache_parent(direntry); */
1086                 if (S_ISREG(direntry->d_inode->i_mode)) {
1087                         if (direntry->d_inode->i_mapping)
1088                                 filemap_fdatawait(direntry->d_inode->i_mapping);
1089                         /* may eventually have to do this for open files too */
1090                         if (list_empty(&(cifsInode->openFileList))) {
1091                                 /* changed on server - flush read ahead pages */
1092                                 cFYI(1, ("Invalidating read ahead data on "
1093                                          "closed file"));
1094                                 invalidate_remote_inode(direntry->d_inode);
1095                         }
1096                 }
1097         }
1098 /*      mutex_unlock(&direntry->d_inode->i_mutex); */
1099         
1100         kfree(full_path);
1101         FreeXid(xid);
1102         return rc;
1103 }
1104
1105 int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
1106         struct kstat *stat)
1107 {
1108         int err = cifs_revalidate(dentry);
1109         if (!err) {
1110                 generic_fillattr(dentry->d_inode, stat);
1111                 stat->blksize = CIFS_MAX_MSGSIZE;
1112         }
1113         return err;
1114 }
1115
1116 static int cifs_truncate_page(struct address_space *mapping, loff_t from)
1117 {
1118         pgoff_t index = from >> PAGE_CACHE_SHIFT;
1119         unsigned offset = from & (PAGE_CACHE_SIZE - 1);
1120         struct page *page;
1121         char *kaddr;
1122         int rc = 0;
1123
1124         page = grab_cache_page(mapping, index);
1125         if (!page)
1126                 return -ENOMEM;
1127
1128         kaddr = kmap_atomic(page, KM_USER0);
1129         memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
1130         flush_dcache_page(page);
1131         kunmap_atomic(kaddr, KM_USER0);
1132         unlock_page(page);
1133         page_cache_release(page);
1134         return rc;
1135 }
1136
1137 static int cifs_vmtruncate(struct inode * inode, loff_t offset)
1138 {
1139         struct address_space *mapping = inode->i_mapping;
1140         unsigned long limit;
1141
1142         spin_lock(&inode->i_lock);
1143         if (inode->i_size < offset)
1144                 goto do_expand;
1145         /*
1146          * truncation of in-use swapfiles is disallowed - it would cause
1147          * subsequent swapout to scribble on the now-freed blocks.
1148          */
1149         if (IS_SWAPFILE(inode)) {
1150                 spin_unlock(&inode->i_lock);
1151                 goto out_busy;
1152         }
1153         i_size_write(inode, offset);
1154         spin_unlock(&inode->i_lock);
1155         unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
1156         truncate_inode_pages(mapping, offset);
1157         goto out_truncate;
1158
1159 do_expand:
1160         limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
1161         if (limit != RLIM_INFINITY && offset > limit) {
1162                 spin_unlock(&inode->i_lock);
1163                 goto out_sig;
1164         }
1165         if (offset > inode->i_sb->s_maxbytes) {
1166                 spin_unlock(&inode->i_lock);
1167                 goto out_big;
1168         }
1169         i_size_write(inode, offset);
1170         spin_unlock(&inode->i_lock);
1171 out_truncate:
1172         if (inode->i_op && inode->i_op->truncate)
1173                 inode->i_op->truncate(inode);
1174         return 0;
1175 out_sig:
1176         send_sig(SIGXFSZ, current, 0);
1177 out_big:
1178         return -EFBIG;
1179 out_busy:
1180         return -ETXTBSY;
1181 }
1182
1183 int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
1184 {
1185         int xid;
1186         struct cifs_sb_info *cifs_sb;
1187         struct cifsTconInfo *pTcon;
1188         char *full_path = NULL;
1189         int rc = -EACCES;
1190         struct cifsFileInfo *open_file = NULL;
1191         FILE_BASIC_INFO time_buf;
1192         int set_time = FALSE;
1193         __u64 mode = 0xFFFFFFFFFFFFFFFFULL;
1194         __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
1195         __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
1196         struct cifsInodeInfo *cifsInode;
1197
1198         xid = GetXid();
1199
1200         cFYI(1, ("setattr on file %s attrs->iavalid 0x%x",
1201                  direntry->d_name.name, attrs->ia_valid));
1202
1203         cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
1204         pTcon = cifs_sb->tcon;
1205
1206         if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
1207                 /* check if we have permission to change attrs */
1208                 rc = inode_change_ok(direntry->d_inode, attrs);
1209                 if(rc < 0) {
1210                         FreeXid(xid);
1211                         return rc;
1212                 } else
1213                         rc = 0;
1214         }
1215                 
1216         full_path = build_path_from_dentry(direntry);
1217         if (full_path == NULL) {
1218                 FreeXid(xid);
1219                 return -ENOMEM;
1220         }
1221         cifsInode = CIFS_I(direntry->d_inode);
1222
1223         /* BB check if we need to refresh inode from server now ? BB */
1224
1225         /* need to flush data before changing file size on server */
1226         filemap_write_and_wait(direntry->d_inode->i_mapping);
1227
1228         if (attrs->ia_valid & ATTR_SIZE) {
1229                 /* To avoid spurious oplock breaks from server, in the case of
1230                    inodes that we already have open, avoid doing path based
1231                    setting of file size if we can do it by handle.
1232                    This keeps our caching token (oplock) and avoids timeouts
1233                    when the local oplock break takes longer to flush
1234                    writebehind data than the SMB timeout for the SetPathInfo
1235                    request would allow */
1236
1237                 open_file = find_writable_file(cifsInode);
1238                 if (open_file) {
1239                         __u16 nfid = open_file->netfid;
1240                         __u32 npid = open_file->pid;
1241                         rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
1242                                                 nfid, npid, FALSE);
1243                         atomic_dec(&open_file->wrtPending);
1244                         cFYI(1,("SetFSize for attrs rc = %d", rc));
1245                         if((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
1246                                 int bytes_written;
1247                                 rc = CIFSSMBWrite(xid, pTcon,
1248                                                   nfid, 0, attrs->ia_size,
1249                                                   &bytes_written, NULL, NULL,
1250                                                   1 /* 45 seconds */);
1251                                 cFYI(1,("Wrt seteof rc %d", rc));
1252                         }
1253                 } else 
1254                         rc = -EINVAL;
1255
1256                 if (rc != 0) {
1257                         /* Set file size by pathname rather than by handle
1258                            either because no valid, writeable file handle for
1259                            it was found or because there was an error setting
1260                            it by handle */
1261                         rc = CIFSSMBSetEOF(xid, pTcon, full_path,
1262                                            attrs->ia_size, FALSE,
1263                                            cifs_sb->local_nls, 
1264                                            cifs_sb->mnt_cifs_flags &
1265                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
1266                         cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc));
1267                         if((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
1268                                 __u16 netfid;
1269                                 int oplock = FALSE;
1270
1271                                 rc = SMBLegacyOpen(xid, pTcon, full_path,
1272                                         FILE_OPEN,
1273                                         SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
1274                                         CREATE_NOT_DIR, &netfid, &oplock,
1275                                         NULL, cifs_sb->local_nls,
1276                                         cifs_sb->mnt_cifs_flags &
1277                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
1278                                 if (rc==0) {
1279                                         int bytes_written;
1280                                         rc = CIFSSMBWrite(xid, pTcon,
1281                                                         netfid, 0,
1282                                                         attrs->ia_size,
1283                                                         &bytes_written, NULL,
1284                                                         NULL, 1 /* 45 sec */);
1285                                         cFYI(1,("wrt seteof rc %d",rc));
1286                                         CIFSSMBClose(xid, pTcon, netfid);
1287                                 }
1288
1289                         }
1290                 }
1291
1292                 /* Server is ok setting allocation size implicitly - no need
1293                    to call:
1294                 CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE,
1295                          cifs_sb->local_nls);
1296                    */
1297
1298                 if (rc == 0) {
1299                         rc = cifs_vmtruncate(direntry->d_inode, attrs->ia_size);
1300                         cifs_truncate_page(direntry->d_inode->i_mapping,
1301                                            direntry->d_inode->i_size);
1302                 } else 
1303                         goto cifs_setattr_exit;
1304         }
1305         if (attrs->ia_valid & ATTR_UID) {
1306                 cFYI(1, ("UID changed to %d", attrs->ia_uid));
1307                 uid = attrs->ia_uid;
1308         }
1309         if (attrs->ia_valid & ATTR_GID) {
1310                 cFYI(1, ("GID changed to %d", attrs->ia_gid));
1311                 gid = attrs->ia_gid;
1312         }
1313
1314         time_buf.Attributes = 0;
1315         if (attrs->ia_valid & ATTR_MODE) {
1316                 cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode));
1317                 mode = attrs->ia_mode;
1318         }
1319
1320         if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
1321             && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
1322                 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
1323                                          0 /* dev_t */, cifs_sb->local_nls,
1324                                          cifs_sb->mnt_cifs_flags & 
1325                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
1326         else if (attrs->ia_valid & ATTR_MODE) {
1327                 rc = 0;
1328                 if ((mode & S_IWUGO) == 0) /* not writeable */ {
1329                         if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0)
1330                                 time_buf.Attributes =
1331                                         cpu_to_le32(cifsInode->cifsAttrs |
1332                                                     ATTR_READONLY);
1333                 } else if ((mode & S_IWUGO) == S_IWUGO) {
1334                         if (cifsInode->cifsAttrs & ATTR_READONLY)
1335                                 time_buf.Attributes =
1336                                         cpu_to_le32(cifsInode->cifsAttrs &
1337                                                     (~ATTR_READONLY));
1338                 }
1339                 /* BB to be implemented -
1340                    via Windows security descriptors or streams */
1341                 /* CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, uid, gid,
1342                                       cifs_sb->local_nls); */
1343         }
1344
1345         if (attrs->ia_valid & ATTR_ATIME) {
1346                 set_time = TRUE;
1347                 time_buf.LastAccessTime =
1348                     cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
1349         } else
1350                 time_buf.LastAccessTime = 0;
1351
1352         if (attrs->ia_valid & ATTR_MTIME) {
1353                 set_time = TRUE;
1354                 time_buf.LastWriteTime =
1355                     cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
1356         } else
1357                 time_buf.LastWriteTime = 0;
1358         /* Do not set ctime explicitly unless other time
1359            stamps are changed explicitly (i.e. by utime()
1360            since we would then have a mix of client and
1361            server times */
1362            
1363         if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
1364                 set_time = TRUE;
1365                 /* Although Samba throws this field away
1366                 it may be useful to Windows - but we do
1367                 not want to set ctime unless some other
1368                 timestamp is changing */
1369                 cFYI(1, ("CIFS - CTIME changed"));
1370                 time_buf.ChangeTime =
1371                     cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
1372         } else
1373                 time_buf.ChangeTime = 0;
1374
1375         if (set_time || time_buf.Attributes) {
1376                 time_buf.CreationTime = 0;      /* do not change */
1377                 /* In the future we should experiment - try setting timestamps
1378                    via Handle (SetFileInfo) instead of by path */
1379                 if (!(pTcon->ses->flags & CIFS_SES_NT4))
1380                         rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
1381                                              cifs_sb->local_nls,
1382                                              cifs_sb->mnt_cifs_flags &
1383                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
1384                 else
1385                         rc = -EOPNOTSUPP;
1386
1387                 if (rc == -EOPNOTSUPP) {
1388                         int oplock = FALSE;
1389                         __u16 netfid;
1390
1391                         cFYI(1, ("calling SetFileInfo since SetPathInfo for "
1392                                  "times not supported by this server"));
1393                         /* BB we could scan to see if we already have it open
1394                            and pass in pid of opener to function */
1395                         rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
1396                                          SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
1397                                          CREATE_NOT_DIR, &netfid, &oplock,
1398                                          NULL, cifs_sb->local_nls,
1399                                          cifs_sb->mnt_cifs_flags &
1400                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
1401                         if (rc==0) {
1402                                 rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf,
1403                                                          netfid);
1404                                 CIFSSMBClose(xid, pTcon, netfid);
1405                         } else {
1406                         /* BB For even older servers we could convert time_buf
1407                            into old DOS style which uses two second
1408                            granularity */
1409
1410                         /* rc = CIFSSMBSetTimesLegacy(xid, pTcon, full_path,
1411                                         &time_buf, cifs_sb->local_nls); */
1412                         }
1413                 }
1414                 /* Even if error on time set, no sense failing the call if
1415                 the server would set the time to a reasonable value anyway,
1416                 and this check ensures that we are not being called from
1417                 sys_utimes in which case we ought to fail the call back to
1418                 the user when the server rejects the call */
1419                 if((rc) && (attrs->ia_valid &
1420                          (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
1421                         rc = 0;
1422         }
1423
1424         /* do not need local check to inode_check_ok since the server does
1425            that */
1426         if (!rc)
1427                 rc = inode_setattr(direntry->d_inode, attrs);
1428 cifs_setattr_exit:
1429         kfree(full_path);
1430         FreeXid(xid);
1431         return rc;
1432 }
1433
1434 #if 0
1435 void cifs_delete_inode(struct inode *inode)
1436 {
1437         cFYI(1, ("In cifs_delete_inode, inode = 0x%p", inode));
1438         /* may have to add back in if and when safe distributed caching of
1439            directories added e.g. via FindNotify */
1440 }
1441 #endif