]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/blob - fs/cifs/inode.c
Linux-2.6.12-rc2
[sojka/nv-tegra/linux-3.10.git] / 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/buffer_head.h>
23 #include <linux/stat.h>
24 #include <linux/pagemap.h>
25 #include <asm/div64.h>
26 #include "cifsfs.h"
27 #include "cifspdu.h"
28 #include "cifsglob.h"
29 #include "cifsproto.h"
30 #include "cifs_debug.h"
31 #include "cifs_fs_sb.h"
32
33 int cifs_get_inode_info_unix(struct inode **pinode,
34         const unsigned char *search_path, struct super_block *sb, int xid)
35 {
36         int rc = 0;
37         FILE_UNIX_BASIC_INFO findData;
38         struct cifsTconInfo *pTcon;
39         struct inode *inode;
40         struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
41         char *tmp_path;
42
43         pTcon = cifs_sb->tcon;
44         cFYI(1, (" Getting info on %s ", search_path));
45         /* could have done a find first instead but this returns more info */
46         rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData,
47                                   cifs_sb->local_nls);
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                         kfree(tmp_path);
68
69                         /* BB fix up inode etc. */
70                 } else if (rc) {
71                         return rc;
72                 }
73         } else {
74                 struct cifsInodeInfo *cifsInfo;
75                 __u32 type = le32_to_cpu(findData.Type);
76                 __u64 num_of_bytes = le64_to_cpu(findData.NumOfBytes);
77                 __u64 end_of_file = le64_to_cpu(findData.EndOfFile);
78
79                 /* get new inode */
80                 if (*pinode == NULL) {
81                         *pinode = new_inode(sb);
82                         if(*pinode == NULL) 
83                                 return -ENOMEM;
84                         /* Is an i_ino of zero legal? */
85                         /* Are there sanity checks we can use to ensure that
86                            the server is really filling in that field? */
87                         if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
88                                 (*pinode)->i_ino =
89                                         (unsigned long)findData.UniqueId;
90                         } /* note ino incremented to unique num in new_inode */
91                         insert_inode_hash(*pinode);
92                 }
93
94                 inode = *pinode;
95                 cifsInfo = CIFS_I(inode);
96
97                 cFYI(1, (" Old time %ld ", cifsInfo->time));
98                 cifsInfo->time = jiffies;
99                 cFYI(1, (" New time %ld ", cifsInfo->time));
100                 /* this is ok to set on every inode revalidate */
101                 atomic_set(&cifsInfo->inUse,1);
102
103                 inode->i_atime =
104                     cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime));
105                 inode->i_mtime =
106                     cifs_NTtimeToUnix(le64_to_cpu
107                                 (findData.LastModificationTime));
108                 inode->i_ctime =
109                     cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange));
110                 inode->i_mode = le64_to_cpu(findData.Permissions);
111                 if (type == UNIX_FILE) {
112                         inode->i_mode |= S_IFREG;
113                 } else if (type == UNIX_SYMLINK) {
114                         inode->i_mode |= S_IFLNK;
115                 } else if (type == UNIX_DIR) {
116                         inode->i_mode |= S_IFDIR;
117                 } else if (type == UNIX_CHARDEV) {
118                         inode->i_mode |= S_IFCHR;
119                         inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor),
120                                 le64_to_cpu(findData.DevMinor) & MINORMASK);
121                 } else if (type == UNIX_BLOCKDEV) {
122                         inode->i_mode |= S_IFBLK;
123                         inode->i_rdev = MKDEV(le64_to_cpu(findData.DevMajor),
124                                 le64_to_cpu(findData.DevMinor) & MINORMASK);
125                 } else if (type == UNIX_FIFO) {
126                         inode->i_mode |= S_IFIFO;
127                 } else if (type == UNIX_SOCKET) {
128                         inode->i_mode |= S_IFSOCK;
129                 }
130                 inode->i_uid = le64_to_cpu(findData.Uid);
131                 inode->i_gid = le64_to_cpu(findData.Gid);
132                 inode->i_nlink = le64_to_cpu(findData.Nlinks);
133
134                 if(is_size_safe_to_change(cifsInfo)) {
135                 /* can not safely change the file size here if the
136                    client is writing to it due to potential races */
137
138                         i_size_write(inode, end_of_file);
139
140                 /* blksize needs to be multiple of two. So safer to default to
141                 blksize and blkbits set in superblock so 2**blkbits and blksize
142                 will match rather than setting to:
143                 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
144
145                 /* This seems incredibly stupid but it turns out that i_blocks
146                    is not related to (i_size / i_blksize), instead 512 byte size
147                    is required for calculating num blocks */
148
149                 /* 512 bytes (2**9) is the fake blocksize that must be used */
150                 /* for this calculation */
151                         inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
152                 }
153
154                 if (num_of_bytes < end_of_file)
155                         cFYI(1, ("allocation size less than end of file "));
156                 cFYI(1,
157                      ("Size %ld and blocks %ld",
158                       (unsigned long) inode->i_size, inode->i_blocks));
159                 if (S_ISREG(inode->i_mode)) {
160                         cFYI(1, (" File inode "));
161                         inode->i_op = &cifs_file_inode_ops;
162                         if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
163                                 inode->i_fop = &cifs_file_direct_ops;
164                         else
165                                 inode->i_fop = &cifs_file_ops;
166                         inode->i_data.a_ops = &cifs_addr_ops;
167                 } else if (S_ISDIR(inode->i_mode)) {
168                         cFYI(1, (" Directory inode"));
169                         inode->i_op = &cifs_dir_inode_ops;
170                         inode->i_fop = &cifs_dir_ops;
171                 } else if (S_ISLNK(inode->i_mode)) {
172                         cFYI(1, (" Symbolic Link inode "));
173                         inode->i_op = &cifs_symlink_inode_ops;
174                 /* tmp_inode->i_fop = */ /* do not need to set to anything */
175                 } else {
176                         cFYI(1, (" Init special inode "));
177                         init_special_inode(inode, inode->i_mode,
178                                            inode->i_rdev);
179                 }
180         }
181         return rc;
182 }
183
184 int cifs_get_inode_info(struct inode **pinode,
185         const unsigned char *search_path, FILE_ALL_INFO *pfindData,
186         struct super_block *sb, int xid)
187 {
188         int rc = 0;
189         struct cifsTconInfo *pTcon;
190         struct inode *inode;
191         struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
192         char *tmp_path;
193         char *buf = NULL;
194
195         pTcon = cifs_sb->tcon;
196         cFYI(1,("Getting info on %s ", search_path));
197
198         if((pfindData == NULL) && (*pinode != NULL)) {
199                 if(CIFS_I(*pinode)->clientCanCacheRead) {
200                         cFYI(1,("No need to revalidate cached inode sizes"));
201                         return rc;
202                 }
203         }
204
205         /* if file info not passed in then get it from server */
206         if(pfindData == NULL) {
207                 buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
208                 if(buf == NULL)
209                         return -ENOMEM;
210                 pfindData = (FILE_ALL_INFO *)buf;
211                 /* could do find first instead but this returns more info */
212                 rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
213                               cifs_sb->local_nls);
214         }
215         /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
216         if (rc) {
217                 if (rc == -EREMOTE) {
218                         tmp_path =
219                             kmalloc(strnlen
220                                     (pTcon->treeName,
221                                      MAX_TREE_SIZE + 1) +
222                                     strnlen(search_path, MAX_PATHCONF) + 1,
223                                     GFP_KERNEL);
224                         if (tmp_path == NULL) {
225                                 kfree(buf);
226                                 return -ENOMEM;
227                         }
228
229                         strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
230                         strncat(tmp_path, search_path, MAX_PATHCONF);
231                         rc = connect_to_dfs_path(xid, pTcon->ses,
232                                                  /* treename + */ tmp_path,
233                                                  cifs_sb->local_nls);
234                         kfree(tmp_path);
235                         /* BB fix up inode etc. */
236                 } else if (rc) {
237                         kfree(buf);
238                         return rc;
239                 }
240         } else {
241                 struct cifsInodeInfo *cifsInfo;
242                 __u32 attr = le32_to_cpu(pfindData->Attributes);
243
244                 /* get new inode */
245                 if (*pinode == NULL) {
246                         *pinode = new_inode(sb);
247                         if (*pinode == NULL)
248                                 return -ENOMEM;
249                         /* Is an i_ino of zero legal? Can we use that to check
250                            if the server supports returning inode numbers?  Are
251                            there other sanity checks we can use to ensure that
252                            the server is really filling in that field? */
253
254                         /* We can not use the IndexNumber field by default from
255                            Windows or Samba (in ALL_INFO buf) but we can request
256                            it explicitly.  It may not be unique presumably if
257                            the server has multiple devices mounted under one
258                            share */
259
260                         /* There may be higher info levels that work but are
261                            there Windows server or network appliances for which
262                            IndexNumber field is not guaranteed unique? */
263
264 #ifdef CONFIG_CIFS_EXPERIMENTAL         
265                         if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM){
266                                 int rc1 = 0;
267                                 __u64 inode_num;
268
269                                 rc1 = CIFSGetSrvInodeNumber(xid, pTcon, 
270                                         search_path, &inode_num, 
271                                         cifs_sb->local_nls);
272                                 if(rc1) {
273                                         cFYI(1,("GetSrvInodeNum rc %d", rc1));
274                                         /* BB EOPNOSUPP disable SERVER_INUM? */
275                                 } else /* do we need cast or hash to ino? */
276                                         (*pinode)->i_ino = inode_num;
277                         } /* else ino incremented to unique num in new_inode*/
278 #endif /* CIFS_EXPERIMENTAL */
279                         insert_inode_hash(*pinode);
280                 }
281                 inode = *pinode;
282                 cifsInfo = CIFS_I(inode);
283                 cifsInfo->cifsAttrs = attr;
284                 cFYI(1, (" Old time %ld ", cifsInfo->time));
285                 cifsInfo->time = jiffies;
286                 cFYI(1, (" New time %ld ", cifsInfo->time));
287
288                 /* blksize needs to be multiple of two. So safer to default to
289                 blksize and blkbits set in superblock so 2**blkbits and blksize
290                 will match rather than setting to:
291                 (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
292
293                 /* Linux can not store file creation time unfortunately so we ignore it */
294                 inode->i_atime =
295                     cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
296                 inode->i_mtime =
297                     cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
298                 inode->i_ctime =
299                     cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
300                 cFYI(0, (" Attributes came in as 0x%x ", attr));
301
302                 /* set default mode. will override for dirs below */
303                 if (atomic_read(&cifsInfo->inUse) == 0)
304                         /* new inode, can safely set these fields */
305                         inode->i_mode = cifs_sb->mnt_file_mode;
306
307 /*              if (attr & ATTR_REPARSE)  */
308                 /* We no longer handle these as symlinks because we could not
309                    follow them due to the absolute path with drive letter */
310                 if (attr & ATTR_DIRECTORY) {
311                 /* override default perms since we do not do byte range locking
312                    on dirs */
313                         inode->i_mode = cifs_sb->mnt_dir_mode;
314                         inode->i_mode |= S_IFDIR;
315                 } else {
316                         inode->i_mode |= S_IFREG;
317                         /* treat the dos attribute of read-only as read-only
318                            mode e.g. 555 */
319                         if (cifsInfo->cifsAttrs & ATTR_READONLY)
320                                 inode->i_mode &= ~(S_IWUGO);
321                 /* BB add code here -
322                    validate if device or weird share or device type? */
323                 }
324                 if (is_size_safe_to_change(cifsInfo)) {
325                         /* can not safely change the file size here if the
326                            client is writing to it due to potential races */
327                         i_size_write(inode,le64_to_cpu(pfindData->EndOfFile));
328
329                         /* 512 bytes (2**9) is the fake blocksize that must be
330                            used for this calculation */
331                         inode->i_blocks = (512 - 1 + le64_to_cpu(
332                                            pfindData->AllocationSize)) >> 9;
333                 }
334
335                 inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
336
337                 /* BB fill in uid and gid here? with help from winbind? 
338                    or retrieve from NTFS stream extended attribute */
339                 if (atomic_read(&cifsInfo->inUse) == 0) {
340                         inode->i_uid = cifs_sb->mnt_uid;
341                         inode->i_gid = cifs_sb->mnt_gid;
342                         /* set so we do not keep refreshing these fields with
343                            bad data after user has changed them in memory */
344                         atomic_set(&cifsInfo->inUse,1);
345                 }
346
347                 if (S_ISREG(inode->i_mode)) {
348                         cFYI(1, (" File inode "));
349                         inode->i_op = &cifs_file_inode_ops;
350                         if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO)
351                                 inode->i_fop = &cifs_file_direct_ops;
352                         else
353                                 inode->i_fop = &cifs_file_ops;
354                         inode->i_data.a_ops = &cifs_addr_ops;
355                 } else if (S_ISDIR(inode->i_mode)) {
356                         cFYI(1, (" Directory inode "));
357                         inode->i_op = &cifs_dir_inode_ops;
358                         inode->i_fop = &cifs_dir_ops;
359                 } else if (S_ISLNK(inode->i_mode)) {
360                         cFYI(1, (" Symbolic Link inode "));
361                         inode->i_op = &cifs_symlink_inode_ops;
362                 } else {
363                         init_special_inode(inode, inode->i_mode,
364                                            inode->i_rdev);
365                 }
366         }
367         kfree(buf);
368         return rc;
369 }
370
371 /* gets root inode */
372 void cifs_read_inode(struct inode *inode)
373 {
374         int xid;
375         struct cifs_sb_info *cifs_sb;
376
377         cifs_sb = CIFS_SB(inode->i_sb);
378         xid = GetXid();
379         if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
380                 cifs_get_inode_info_unix(&inode, "", inode->i_sb,xid);
381         else
382                 cifs_get_inode_info(&inode, "", NULL, inode->i_sb,xid);
383         /* can not call macro FreeXid here since in a void func */
384         _FreeXid(xid);
385 }
386
387 int cifs_unlink(struct inode *inode, struct dentry *direntry)
388 {
389         int rc = 0;
390         int xid;
391         struct cifs_sb_info *cifs_sb;
392         struct cifsTconInfo *pTcon;
393         char *full_path = NULL;
394         struct cifsInodeInfo *cifsInode;
395         FILE_BASIC_INFO *pinfo_buf;
396
397         cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode));
398
399         xid = GetXid();
400
401         cifs_sb = CIFS_SB(inode->i_sb);
402         pTcon = cifs_sb->tcon;
403
404         /* Unlink can be called from rename so we can not grab the sem here
405            since we deadlock otherwise */
406 /*      down(&direntry->d_sb->s_vfs_rename_sem);*/
407         full_path = build_path_from_dentry(direntry);
408 /*      up(&direntry->d_sb->s_vfs_rename_sem);*/
409         if (full_path == NULL) {
410                 FreeXid(xid);
411                 return -ENOMEM;
412         }
413         rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
414
415         if (!rc) {
416                 direntry->d_inode->i_nlink--;
417         } else if (rc == -ENOENT) {
418                 d_drop(direntry);
419         } else if (rc == -ETXTBSY) {
420                 int oplock = FALSE;
421                 __u16 netfid;
422
423                 rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
424                                  CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
425                                  &netfid, &oplock, NULL, cifs_sb->local_nls);
426                 if (rc==0) {
427                         CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL,
428                                               cifs_sb->local_nls);
429                         CIFSSMBClose(xid, pTcon, netfid);
430                         direntry->d_inode->i_nlink--;
431                 }
432         } else if (rc == -EACCES) {
433                 /* try only if r/o attribute set in local lookup data? */
434                 pinfo_buf = kmalloc(sizeof(FILE_BASIC_INFO), GFP_KERNEL);
435                 if (pinfo_buf) {
436                         memset(pinfo_buf, 0, sizeof(FILE_BASIC_INFO));
437                         /* ATTRS set to normal clears r/o bit */
438                         pinfo_buf->Attributes = cpu_to_le32(ATTR_NORMAL);
439                         if (!(pTcon->ses->flags & CIFS_SES_NT4))
440                                 rc = CIFSSMBSetTimes(xid, pTcon, full_path,
441                                                      pinfo_buf,
442                                                      cifs_sb->local_nls);
443                         else
444                                 rc = -EOPNOTSUPP;
445
446                         if (rc == -EOPNOTSUPP) {
447                                 int oplock = FALSE;
448                                 __u16 netfid;
449                         /*      rc = CIFSSMBSetAttrLegacy(xid, pTcon,
450                                                           full_path,
451                                                           (__u16)ATTR_NORMAL,
452                                                           cifs_sb->local_nls); 
453                            For some strange reason it seems that NT4 eats the
454                            old setattr call without actually setting the
455                            attributes so on to the third attempted workaround
456                            */
457
458                         /* BB could scan to see if we already have it open
459                            and pass in pid of opener to function */
460                                 rc = CIFSSMBOpen(xid, pTcon, full_path,
461                                                  FILE_OPEN, SYNCHRONIZE |
462                                                  FILE_WRITE_ATTRIBUTES, 0,
463                                                  &netfid, &oplock, NULL,
464                                                  cifs_sb->local_nls);
465                                 if (rc==0) {
466                                         rc = CIFSSMBSetFileTimes(xid, pTcon,
467                                                                  pinfo_buf,
468                                                                  netfid);
469                                         CIFSSMBClose(xid, pTcon, netfid);
470                                 }
471                         }
472                         kfree(pinfo_buf);
473                 }
474                 if (rc==0) {
475                         rc = CIFSSMBDelFile(xid, pTcon, full_path,
476                                             cifs_sb->local_nls);
477                         if (!rc) {
478                                 direntry->d_inode->i_nlink--;
479                         } else if (rc == -ETXTBSY) {
480                                 int oplock = FALSE;
481                                 __u16 netfid;
482
483                                 rc = CIFSSMBOpen(xid, pTcon, full_path,
484                                                  FILE_OPEN, DELETE,
485                                                  CREATE_NOT_DIR |
486                                                  CREATE_DELETE_ON_CLOSE,
487                                                  &netfid, &oplock, NULL,
488                                                  cifs_sb->local_nls);
489                                 if (rc==0) {
490                                         CIFSSMBRenameOpenFile(xid, pTcon,
491                                                 netfid, NULL,
492                                                 cifs_sb->local_nls);
493                                         CIFSSMBClose(xid, pTcon, netfid);
494                                         direntry->d_inode->i_nlink--;
495                                 }
496                         /* BB if rc = -ETXTBUSY goto the rename logic BB */
497                         }
498                 }
499         }
500         cifsInode = CIFS_I(direntry->d_inode);
501         cifsInode->time = 0;    /* will force revalidate to get info when
502                                    needed */
503         direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
504                 current_fs_time(inode->i_sb);
505         cifsInode = CIFS_I(inode);
506         cifsInode->time = 0;    /* force revalidate of dir as well */
507
508         kfree(full_path);
509         FreeXid(xid);
510         return rc;
511 }
512
513 int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
514 {
515         int rc = 0;
516         int xid;
517         struct cifs_sb_info *cifs_sb;
518         struct cifsTconInfo *pTcon;
519         char *full_path = NULL;
520         struct inode *newinode = NULL;
521
522         cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode));
523
524         xid = GetXid();
525
526         cifs_sb = CIFS_SB(inode->i_sb);
527         pTcon = cifs_sb->tcon;
528
529         down(&inode->i_sb->s_vfs_rename_sem);
530         full_path = build_path_from_dentry(direntry);
531         up(&inode->i_sb->s_vfs_rename_sem);
532         if (full_path == NULL) {
533                 FreeXid(xid);
534                 return -ENOMEM;
535         }
536         /* BB add setting the equivalent of mode via CreateX w/ACLs */
537         rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls);
538         if (rc) {
539                 cFYI(1, ("cifs_mkdir returned 0x%x ", rc));
540                 d_drop(direntry);
541         } else {
542                 inode->i_nlink++;
543                 if (pTcon->ses->capabilities & CAP_UNIX)
544                         rc = cifs_get_inode_info_unix(&newinode, full_path,
545                                                       inode->i_sb,xid);
546                 else
547                         rc = cifs_get_inode_info(&newinode, full_path, NULL,
548                                                  inode->i_sb,xid);
549
550                 direntry->d_op = &cifs_dentry_ops;
551                 d_instantiate(direntry, newinode);
552                 if (direntry->d_inode)
553                         direntry->d_inode->i_nlink = 2;
554                 if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
555                         if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
556                                 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
557                                                     mode,
558                                                     (__u64)current->euid,
559                                                     (__u64)current->egid,
560                                                     0 /* dev_t */,
561                                                     cifs_sb->local_nls);
562                         } else {
563                                 CIFSSMBUnixSetPerms(xid, pTcon, full_path,
564                                                     mode, (__u64)-1,
565                                                     (__u64)-1, 0 /* dev_t */,
566                                                     cifs_sb->local_nls);
567                         }
568                 else {
569                         /* BB to be implemented via Windows secrty descriptors
570                            eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
571                                                  -1, -1, local_nls); */
572                 }
573         }
574         kfree(full_path);
575         FreeXid(xid);
576         return rc;
577 }
578
579 int cifs_rmdir(struct inode *inode, struct dentry *direntry)
580 {
581         int rc = 0;
582         int xid;
583         struct cifs_sb_info *cifs_sb;
584         struct cifsTconInfo *pTcon;
585         char *full_path = NULL;
586         struct cifsInodeInfo *cifsInode;
587
588         cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode));
589
590         xid = GetXid();
591
592         cifs_sb = CIFS_SB(inode->i_sb);
593         pTcon = cifs_sb->tcon;
594
595         down(&inode->i_sb->s_vfs_rename_sem);
596         full_path = build_path_from_dentry(direntry);
597         up(&inode->i_sb->s_vfs_rename_sem);
598         if (full_path == NULL) {
599                 FreeXid(xid);
600                 return -ENOMEM;
601         }
602
603         rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls);
604
605         if (!rc) {
606                 inode->i_nlink--;
607                 i_size_write(direntry->d_inode,0);
608                 direntry->d_inode->i_nlink = 0;
609         }
610
611         cifsInode = CIFS_I(direntry->d_inode);
612         cifsInode->time = 0;    /* force revalidate to go get info when
613                                    needed */
614         direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime =
615                 current_fs_time(inode->i_sb);
616
617         kfree(full_path);
618         FreeXid(xid);
619         return rc;
620 }
621
622 int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
623         struct inode *target_inode, struct dentry *target_direntry)
624 {
625         char *fromName;
626         char *toName;
627         struct cifs_sb_info *cifs_sb_source;
628         struct cifs_sb_info *cifs_sb_target;
629         struct cifsTconInfo *pTcon;
630         int xid;
631         int rc = 0;
632
633         xid = GetXid();
634
635         cifs_sb_target = CIFS_SB(target_inode->i_sb);
636         cifs_sb_source = CIFS_SB(source_inode->i_sb);
637         pTcon = cifs_sb_source->tcon;
638
639         if (pTcon != cifs_sb_target->tcon) {
640                 FreeXid(xid);
641                 return -EXDEV;  /* BB actually could be allowed if same server,
642                                    but different share.
643                                    Might eventually add support for this */
644         }
645
646         /* we already  have the rename sem so we do not need to grab it again
647            here to protect the path integrity */
648         fromName = build_path_from_dentry(source_direntry);
649         toName = build_path_from_dentry(target_direntry);
650         if ((fromName == NULL) || (toName == NULL)) {
651                 rc = -ENOMEM;
652                 goto cifs_rename_exit;
653         }
654
655         rc = CIFSSMBRename(xid, pTcon, fromName, toName,
656                            cifs_sb_source->local_nls);
657         if (rc == -EEXIST) {
658                 /* check if they are the same file because rename of hardlinked
659                    files is a noop */
660                 FILE_UNIX_BASIC_INFO *info_buf_source;
661                 FILE_UNIX_BASIC_INFO *info_buf_target;
662
663                 info_buf_source =
664                         kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
665                 if (info_buf_source != NULL) {
666                         info_buf_target = info_buf_source + 1;
667                         rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
668                                 info_buf_source, cifs_sb_source->local_nls);
669                         if (rc == 0) {
670                                 rc = CIFSSMBUnixQPathInfo(xid, pTcon, toName,
671                                                 info_buf_target,
672                                                 cifs_sb_target->local_nls);
673                         }
674                         if ((rc == 0) &&
675                             (info_buf_source->UniqueId ==
676                              info_buf_target->UniqueId)) {
677                         /* do not rename since the files are hardlinked which
678                            is a noop */
679                         } else {
680                         /* we either can not tell the files are hardlinked
681                            (as with Windows servers) or files are not
682                            hardlinked so delete the target manually before
683                            renaming to follow POSIX rather than Windows
684                            semantics */
685                                 cifs_unlink(target_inode, target_direntry);
686                                 rc = CIFSSMBRename(xid, pTcon, fromName,
687                                                    toName,
688                                                    cifs_sb_source->local_nls);
689                         }
690                         kfree(info_buf_source);
691                 } /* if we can not get memory just leave rc as EEXIST */
692         }
693
694         if (rc) {
695                 cFYI(1, ("rename rc %d", rc));
696         }
697
698         if ((rc == -EIO) || (rc == -EEXIST)) {
699                 int oplock = FALSE;
700                 __u16 netfid;
701
702                 /* BB FIXME Is Generic Read correct for rename? */
703                 /* if renaming directory - we should not say CREATE_NOT_DIR,
704                    need to test renaming open directory, also GENERIC_READ
705                    might not right be right access to request */
706                 rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
707                                  CREATE_NOT_DIR, &netfid, &oplock, NULL,
708                                  cifs_sb_source->local_nls);
709                 if (rc==0) {
710                         CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName,
711                                               cifs_sb_source->local_nls);
712                         CIFSSMBClose(xid, pTcon, netfid);
713                 }
714         }
715
716 cifs_rename_exit:
717         kfree(fromName);
718         kfree(toName);
719         FreeXid(xid);
720         return rc;
721 }
722
723 int cifs_revalidate(struct dentry *direntry)
724 {
725         int xid;
726         int rc = 0;
727         char *full_path;
728         struct cifs_sb_info *cifs_sb;
729         struct cifsInodeInfo *cifsInode;
730         loff_t local_size;
731         struct timespec local_mtime;
732         int invalidate_inode = FALSE;
733
734         if (direntry->d_inode == NULL)
735                 return -ENOENT;
736
737         cifsInode = CIFS_I(direntry->d_inode);
738
739         if (cifsInode == NULL)
740                 return -ENOENT;
741
742         /* no sense revalidating inode info on file that no one can write */
743         if (CIFS_I(direntry->d_inode)->clientCanCacheRead)
744                 return rc;
745
746         xid = GetXid();
747
748         cifs_sb = CIFS_SB(direntry->d_sb);
749
750         /* can not safely grab the rename sem here if rename calls revalidate
751            since that would deadlock */
752         full_path = build_path_from_dentry(direntry);
753         if (full_path == NULL) {
754                 FreeXid(xid);
755                 return -ENOMEM;
756         }
757         cFYI(1, ("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld "
758                  "jiffies %ld", full_path, direntry->d_inode,
759                  direntry->d_inode->i_count.counter, direntry,
760                  direntry->d_time, jiffies));
761
762         if (cifsInode->time == 0) {
763                 /* was set to zero previously to force revalidate */
764         } else if (time_before(jiffies, cifsInode->time + HZ) &&
765                    lookupCacheEnabled) {
766                 if ((S_ISREG(direntry->d_inode->i_mode) == 0) ||
767                     (direntry->d_inode->i_nlink == 1)) {
768                         kfree(full_path);
769                         FreeXid(xid);
770                         return rc;
771                 } else {
772                         cFYI(1, ("Have to revalidate file due to hardlinks"));
773                 }
774         }
775
776         /* save mtime and size */
777         local_mtime = direntry->d_inode->i_mtime;
778         local_size = direntry->d_inode->i_size;
779
780         if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
781                 rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
782                                               direntry->d_sb,xid);
783                 if (rc) {
784                         cFYI(1, ("error on getting revalidate info %d", rc));
785 /*                      if (rc != -ENOENT)
786                                 rc = 0; */      /* BB should we cache info on
787                                                    certain errors? */
788                 }
789         } else {
790                 rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
791                                          direntry->d_sb,xid);
792                 if (rc) {
793                         cFYI(1, ("error on getting revalidate info %d", rc));
794 /*                      if (rc != -ENOENT)
795                                 rc = 0; */      /* BB should we cache info on
796                                                    certain errors? */
797                 }
798         }
799         /* should we remap certain errors, access denied?, to zero */
800
801         /* if not oplocked, we invalidate inode pages if mtime or file size
802            had changed on server */
803
804         if (timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) && 
805             (local_size == direntry->d_inode->i_size)) {
806                 cFYI(1, ("cifs_revalidate - inode unchanged"));
807         } else {
808                 /* file may have changed on server */
809                 if (cifsInode->clientCanCacheRead) {
810                         /* no need to invalidate inode pages since we were the
811                            only ones who could have modified the file and the
812                            server copy is staler than ours */
813                 } else {
814                         invalidate_inode = TRUE;
815                 }
816         }
817
818         /* can not grab this sem since kernel filesys locking documentation
819            indicates i_sem may be taken by the kernel on lookup and rename
820            which could deadlock if we grab the i_sem here as well */
821 /*      down(&direntry->d_inode->i_sem);*/
822         /* need to write out dirty pages here  */
823         if (direntry->d_inode->i_mapping) {
824                 /* do we need to lock inode until after invalidate completes
825                    below? */
826                 filemap_fdatawrite(direntry->d_inode->i_mapping);
827         }
828         if (invalidate_inode) {
829                 if (direntry->d_inode->i_mapping)
830                         filemap_fdatawait(direntry->d_inode->i_mapping);
831                 /* may eventually have to do this for open files too */
832                 if (list_empty(&(cifsInode->openFileList))) {
833                         /* Has changed on server - flush read ahead pages */
834                         cFYI(1, ("Invalidating read ahead data on "
835                                  "closed file"));
836                         invalidate_remote_inode(direntry->d_inode);
837                 }
838         }
839 /*      up(&direntry->d_inode->i_sem); */
840         
841         kfree(full_path);
842         FreeXid(xid);
843         return rc;
844 }
845
846 int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
847         struct kstat *stat)
848 {
849         int err = cifs_revalidate(dentry);
850         if (!err)
851                 generic_fillattr(dentry->d_inode, stat);
852         return err;
853 }
854
855 static int cifs_truncate_page(struct address_space *mapping, loff_t from)
856 {
857         pgoff_t index = from >> PAGE_CACHE_SHIFT;
858         unsigned offset = from & (PAGE_CACHE_SIZE - 1);
859         struct page *page;
860         char *kaddr;
861         int rc = 0;
862
863         page = grab_cache_page(mapping, index);
864         if (!page)
865                 return -ENOMEM;
866
867         kaddr = kmap_atomic(page, KM_USER0);
868         memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
869         flush_dcache_page(page);
870         kunmap_atomic(kaddr, KM_USER0);
871         unlock_page(page);
872         page_cache_release(page);
873         return rc;
874 }
875
876 int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
877 {
878         int xid;
879         struct cifs_sb_info *cifs_sb;
880         struct cifsTconInfo *pTcon;
881         char *full_path = NULL;
882         int rc = -EACCES;
883         int found = FALSE;
884         struct cifsFileInfo *open_file = NULL;
885         FILE_BASIC_INFO time_buf;
886         int set_time = FALSE;
887         __u64 mode = 0xFFFFFFFFFFFFFFFFULL;
888         __u64 uid = 0xFFFFFFFFFFFFFFFFULL;
889         __u64 gid = 0xFFFFFFFFFFFFFFFFULL;
890         struct cifsInodeInfo *cifsInode;
891         struct list_head *tmp;
892
893         xid = GetXid();
894
895         cFYI(1, (" In cifs_setattr, name = %s attrs->iavalid 0x%x ",
896                  direntry->d_name.name, attrs->ia_valid));
897         cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
898         pTcon = cifs_sb->tcon;
899
900         down(&direntry->d_sb->s_vfs_rename_sem);
901         full_path = build_path_from_dentry(direntry);
902         up(&direntry->d_sb->s_vfs_rename_sem);
903         if (full_path == NULL) {
904                 FreeXid(xid);
905                 return -ENOMEM;
906         }
907         cifsInode = CIFS_I(direntry->d_inode);
908
909         /* BB check if we need to refresh inode from server now ? BB */
910
911         /* need to flush data before changing file size on server */
912         filemap_fdatawrite(direntry->d_inode->i_mapping);
913         filemap_fdatawait(direntry->d_inode->i_mapping);
914
915         if (attrs->ia_valid & ATTR_SIZE) {
916                 read_lock(&GlobalSMBSeslock);
917                 /* To avoid spurious oplock breaks from server, in the case of
918                    inodes that we already have open, avoid doing path based
919                    setting of file size if we can do it by handle.
920                    This keeps our caching token (oplock) and avoids timeouts
921                    when the local oplock break takes longer to flush
922                    writebehind data than the SMB timeout for the SetPathInfo
923                    request would allow */
924                 list_for_each(tmp, &cifsInode->openFileList) {
925                         open_file = list_entry(tmp, struct cifsFileInfo,
926                                                flist);
927                         /* We check if file is open for writing first */
928                         if ((open_file->pfile) &&
929                             ((open_file->pfile->f_flags & O_RDWR) ||
930                             (open_file->pfile->f_flags & O_WRONLY))) {
931                                 if (open_file->invalidHandle == FALSE) {
932                                         /* we found a valid, writeable network
933                                            file handle to use to try to set the
934                                            file size */
935                                         __u16 nfid = open_file->netfid;
936                                         __u32 npid = open_file->pid;
937                                         read_unlock(&GlobalSMBSeslock);
938                                         found = TRUE;
939                                         rc = CIFSSMBSetFileSize(xid, pTcon,
940                                                 attrs->ia_size, nfid, npid,
941                                                 FALSE);
942                                         cFYI(1, ("SetFileSize by handle "
943                                                  "(setattrs) rc = %d", rc));
944                                         /* Do not need reopen and retry on
945                                            EAGAIN since we will retry by
946                                            pathname below */
947
948                                         /* now that we found one valid file
949                                            handle no sense continuing to loop
950                                            trying others, so break here */
951                                         break;
952                                 }
953                         }
954                 }
955                 if (found == FALSE)
956                         read_unlock(&GlobalSMBSeslock);
957
958                 if (rc != 0) {
959                         /* Set file size by pathname rather than by handle
960                            either because no valid, writeable file handle for
961                            it was found or because there was an error setting
962                            it by handle */
963                         rc = CIFSSMBSetEOF(xid, pTcon, full_path,
964                                            attrs->ia_size, FALSE,
965                                            cifs_sb->local_nls);
966                         cFYI(1, (" SetEOF by path (setattrs) rc = %d", rc));
967                 }
968
969                 /* Server is ok setting allocation size implicitly - no need
970                    to call:
971                 CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size, TRUE,
972                          cifs_sb->local_nls);
973                    */
974
975                 if (rc == 0) {
976                         rc = vmtruncate(direntry->d_inode, attrs->ia_size);
977                         cifs_truncate_page(direntry->d_inode->i_mapping,
978                                            direntry->d_inode->i_size);
979                 }
980         }
981         if (attrs->ia_valid & ATTR_UID) {
982                 cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid));
983                 uid = attrs->ia_uid;
984                 /* entry->uid = cpu_to_le16(attr->ia_uid); */
985         }
986         if (attrs->ia_valid & ATTR_GID) {
987                 cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid));
988                 gid = attrs->ia_gid;
989                 /* entry->gid = cpu_to_le16(attr->ia_gid); */
990         }
991
992         time_buf.Attributes = 0;
993         if (attrs->ia_valid & ATTR_MODE) {
994                 cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode));
995                 mode = attrs->ia_mode;
996                 /* entry->mode = cpu_to_le16(attr->ia_mode); */
997         }
998
999         if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
1000             && (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
1001                 rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
1002                                          0 /* dev_t */, cifs_sb->local_nls);
1003         else if (attrs->ia_valid & ATTR_MODE) {
1004                 if ((mode & S_IWUGO) == 0) /* not writeable */ {
1005                         if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0)
1006                                 time_buf.Attributes =
1007                                         cpu_to_le32(cifsInode->cifsAttrs |
1008                                                     ATTR_READONLY);
1009                 } else if ((mode & S_IWUGO) == S_IWUGO) {
1010                         if (cifsInode->cifsAttrs & ATTR_READONLY)
1011                                 time_buf.Attributes =
1012                                         cpu_to_le32(cifsInode->cifsAttrs &
1013                                                     (~ATTR_READONLY));
1014                 }
1015                 /* BB to be implemented -
1016                    via Windows security descriptors or streams */
1017                 /* CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, uid, gid,
1018                                       cifs_sb->local_nls); */
1019         }
1020
1021         if (attrs->ia_valid & ATTR_ATIME) {
1022                 set_time = TRUE;
1023                 time_buf.LastAccessTime =
1024                     cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_atime));
1025         } else
1026                 time_buf.LastAccessTime = 0;
1027
1028         if (attrs->ia_valid & ATTR_MTIME) {
1029                 set_time = TRUE;
1030                 time_buf.LastWriteTime =
1031                     cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime));
1032         } else
1033                 time_buf.LastWriteTime = 0;
1034
1035         if (attrs->ia_valid & ATTR_CTIME) {
1036                 set_time = TRUE;
1037                 cFYI(1, (" CIFS - CTIME changed ")); /* BB probably no need */
1038                 time_buf.ChangeTime =
1039                     cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime));
1040         } else
1041                 time_buf.ChangeTime = 0;
1042
1043         if (set_time || time_buf.Attributes) {
1044                 /* BB what if setting one attribute fails (such as size) but
1045                    time setting works? */
1046                 time_buf.CreationTime = 0;      /* do not change */
1047                 /* In the future we should experiment - try setting timestamps
1048                    via Handle (SetFileInfo) instead of by path */
1049                 if (!(pTcon->ses->flags & CIFS_SES_NT4))
1050                         rc = CIFSSMBSetTimes(xid, pTcon, full_path, &time_buf,
1051                                              cifs_sb->local_nls);
1052                 else
1053                         rc = -EOPNOTSUPP;
1054
1055                 if (rc == -EOPNOTSUPP) {
1056                         int oplock = FALSE;
1057                         __u16 netfid;
1058
1059                         cFYI(1, ("calling SetFileInfo since SetPathInfo for "
1060                                  "times not supported by this server"));
1061                         /* BB we could scan to see if we already have it open
1062                            and pass in pid of opener to function */
1063                         rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
1064                                          SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
1065                                          CREATE_NOT_DIR, &netfid, &oplock,
1066                                          NULL, cifs_sb->local_nls);
1067                         if (rc==0) {
1068                                 rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf,
1069                                                          netfid);
1070                                 CIFSSMBClose(xid, pTcon, netfid);
1071                         } else {
1072                         /* BB For even older servers we could convert time_buf
1073                            into old DOS style which uses two second
1074                            granularity */
1075
1076                         /* rc = CIFSSMBSetTimesLegacy(xid, pTcon, full_path,
1077                                         &time_buf, cifs_sb->local_nls); */
1078                         }
1079                 }
1080         }
1081
1082         /* do not need local check to inode_check_ok since the server does
1083            that */
1084         if (!rc)
1085                 rc = inode_setattr(direntry->d_inode, attrs);
1086         kfree(full_path);
1087         FreeXid(xid);
1088         return rc;
1089 }
1090
1091 void cifs_delete_inode(struct inode *inode)
1092 {
1093         cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode));
1094         /* may have to add back in if and when safe distributed caching of
1095            directories added e.g. via FindNotify */
1096 }