diff options
author | Jeff Garzik <jgarzik@pobox.com> | 2006-01-26 22:19:57 -0500 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2006-01-26 22:19:57 -0500 |
commit | 97309d1a0bbdcb0813ea08574b4473d8e5416012 (patch) | |
tree | 0dcbcf5aa5146147e0ac1d0c4b73b868a67d333b /fs | |
parent | b4ea75b649417606fd6b38710a2962ec9770e772 (diff) | |
parent | efd51b5c6798d103e3aa683464aebb2019b62119 (diff) |
Merge branch 'upstream-fixes'
Diffstat (limited to 'fs')
67 files changed, 2132 insertions, 788 deletions
diff --git a/fs/9p/Makefile b/fs/9p/Makefile index 3d023089707e..2f4ce43f7b6c 100644 --- a/fs/9p/Makefile +++ b/fs/9p/Makefile | |||
@@ -8,6 +8,7 @@ obj-$(CONFIG_9P_FS) := 9p2000.o | |||
8 | conv.o \ | 8 | conv.o \ |
9 | vfs_super.o \ | 9 | vfs_super.o \ |
10 | vfs_inode.o \ | 10 | vfs_inode.o \ |
11 | vfs_addr.o \ | ||
11 | vfs_file.o \ | 12 | vfs_file.o \ |
12 | vfs_dir.o \ | 13 | vfs_dir.o \ |
13 | vfs_dentry.o \ | 14 | vfs_dentry.o \ |
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h index c78502ad00ed..69cf2905dc90 100644 --- a/fs/9p/v9fs_vfs.h +++ b/fs/9p/v9fs_vfs.h | |||
@@ -39,6 +39,7 @@ | |||
39 | */ | 39 | */ |
40 | 40 | ||
41 | extern struct file_system_type v9fs_fs_type; | 41 | extern struct file_system_type v9fs_fs_type; |
42 | extern struct address_space_operations v9fs_addr_operations; | ||
42 | extern struct file_operations v9fs_file_operations; | 43 | extern struct file_operations v9fs_file_operations; |
43 | extern struct file_operations v9fs_dir_operations; | 44 | extern struct file_operations v9fs_dir_operations; |
44 | extern struct dentry_operations v9fs_dentry_operations; | 45 | extern struct dentry_operations v9fs_dentry_operations; |
diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c new file mode 100644 index 000000000000..8100fb5171b7 --- /dev/null +++ b/fs/9p/vfs_addr.c | |||
@@ -0,0 +1,109 @@ | |||
1 | /* | ||
2 | * linux/fs/9p/vfs_addr.c | ||
3 | * | ||
4 | * This file contians vfs address (mmap) ops for 9P2000. | ||
5 | * | ||
6 | * Copyright (C) 2005 by Eric Van Hensbergen <ericvh@gmail.com> | ||
7 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to: | ||
21 | * Free Software Foundation | ||
22 | * 51 Franklin Street, Fifth Floor | ||
23 | * Boston, MA 02111-1301 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | #include <linux/errno.h> | ||
29 | #include <linux/fs.h> | ||
30 | #include <linux/file.h> | ||
31 | #include <linux/stat.h> | ||
32 | #include <linux/string.h> | ||
33 | #include <linux/smp_lock.h> | ||
34 | #include <linux/inet.h> | ||
35 | #include <linux/version.h> | ||
36 | #include <linux/pagemap.h> | ||
37 | #include <linux/idr.h> | ||
38 | |||
39 | #include "debug.h" | ||
40 | #include "v9fs.h" | ||
41 | #include "9p.h" | ||
42 | #include "v9fs_vfs.h" | ||
43 | #include "fid.h" | ||
44 | |||
45 | /** | ||
46 | * v9fs_vfs_readpage - read an entire page in from 9P | ||
47 | * | ||
48 | * @file: file being read | ||
49 | * @page: structure to page | ||
50 | * | ||
51 | */ | ||
52 | |||
53 | static int v9fs_vfs_readpage(struct file *filp, struct page *page) | ||
54 | { | ||
55 | char *buffer = NULL; | ||
56 | int retval = -EIO; | ||
57 | loff_t offset = page_offset(page); | ||
58 | int count = PAGE_CACHE_SIZE; | ||
59 | struct inode *inode = filp->f_dentry->d_inode; | ||
60 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); | ||
61 | int rsize = v9ses->maxdata - V9FS_IOHDRSZ; | ||
62 | struct v9fs_fid *v9f = filp->private_data; | ||
63 | struct v9fs_fcall *fcall = NULL; | ||
64 | int fid = v9f->fid; | ||
65 | int total = 0; | ||
66 | int result = 0; | ||
67 | |||
68 | buffer = kmap(page); | ||
69 | do { | ||
70 | if (count < rsize) | ||
71 | rsize = count; | ||
72 | |||
73 | result = v9fs_t_read(v9ses, fid, offset, rsize, &fcall); | ||
74 | |||
75 | if (result < 0) { | ||
76 | printk(KERN_ERR "v9fs_t_read returned %d\n", | ||
77 | result); | ||
78 | |||
79 | kfree(fcall); | ||
80 | goto UnmapAndUnlock; | ||
81 | } else | ||
82 | offset += result; | ||
83 | |||
84 | memcpy(buffer, fcall->params.rread.data, result); | ||
85 | |||
86 | count -= result; | ||
87 | buffer += result; | ||
88 | total += result; | ||
89 | |||
90 | kfree(fcall); | ||
91 | |||
92 | if (result < rsize) | ||
93 | break; | ||
94 | } while (count); | ||
95 | |||
96 | memset(buffer, 0, count); | ||
97 | flush_dcache_page(page); | ||
98 | SetPageUptodate(page); | ||
99 | retval = 0; | ||
100 | |||
101 | UnmapAndUnlock: | ||
102 | kunmap(page); | ||
103 | unlock_page(page); | ||
104 | return retval; | ||
105 | } | ||
106 | |||
107 | struct address_space_operations v9fs_addr_operations = { | ||
108 | .readpage = v9fs_vfs_readpage, | ||
109 | }; | ||
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 6852f0eb96ed..c7e14d917215 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c | |||
@@ -289,6 +289,9 @@ v9fs_file_write(struct file *filp, const char __user * data, | |||
289 | total += result; | 289 | total += result; |
290 | } while (count); | 290 | } while (count); |
291 | 291 | ||
292 | if(inode->i_mapping->nrpages) | ||
293 | invalidate_inode_pages2(inode->i_mapping); | ||
294 | |||
292 | return total; | 295 | return total; |
293 | } | 296 | } |
294 | 297 | ||
@@ -299,4 +302,5 @@ struct file_operations v9fs_file_operations = { | |||
299 | .open = v9fs_file_open, | 302 | .open = v9fs_file_open, |
300 | .release = v9fs_dir_release, | 303 | .release = v9fs_dir_release, |
301 | .lock = v9fs_file_lock, | 304 | .lock = v9fs_file_lock, |
305 | .mmap = generic_file_mmap, | ||
302 | }; | 306 | }; |
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index a17b28854288..91f552454c76 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c | |||
@@ -177,6 +177,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode) | |||
177 | inode->i_blocks = 0; | 177 | inode->i_blocks = 0; |
178 | inode->i_rdev = 0; | 178 | inode->i_rdev = 0; |
179 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 179 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
180 | inode->i_mapping->a_ops = &v9fs_addr_operations; | ||
180 | 181 | ||
181 | switch (mode & S_IFMT) { | 182 | switch (mode & S_IFMT) { |
182 | case S_IFIFO: | 183 | case S_IFIFO: |
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 943ef9b82244..d335015473a5 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -1,3 +1,11 @@ | |||
1 | Version 1.40 | ||
2 | ------------ | ||
3 | Use fsuid (fsgid) more consistently instead of uid (gid). Improve performance | ||
4 | of readpages by eliminating one extra memcpy. Allow update of file size | ||
5 | from remote server even if file is open for write as long as mount is | ||
6 | directio. Recognize share mode security and send NTLM encrypted password | ||
7 | on tree connect if share mode negotiated. | ||
8 | |||
1 | Version 1.39 | 9 | Version 1.39 |
2 | ------------ | 10 | ------------ |
3 | Defer close of a file handle slightly if pending writes depend on that handle | 11 | Defer close of a file handle slightly if pending writes depend on that handle |
@@ -7,6 +15,8 @@ Fix SFU style symlinks and mknod needed for servers which do not support the | |||
7 | CIFS Unix Extensions. Fix setfacl/getfacl on bigendian. Timeout negative | 15 | CIFS Unix Extensions. Fix setfacl/getfacl on bigendian. Timeout negative |
8 | dentries so files that the client sees as deleted but that later get created | 16 | dentries so files that the client sees as deleted but that later get created |
9 | on the server will be recognized. Add client side permission check on setattr. | 17 | on the server will be recognized. Add client side permission check on setattr. |
18 | Timeout stuck requests better (where server has never responded or sent corrupt | ||
19 | responses) | ||
10 | 20 | ||
11 | Version 1.38 | 21 | Version 1.38 |
12 | ------------ | 22 | ------------ |
diff --git a/fs/cifs/README b/fs/cifs/README index e5d09a2fc7a5..b0070d1b149d 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
@@ -436,7 +436,17 @@ A partial list of the supported mount options follows: | |||
436 | SFU does). In the future the bottom 9 bits of the mode | 436 | SFU does). In the future the bottom 9 bits of the mode |
437 | mode also will be emulated using queries of the security | 437 | mode also will be emulated using queries of the security |
438 | descriptor (ACL). | 438 | descriptor (ACL). |
439 | 439 | sec Security mode. Allowed values are: | |
440 | none attempt to connection as a null user (no name) | ||
441 | krb5 Use Kerberos version 5 authentication | ||
442 | krb5i Use Kerberos authentication and packet signing | ||
443 | ntlm Use NTLM password hashing (default) | ||
444 | ntlmi Use NTLM password hashing with signing (if | ||
445 | /proc/fs/cifs/PacketSigningEnabled on or if | ||
446 | server requires signing also can be the default) | ||
447 | ntlmv2 Use NTLMv2 password hashing | ||
448 | ntlmv2i Use NTLMv2 password hashing with packet signing | ||
449 | |||
440 | The mount.cifs mount helper also accepts a few mount options before -o | 450 | The mount.cifs mount helper also accepts a few mount options before -o |
441 | including: | 451 | including: |
442 | 452 | ||
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 22a444a3fe4c..f4124a32bef8 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c | |||
@@ -219,6 +219,10 @@ cifs_stats_write(struct file *file, const char __user *buffer, | |||
219 | 219 | ||
220 | if (c == '1' || c == 'y' || c == 'Y' || c == '0') { | 220 | if (c == '1' || c == 'y' || c == 'Y' || c == '0') { |
221 | read_lock(&GlobalSMBSeslock); | 221 | read_lock(&GlobalSMBSeslock); |
222 | #ifdef CONFIG_CIFS_STATS2 | ||
223 | atomic_set(&totBufAllocCount, 0); | ||
224 | atomic_set(&totSmBufAllocCount, 0); | ||
225 | #endif /* CONFIG_CIFS_STATS2 */ | ||
222 | list_for_each(tmp, &GlobalTreeConnectionList) { | 226 | list_for_each(tmp, &GlobalTreeConnectionList) { |
223 | tcon = list_entry(tmp, struct cifsTconInfo, | 227 | tcon = list_entry(tmp, struct cifsTconInfo, |
224 | cifsConnectionList); | 228 | cifsConnectionList); |
@@ -276,6 +280,14 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset, | |||
276 | smBufAllocCount.counter,cifs_min_small); | 280 | smBufAllocCount.counter,cifs_min_small); |
277 | length += item_length; | 281 | length += item_length; |
278 | buf += item_length; | 282 | buf += item_length; |
283 | #ifdef CONFIG_CIFS_STATS2 | ||
284 | item_length = sprintf(buf, "Total Large %d Small %d Allocations\n", | ||
285 | atomic_read(&totBufAllocCount), | ||
286 | atomic_read(&totSmBufAllocCount)); | ||
287 | length += item_length; | ||
288 | buf += item_length; | ||
289 | #endif /* CONFIG_CIFS_STATS2 */ | ||
290 | |||
279 | item_length = | 291 | item_length = |
280 | sprintf(buf,"Operations (MIDs): %d\n", | 292 | sprintf(buf,"Operations (MIDs): %d\n", |
281 | midCount.counter); | 293 | midCount.counter); |
@@ -389,8 +401,8 @@ static read_proc_t ntlmv2_enabled_read; | |||
389 | static write_proc_t ntlmv2_enabled_write; | 401 | static write_proc_t ntlmv2_enabled_write; |
390 | static read_proc_t packet_signing_enabled_read; | 402 | static read_proc_t packet_signing_enabled_read; |
391 | static write_proc_t packet_signing_enabled_write; | 403 | static write_proc_t packet_signing_enabled_write; |
392 | static read_proc_t quotaEnabled_read; | 404 | static read_proc_t experimEnabled_read; |
393 | static write_proc_t quotaEnabled_write; | 405 | static write_proc_t experimEnabled_write; |
394 | static read_proc_t linuxExtensionsEnabled_read; | 406 | static read_proc_t linuxExtensionsEnabled_read; |
395 | static write_proc_t linuxExtensionsEnabled_write; | 407 | static write_proc_t linuxExtensionsEnabled_write; |
396 | 408 | ||
@@ -430,9 +442,9 @@ cifs_proc_init(void) | |||
430 | pde->write_proc = oplockEnabled_write; | 442 | pde->write_proc = oplockEnabled_write; |
431 | 443 | ||
432 | pde = create_proc_read_entry("Experimental", 0, proc_fs_cifs, | 444 | pde = create_proc_read_entry("Experimental", 0, proc_fs_cifs, |
433 | quotaEnabled_read, NULL); | 445 | experimEnabled_read, NULL); |
434 | if (pde) | 446 | if (pde) |
435 | pde->write_proc = quotaEnabled_write; | 447 | pde->write_proc = experimEnabled_write; |
436 | 448 | ||
437 | pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs, | 449 | pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs, |
438 | linuxExtensionsEnabled_read, NULL); | 450 | linuxExtensionsEnabled_read, NULL); |
@@ -574,14 +586,13 @@ oplockEnabled_write(struct file *file, const char __user *buffer, | |||
574 | } | 586 | } |
575 | 587 | ||
576 | static int | 588 | static int |
577 | quotaEnabled_read(char *page, char **start, off_t off, | 589 | experimEnabled_read(char *page, char **start, off_t off, |
578 | int count, int *eof, void *data) | 590 | int count, int *eof, void *data) |
579 | { | 591 | { |
580 | int len; | 592 | int len; |
581 | 593 | ||
582 | len = sprintf(page, "%d\n", experimEnabled); | 594 | len = sprintf(page, "%d\n", experimEnabled); |
583 | /* could also check if quotas are enabled in kernel | 595 | |
584 | as a whole first */ | ||
585 | len -= off; | 596 | len -= off; |
586 | *start = page + off; | 597 | *start = page + off; |
587 | 598 | ||
@@ -596,21 +607,23 @@ quotaEnabled_read(char *page, char **start, off_t off, | |||
596 | return len; | 607 | return len; |
597 | } | 608 | } |
598 | static int | 609 | static int |
599 | quotaEnabled_write(struct file *file, const char __user *buffer, | 610 | experimEnabled_write(struct file *file, const char __user *buffer, |
600 | unsigned long count, void *data) | 611 | unsigned long count, void *data) |
601 | { | 612 | { |
602 | char c; | 613 | char c; |
603 | int rc; | 614 | int rc; |
604 | 615 | ||
605 | rc = get_user(c, buffer); | 616 | rc = get_user(c, buffer); |
606 | if (rc) | 617 | if (rc) |
607 | return rc; | 618 | return rc; |
608 | if (c == '0' || c == 'n' || c == 'N') | 619 | if (c == '0' || c == 'n' || c == 'N') |
609 | experimEnabled = 0; | 620 | experimEnabled = 0; |
610 | else if (c == '1' || c == 'y' || c == 'Y') | 621 | else if (c == '1' || c == 'y' || c == 'Y') |
611 | experimEnabled = 1; | 622 | experimEnabled = 1; |
623 | else if (c == '2') | ||
624 | experimEnabled = 2; | ||
612 | 625 | ||
613 | return count; | 626 | return count; |
614 | } | 627 | } |
615 | 628 | ||
616 | static int | 629 | static int |
@@ -620,8 +633,6 @@ linuxExtensionsEnabled_read(char *page, char **start, off_t off, | |||
620 | int len; | 633 | int len; |
621 | 634 | ||
622 | len = sprintf(page, "%d\n", linuxExtEnabled); | 635 | len = sprintf(page, "%d\n", linuxExtEnabled); |
623 | /* could also check if quotas are enabled in kernel | ||
624 | as a whole first */ | ||
625 | len -= off; | 636 | len -= off; |
626 | *start = page + off; | 637 | *start = page + off; |
627 | 638 | ||
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index f799f6f0e729..ad58eb0c4d6d 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h | |||
@@ -24,9 +24,10 @@ | |||
24 | #define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */ | 24 | #define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */ |
25 | #define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */ | 25 | #define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */ |
26 | #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */ | 26 | #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */ |
27 | #define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible. */ | 27 | #define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible. */ |
28 | #define CIFS_MOUNT_UNX_EMUL 0x80 /* Network compat with SFUnix emulation */ | 28 | #define CIFS_MOUNT_UNX_EMUL 0x80 /* Network compat with SFUnix emulation */ |
29 | #define CIFS_MOUNT_NO_BRL 0x100 /* No sending byte range locks to srv */ | 29 | #define CIFS_MOUNT_NO_BRL 0x100 /* No sending byte range locks to srv */ |
30 | #define CIFS_MOUNT_CIFS_ACL 0x200 /* send ACL requests to non-POSIX srv */ | ||
30 | 31 | ||
31 | struct cifs_sb_info { | 32 | struct cifs_sb_info { |
32 | struct cifsTconInfo *tcon; /* primary mount */ | 33 | struct cifsTconInfo *tcon; /* primary mount */ |
diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h new file mode 100644 index 000000000000..d0776ac2b804 --- /dev/null +++ b/fs/cifs/cifsacl.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /* | ||
2 | * fs/cifs/cifsacl.h | ||
3 | * | ||
4 | * Copyright (c) International Business Machines Corp., 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 | |||
22 | #ifndef _CIFSACL_H | ||
23 | #define _CIFSACL_H | ||
24 | |||
25 | struct cifs_sid { | ||
26 | __u8 revision; /* revision level */ | ||
27 | __u8 num_subauths; | ||
28 | __u8 authority[6]; | ||
29 | __u32 sub_auth[4]; | ||
30 | /* next sub_auth if any ... */ | ||
31 | } __attribute__((packed)); | ||
32 | |||
33 | /* everyone */ | ||
34 | extern const struct cifs_sid sid_everyone; | ||
35 | /* group users */ | ||
36 | extern const struct cifs_sid sid_user; | ||
37 | |||
38 | #endif /* _CIFSACL_H */ | ||
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index fe2bb7c4c912..a2c24858d40f 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * fs/cifs/cifsencrypt.c | 2 | * fs/cifs/cifsencrypt.c |
3 | * | 3 | * |
4 | * Copyright (C) International Business Machines Corp., 2003 | 4 | * Copyright (C) International Business Machines Corp., 2005 |
5 | * Author(s): Steve French (sfrench@us.ibm.com) | 5 | * Author(s): Steve French (sfrench@us.ibm.com) |
6 | * | 6 | * |
7 | * This library is free software; you can redistribute it and/or modify | 7 | * This library is free software; you can redistribute it and/or modify |
@@ -82,6 +82,59 @@ int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct TCP_Server_Info * server, | |||
82 | return rc; | 82 | return rc; |
83 | } | 83 | } |
84 | 84 | ||
85 | static int cifs_calc_signature2(const struct kvec * iov, int n_vec, | ||
86 | const char * key, char * signature) | ||
87 | { | ||
88 | struct MD5Context context; | ||
89 | |||
90 | if((iov == NULL) || (signature == NULL)) | ||
91 | return -EINVAL; | ||
92 | |||
93 | MD5Init(&context); | ||
94 | MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16); | ||
95 | |||
96 | /* MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length); */ /* BB FIXME BB */ | ||
97 | |||
98 | MD5Final(signature,&context); | ||
99 | |||
100 | return -EOPNOTSUPP; | ||
101 | /* return 0; */ | ||
102 | } | ||
103 | |||
104 | |||
105 | int cifs_sign_smb2(struct kvec * iov, int n_vec, struct TCP_Server_Info *server, | ||
106 | __u32 * pexpected_response_sequence_number) | ||
107 | { | ||
108 | int rc = 0; | ||
109 | char smb_signature[20]; | ||
110 | struct smb_hdr * cifs_pdu = iov[0].iov_base; | ||
111 | |||
112 | if((cifs_pdu == NULL) || (server == NULL)) | ||
113 | return -EINVAL; | ||
114 | |||
115 | if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) | ||
116 | return rc; | ||
117 | |||
118 | spin_lock(&GlobalMid_Lock); | ||
119 | cifs_pdu->Signature.Sequence.SequenceNumber = | ||
120 | cpu_to_le32(server->sequence_number); | ||
121 | cifs_pdu->Signature.Sequence.Reserved = 0; | ||
122 | |||
123 | *pexpected_response_sequence_number = server->sequence_number++; | ||
124 | server->sequence_number++; | ||
125 | spin_unlock(&GlobalMid_Lock); | ||
126 | |||
127 | rc = cifs_calc_signature2(iov, n_vec, server->mac_signing_key, | ||
128 | smb_signature); | ||
129 | if(rc) | ||
130 | memset(cifs_pdu->Signature.SecuritySignature, 0, 8); | ||
131 | else | ||
132 | memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8); | ||
133 | |||
134 | return rc; | ||
135 | |||
136 | } | ||
137 | |||
85 | int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key, | 138 | int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key, |
86 | __u32 expected_sequence_number) | 139 | __u32 expected_sequence_number) |
87 | { | 140 | { |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index e10213b7541e..79eeccd0437f 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -513,6 +513,17 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const char __user *buf, | |||
513 | return written; | 513 | return written; |
514 | } | 514 | } |
515 | 515 | ||
516 | static loff_t cifs_llseek(struct file *file, loff_t offset, int origin) | ||
517 | { | ||
518 | /* origin == SEEK_END => we must revalidate the cached file length */ | ||
519 | if (origin == 2) { | ||
520 | int retval = cifs_revalidate(file->f_dentry); | ||
521 | if (retval < 0) | ||
522 | return (loff_t)retval; | ||
523 | } | ||
524 | return remote_llseek(file, offset, origin); | ||
525 | } | ||
526 | |||
516 | static struct file_system_type cifs_fs_type = { | 527 | static struct file_system_type cifs_fs_type = { |
517 | .owner = THIS_MODULE, | 528 | .owner = THIS_MODULE, |
518 | .name = "cifs", | 529 | .name = "cifs", |
@@ -586,6 +597,7 @@ struct file_operations cifs_file_ops = { | |||
586 | .flush = cifs_flush, | 597 | .flush = cifs_flush, |
587 | .mmap = cifs_file_mmap, | 598 | .mmap = cifs_file_mmap, |
588 | .sendfile = generic_file_sendfile, | 599 | .sendfile = generic_file_sendfile, |
600 | .llseek = cifs_llseek, | ||
589 | #ifdef CONFIG_CIFS_POSIX | 601 | #ifdef CONFIG_CIFS_POSIX |
590 | .ioctl = cifs_ioctl, | 602 | .ioctl = cifs_ioctl, |
591 | #endif /* CONFIG_CIFS_POSIX */ | 603 | #endif /* CONFIG_CIFS_POSIX */ |
@@ -609,7 +621,7 @@ struct file_operations cifs_file_direct_ops = { | |||
609 | #ifdef CONFIG_CIFS_POSIX | 621 | #ifdef CONFIG_CIFS_POSIX |
610 | .ioctl = cifs_ioctl, | 622 | .ioctl = cifs_ioctl, |
611 | #endif /* CONFIG_CIFS_POSIX */ | 623 | #endif /* CONFIG_CIFS_POSIX */ |
612 | 624 | .llseek = cifs_llseek, | |
613 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 625 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
614 | .dir_notify = cifs_dir_notify, | 626 | .dir_notify = cifs_dir_notify, |
615 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | 627 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ |
@@ -627,6 +639,7 @@ struct file_operations cifs_file_nobrl_ops = { | |||
627 | .flush = cifs_flush, | 639 | .flush = cifs_flush, |
628 | .mmap = cifs_file_mmap, | 640 | .mmap = cifs_file_mmap, |
629 | .sendfile = generic_file_sendfile, | 641 | .sendfile = generic_file_sendfile, |
642 | .llseek = cifs_llseek, | ||
630 | #ifdef CONFIG_CIFS_POSIX | 643 | #ifdef CONFIG_CIFS_POSIX |
631 | .ioctl = cifs_ioctl, | 644 | .ioctl = cifs_ioctl, |
632 | #endif /* CONFIG_CIFS_POSIX */ | 645 | #endif /* CONFIG_CIFS_POSIX */ |
@@ -649,7 +662,7 @@ struct file_operations cifs_file_direct_nobrl_ops = { | |||
649 | #ifdef CONFIG_CIFS_POSIX | 662 | #ifdef CONFIG_CIFS_POSIX |
650 | .ioctl = cifs_ioctl, | 663 | .ioctl = cifs_ioctl, |
651 | #endif /* CONFIG_CIFS_POSIX */ | 664 | #endif /* CONFIG_CIFS_POSIX */ |
652 | 665 | .llseek = cifs_llseek, | |
653 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 666 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
654 | .dir_notify = cifs_dir_notify, | 667 | .dir_notify = cifs_dir_notify, |
655 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | 668 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ |
@@ -733,7 +746,7 @@ cifs_init_request_bufs(void) | |||
733 | kmem_cache_destroy(cifs_req_cachep); | 746 | kmem_cache_destroy(cifs_req_cachep); |
734 | return -ENOMEM; | 747 | return -ENOMEM; |
735 | } | 748 | } |
736 | /* 256 (MAX_CIFS_HDR_SIZE bytes is enough for most SMB responses and | 749 | /* MAX_CIFS_SMALL_BUFFER_SIZE bytes is enough for most SMB responses and |
737 | almost all handle based requests (but not write response, nor is it | 750 | almost all handle based requests (but not write response, nor is it |
738 | sufficient for path based requests). A smaller size would have | 751 | sufficient for path based requests). A smaller size would have |
739 | been more efficient (compacting multiple slab items on one 4k page) | 752 | been more efficient (compacting multiple slab items on one 4k page) |
@@ -742,7 +755,8 @@ cifs_init_request_bufs(void) | |||
742 | efficient to alloc 1 per page off the slab compared to 17K (5page) | 755 | efficient to alloc 1 per page off the slab compared to 17K (5page) |
743 | alloc of large cifs buffers even when page debugging is on */ | 756 | alloc of large cifs buffers even when page debugging is on */ |
744 | cifs_sm_req_cachep = kmem_cache_create("cifs_small_rq", | 757 | cifs_sm_req_cachep = kmem_cache_create("cifs_small_rq", |
745 | MAX_CIFS_HDR_SIZE, 0, SLAB_HWCACHE_ALIGN, NULL, NULL); | 758 | MAX_CIFS_SMALL_BUFFER_SIZE, 0, SLAB_HWCACHE_ALIGN, |
759 | NULL, NULL); | ||
746 | if (cifs_sm_req_cachep == NULL) { | 760 | if (cifs_sm_req_cachep == NULL) { |
747 | mempool_destroy(cifs_req_poolp); | 761 | mempool_destroy(cifs_req_poolp); |
748 | kmem_cache_destroy(cifs_req_cachep); | 762 | kmem_cache_destroy(cifs_req_cachep); |
@@ -954,6 +968,12 @@ init_cifs(void) | |||
954 | atomic_set(&tconInfoReconnectCount, 0); | 968 | atomic_set(&tconInfoReconnectCount, 0); |
955 | 969 | ||
956 | atomic_set(&bufAllocCount, 0); | 970 | atomic_set(&bufAllocCount, 0); |
971 | atomic_set(&smBufAllocCount, 0); | ||
972 | #ifdef CONFIG_CIFS_STATS2 | ||
973 | atomic_set(&totBufAllocCount, 0); | ||
974 | atomic_set(&totSmBufAllocCount, 0); | ||
975 | #endif /* CONFIG_CIFS_STATS2 */ | ||
976 | |||
957 | atomic_set(&midCount, 0); | 977 | atomic_set(&midCount, 0); |
958 | GlobalCurrentXid = 0; | 978 | GlobalCurrentXid = 0; |
959 | GlobalTotalActiveXid = 0; | 979 | GlobalTotalActiveXid = 0; |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 9ec40e0e54fc..821a8eb22559 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -99,5 +99,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); | |||
99 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); | 99 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); |
100 | extern int cifs_ioctl (struct inode * inode, struct file * filep, | 100 | extern int cifs_ioctl (struct inode * inode, struct file * filep, |
101 | unsigned int command, unsigned long arg); | 101 | unsigned int command, unsigned long arg); |
102 | #define CIFS_VERSION "1.39" | 102 | #define CIFS_VERSION "1.40" |
103 | #endif /* _CIFSFS_H */ | 103 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 1ba08f8c5bc4..7bed27601ce5 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -233,6 +233,8 @@ struct cifsTconInfo { | |||
233 | atomic_t num_hardlinks; | 233 | atomic_t num_hardlinks; |
234 | atomic_t num_symlinks; | 234 | atomic_t num_symlinks; |
235 | atomic_t num_locks; | 235 | atomic_t num_locks; |
236 | atomic_t num_acl_get; | ||
237 | atomic_t num_acl_set; | ||
236 | #ifdef CONFIG_CIFS_STATS2 | 238 | #ifdef CONFIG_CIFS_STATS2 |
237 | unsigned long long time_writes; | 239 | unsigned long long time_writes; |
238 | unsigned long long time_reads; | 240 | unsigned long long time_reads; |
@@ -285,6 +287,7 @@ struct cifs_search_info { | |||
285 | unsigned endOfSearch:1; | 287 | unsigned endOfSearch:1; |
286 | unsigned emptyDir:1; | 288 | unsigned emptyDir:1; |
287 | unsigned unicode:1; | 289 | unsigned unicode:1; |
290 | unsigned smallBuf:1; /* so we know which buf_release function to call */ | ||
288 | }; | 291 | }; |
289 | 292 | ||
290 | struct cifsFileInfo { | 293 | struct cifsFileInfo { |
@@ -420,7 +423,12 @@ struct dir_notify_req { | |||
420 | #define MID_RESPONSE_RECEIVED 4 | 423 | #define MID_RESPONSE_RECEIVED 4 |
421 | #define MID_RETRY_NEEDED 8 /* session closed while this request out */ | 424 | #define MID_RETRY_NEEDED 8 /* session closed while this request out */ |
422 | #define MID_NO_RESP_NEEDED 0x10 | 425 | #define MID_NO_RESP_NEEDED 0x10 |
423 | #define MID_SMALL_BUFFER 0x20 /* 112 byte response buffer instead of 4K */ | 426 | |
427 | /* Types of response buffer returned from SendReceive2 */ | ||
428 | #define CIFS_NO_BUFFER 0 /* Response buffer not returned */ | ||
429 | #define CIFS_SMALL_BUFFER 1 | ||
430 | #define CIFS_LARGE_BUFFER 2 | ||
431 | #define CIFS_IOVEC 4 /* array of response buffers */ | ||
424 | 432 | ||
425 | /* | 433 | /* |
426 | ***************************************************************** | 434 | ***************************************************************** |
@@ -505,8 +513,12 @@ GLOBAL_EXTERN atomic_t tcpSesReconnectCount; | |||
505 | GLOBAL_EXTERN atomic_t tconInfoReconnectCount; | 513 | GLOBAL_EXTERN atomic_t tconInfoReconnectCount; |
506 | 514 | ||
507 | /* Various Debug counters to remove someday (BB) */ | 515 | /* Various Debug counters to remove someday (BB) */ |
508 | GLOBAL_EXTERN atomic_t bufAllocCount; | 516 | GLOBAL_EXTERN atomic_t bufAllocCount; /* current number allocated */ |
509 | GLOBAL_EXTERN atomic_t smBufAllocCount; | 517 | #ifdef CONFIG_CIFS_STATS2 |
518 | GLOBAL_EXTERN atomic_t totBufAllocCount; /* total allocated over all time */ | ||
519 | GLOBAL_EXTERN atomic_t totSmBufAllocCount; | ||
520 | #endif | ||
521 | GLOBAL_EXTERN atomic_t smBufAllocCount; | ||
510 | GLOBAL_EXTERN atomic_t midCount; | 522 | GLOBAL_EXTERN atomic_t midCount; |
511 | 523 | ||
512 | /* Misc globals */ | 524 | /* Misc globals */ |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 33e1859fd2f6..cc2471094ca5 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * fs/cifs/cifspdu.h | 2 | * fs/cifs/cifspdu.h |
3 | * | 3 | * |
4 | * Copyright (c) International Business Machines Corp., 2002 | 4 | * Copyright (c) International Business Machines Corp., 2002,2005 |
5 | * Author(s): Steve French (sfrench@us.ibm.com) | 5 | * Author(s): Steve French (sfrench@us.ibm.com) |
6 | * | 6 | * |
7 | * This library is free software; you can redistribute it and/or modify | 7 | * This library is free software; you can redistribute it and/or modify |
@@ -80,7 +80,11 @@ | |||
80 | #define NT_TRANSACT_GET_USER_QUOTA 0x07 | 80 | #define NT_TRANSACT_GET_USER_QUOTA 0x07 |
81 | #define NT_TRANSACT_SET_USER_QUOTA 0x08 | 81 | #define NT_TRANSACT_SET_USER_QUOTA 0x08 |
82 | 82 | ||
83 | #define MAX_CIFS_HDR_SIZE 256 /* is future chained NTCreateXReadX bigger? */ | 83 | #define MAX_CIFS_SMALL_BUFFER_SIZE 448 /* big enough for most */ |
84 | /* future chained NTCreateXReadX bigger, but for time being NTCreateX biggest */ | ||
85 | /* among the requests (NTCreateX response is bigger with wct of 34) */ | ||
86 | #define MAX_CIFS_HDR_SIZE 0x58 /* 4 len + 32 hdr + (2*24 wct) + 2 bct + 2 pad */ | ||
87 | #define CIFS_SMALL_PATH 120 /* allows for (448-88)/3 */ | ||
84 | 88 | ||
85 | /* internal cifs vfs structures */ | 89 | /* internal cifs vfs structures */ |
86 | /***************************************************************** | 90 | /***************************************************************** |
@@ -524,7 +528,7 @@ typedef union smb_com_session_setup_andx { | |||
524 | /* STRING PrimaryDomain */ | 528 | /* STRING PrimaryDomain */ |
525 | /* STRING NativeOS */ | 529 | /* STRING NativeOS */ |
526 | /* STRING NativeLanMan */ | 530 | /* STRING NativeLanMan */ |
527 | } __attribute__((packed)) old_req; /* pre-NTLM (LANMAN2.1) request format */ | 531 | } __attribute__((packed)) old_req; /* pre-NTLM (LANMAN2.1) req format */ |
528 | 532 | ||
529 | struct { /* default (NTLM) response format */ | 533 | struct { /* default (NTLM) response format */ |
530 | struct smb_hdr hdr; /* wct = 3 */ | 534 | struct smb_hdr hdr; /* wct = 3 */ |
@@ -536,7 +540,7 @@ typedef union smb_com_session_setup_andx { | |||
536 | unsigned char NativeOS[1]; /* followed by */ | 540 | unsigned char NativeOS[1]; /* followed by */ |
537 | /* unsigned char * NativeLanMan; */ | 541 | /* unsigned char * NativeLanMan; */ |
538 | /* unsigned char * PrimaryDomain; */ | 542 | /* unsigned char * PrimaryDomain; */ |
539 | } __attribute__((packed)) old_resp; /* pre-NTLM (LANMAN2.1) response format */ | 543 | } __attribute__((packed)) old_resp; /* pre-NTLM (LANMAN2.1) response */ |
540 | } __attribute__((packed)) SESSION_SETUP_ANDX; | 544 | } __attribute__((packed)) SESSION_SETUP_ANDX; |
541 | 545 | ||
542 | #define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux" | 546 | #define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux" |
@@ -1003,10 +1007,49 @@ typedef struct smb_com_setattr_rsp { | |||
1003 | 1007 | ||
1004 | /* empty wct response to setattr */ | 1008 | /* empty wct response to setattr */ |
1005 | 1009 | ||
1006 | /***************************************************/ | 1010 | /*******************************************************/ |
1007 | /* NT Transact structure defintions follow */ | 1011 | /* NT Transact structure defintions follow */ |
1008 | /* Currently only ioctl and notify are implemented */ | 1012 | /* Currently only ioctl, acl (get security descriptor) */ |
1009 | /***************************************************/ | 1013 | /* and notify are implemented */ |
1014 | /*******************************************************/ | ||
1015 | typedef struct smb_com_ntransact_req { | ||
1016 | struct smb_hdr hdr; /* wct >= 19 */ | ||
1017 | __u8 MaxSetupCount; | ||
1018 | __u16 Reserved; | ||
1019 | __le32 TotalParameterCount; | ||
1020 | __le32 TotalDataCount; | ||
1021 | __le32 MaxParameterCount; | ||
1022 | __le32 MaxDataCount; | ||
1023 | __le32 ParameterCount; | ||
1024 | __le32 ParameterOffset; | ||
1025 | __le32 DataCount; | ||
1026 | __le32 DataOffset; | ||
1027 | __u8 SetupCount; /* four setup words follow subcommand */ | ||
1028 | /* SNIA spec incorrectly included spurious pad here */ | ||
1029 | __le16 SubCommand; /* 2 = IOCTL/FSCTL */ | ||
1030 | /* SetupCount words follow then */ | ||
1031 | __le16 ByteCount; | ||
1032 | __u8 Pad[3]; | ||
1033 | __u8 Parms[0]; | ||
1034 | } __attribute__((packed)) NTRANSACT_REQ; | ||
1035 | |||
1036 | typedef struct smb_com_ntransact_rsp { | ||
1037 | struct smb_hdr hdr; /* wct = 18 */ | ||
1038 | __u8 Reserved[3]; | ||
1039 | __le32 TotalParameterCount; | ||
1040 | __le32 TotalDataCount; | ||
1041 | __le32 ParameterCount; | ||
1042 | __le32 ParameterOffset; | ||
1043 | __le32 ParameterDisplacement; | ||
1044 | __le32 DataCount; | ||
1045 | __le32 DataOffset; | ||
1046 | __le32 DataDisplacement; | ||
1047 | __u8 SetupCount; /* 0 */ | ||
1048 | __u16 ByteCount; | ||
1049 | /* __u8 Pad[3]; */ | ||
1050 | /* parms and data follow */ | ||
1051 | } __attribute__((packed)) NTRANSACT_RSP; | ||
1052 | |||
1010 | typedef struct smb_com_transaction_ioctl_req { | 1053 | typedef struct smb_com_transaction_ioctl_req { |
1011 | struct smb_hdr hdr; /* wct = 23 */ | 1054 | struct smb_hdr hdr; /* wct = 23 */ |
1012 | __u8 MaxSetupCount; | 1055 | __u8 MaxSetupCount; |
@@ -1021,11 +1064,11 @@ typedef struct smb_com_transaction_ioctl_req { | |||
1021 | __le32 DataOffset; | 1064 | __le32 DataOffset; |
1022 | __u8 SetupCount; /* four setup words follow subcommand */ | 1065 | __u8 SetupCount; /* four setup words follow subcommand */ |
1023 | /* SNIA spec incorrectly included spurious pad here */ | 1066 | /* SNIA spec incorrectly included spurious pad here */ |
1024 | __le16 SubCommand;/* 2 = IOCTL/FSCTL */ | 1067 | __le16 SubCommand; /* 2 = IOCTL/FSCTL */ |
1025 | __le32 FunctionCode; | 1068 | __le32 FunctionCode; |
1026 | __u16 Fid; | 1069 | __u16 Fid; |
1027 | __u8 IsFsctl; /* 1 = File System Control, 0 = device control (IOCTL)*/ | 1070 | __u8 IsFsctl; /* 1 = File System Control 0 = device control (IOCTL) */ |
1028 | __u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS share)*/ | 1071 | __u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS) */ |
1029 | __le16 ByteCount; | 1072 | __le16 ByteCount; |
1030 | __u8 Pad[3]; | 1073 | __u8 Pad[3]; |
1031 | __u8 Data[1]; | 1074 | __u8 Data[1]; |
@@ -1045,9 +1088,35 @@ typedef struct smb_com_transaction_ioctl_rsp { | |||
1045 | __u8 SetupCount; /* 1 */ | 1088 | __u8 SetupCount; /* 1 */ |
1046 | __le16 ReturnedDataLen; | 1089 | __le16 ReturnedDataLen; |
1047 | __u16 ByteCount; | 1090 | __u16 ByteCount; |
1048 | __u8 Pad[3]; | ||
1049 | } __attribute__((packed)) TRANSACT_IOCTL_RSP; | 1091 | } __attribute__((packed)) TRANSACT_IOCTL_RSP; |
1050 | 1092 | ||
1093 | #define CIFS_ACL_OWNER 1 | ||
1094 | #define CIFS_ACL_GROUP 2 | ||
1095 | #define CIFS_ACL_DACL 4 | ||
1096 | #define CIFS_ACL_SACL 8 | ||
1097 | |||
1098 | typedef struct smb_com_transaction_qsec_req { | ||
1099 | struct smb_hdr hdr; /* wct = 19 */ | ||
1100 | __u8 MaxSetupCount; | ||
1101 | __u16 Reserved; | ||
1102 | __le32 TotalParameterCount; | ||
1103 | __le32 TotalDataCount; | ||
1104 | __le32 MaxParameterCount; | ||
1105 | __le32 MaxDataCount; | ||
1106 | __le32 ParameterCount; | ||
1107 | __le32 ParameterOffset; | ||
1108 | __le32 DataCount; | ||
1109 | __le32 DataOffset; | ||
1110 | __u8 SetupCount; /* no setup words follow subcommand */ | ||
1111 | /* SNIA spec incorrectly included spurious pad here */ | ||
1112 | __le16 SubCommand; /* 6 = QUERY_SECURITY_DESC */ | ||
1113 | __le16 ByteCount; /* bcc = 3 + 8 */ | ||
1114 | __u8 Pad[3]; | ||
1115 | __u16 Fid; | ||
1116 | __u16 Reserved2; | ||
1117 | __le32 AclFlags; | ||
1118 | } __attribute__((packed)) QUERY_SEC_DESC_REQ; | ||
1119 | |||
1051 | typedef struct smb_com_transaction_change_notify_req { | 1120 | typedef struct smb_com_transaction_change_notify_req { |
1052 | struct smb_hdr hdr; /* wct = 23 */ | 1121 | struct smb_hdr hdr; /* wct = 23 */ |
1053 | __u8 MaxSetupCount; | 1122 | __u8 MaxSetupCount; |
@@ -1068,10 +1137,12 @@ typedef struct smb_com_transaction_change_notify_req { | |||
1068 | __u8 WatchTree; /* 1 = Monitor subdirectories */ | 1137 | __u8 WatchTree; /* 1 = Monitor subdirectories */ |
1069 | __u8 Reserved2; | 1138 | __u8 Reserved2; |
1070 | __le16 ByteCount; | 1139 | __le16 ByteCount; |
1071 | /* __u8 Pad[3];*/ | 1140 | /* __u8 Pad[3];*/ |
1072 | /* __u8 Data[1];*/ | 1141 | /* __u8 Data[1];*/ |
1073 | } __attribute__((packed)) TRANSACT_CHANGE_NOTIFY_REQ; | 1142 | } __attribute__((packed)) TRANSACT_CHANGE_NOTIFY_REQ; |
1074 | 1143 | ||
1144 | /* BB eventually change to use generic ntransact rsp struct | ||
1145 | and validation routine */ | ||
1075 | typedef struct smb_com_transaction_change_notify_rsp { | 1146 | typedef struct smb_com_transaction_change_notify_rsp { |
1076 | struct smb_hdr hdr; /* wct = 18 */ | 1147 | struct smb_hdr hdr; /* wct = 18 */ |
1077 | __u8 Reserved[3]; | 1148 | __u8 Reserved[3]; |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 1b73f4f4c5ce..3c03aadaff0c 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -48,8 +48,8 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, | |||
48 | struct smb_hdr * /* out */ , | 48 | struct smb_hdr * /* out */ , |
49 | int * /* bytes returned */ , const int long_op); | 49 | int * /* bytes returned */ , const int long_op); |
50 | extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, | 50 | extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, |
51 | struct kvec *, int /* nvec */, | 51 | struct kvec *, int /* nvec to send */, |
52 | int * /* bytes returned */ , const int long_op); | 52 | int * /* type of buf returned */ , const int long_op); |
53 | extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); | 53 | extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); |
54 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); | 54 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); |
55 | extern int is_valid_oplock_break(struct smb_hdr *smb); | 55 | extern int is_valid_oplock_break(struct smb_hdr *smb); |
@@ -93,11 +93,12 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
93 | const struct nls_table *); | 93 | const struct nls_table *); |
94 | 94 | ||
95 | extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, | 95 | extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, |
96 | const char *searchName, const struct nls_table *nls_codepage, | 96 | const char *searchName, const struct nls_table *nls_codepage, |
97 | __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map, const char dirsep); | 97 | __u16 *searchHandle, struct cifs_search_info * psrch_inf, |
98 | int map, const char dirsep); | ||
98 | 99 | ||
99 | extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, | 100 | extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, |
100 | __u16 searchHandle, struct cifs_search_info * psrch_inf); | 101 | __u16 searchHandle, struct cifs_search_info * psrch_inf); |
101 | 102 | ||
102 | extern int CIFSFindClose(const int, struct cifsTconInfo *tcon, | 103 | extern int CIFSFindClose(const int, struct cifsTconInfo *tcon, |
103 | const __u16 search_handle); | 104 | const __u16 search_handle); |
@@ -230,19 +231,18 @@ extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, | |||
230 | const int smb_file_id); | 231 | const int smb_file_id); |
231 | 232 | ||
232 | extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | 233 | extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, |
233 | const int netfid, unsigned int count, | 234 | const int netfid, unsigned int count, |
234 | const __u64 lseek, unsigned int *nbytes, char **buf); | 235 | const __u64 lseek, unsigned int *nbytes, char **buf, |
236 | int * return_buf_type); | ||
235 | extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | 237 | extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, |
236 | const int netfid, const unsigned int count, | 238 | const int netfid, const unsigned int count, |
237 | const __u64 lseek, unsigned int *nbytes, | 239 | const __u64 lseek, unsigned int *nbytes, |
238 | const char *buf, const char __user *ubuf, | 240 | const char *buf, const char __user *ubuf, |
239 | const int long_op); | 241 | const int long_op); |
240 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
241 | extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | 242 | extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, |
242 | const int netfid, const unsigned int count, | 243 | const int netfid, const unsigned int count, |
243 | const __u64 offset, unsigned int *nbytes, | 244 | const __u64 offset, unsigned int *nbytes, |
244 | struct kvec *iov, const int nvec, const int long_op); | 245 | struct kvec *iov, const int nvec, const int long_op); |
245 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | ||
246 | extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, | 246 | extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, |
247 | const unsigned char *searchName, __u64 * inode_number, | 247 | const unsigned char *searchName, __u64 * inode_number, |
248 | const struct nls_table *nls_codepage, | 248 | const struct nls_table *nls_codepage, |
@@ -269,6 +269,8 @@ extern void tconInfoFree(struct cifsTconInfo *); | |||
269 | extern int cifs_reconnect(struct TCP_Server_Info *server); | 269 | extern int cifs_reconnect(struct TCP_Server_Info *server); |
270 | 270 | ||
271 | extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *,__u32 *); | 271 | extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *,__u32 *); |
272 | extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, | ||
273 | __u32 *); | ||
272 | extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key, | 274 | extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key, |
273 | __u32 expected_sequence_number); | 275 | __u32 expected_sequence_number); |
274 | extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); | 276 | extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); |
@@ -297,6 +299,9 @@ extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, | |||
297 | const char *fileName, const char * ea_name, | 299 | const char *fileName, const char * ea_name, |
298 | const void * ea_value, const __u16 ea_value_len, | 300 | const void * ea_value, const __u16 ea_value_len, |
299 | const struct nls_table *nls_codepage, int remap_special_chars); | 301 | const struct nls_table *nls_codepage, int remap_special_chars); |
302 | extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, | ||
303 | __u16 fid, char *acl_inf, const int buflen, | ||
304 | const int acl_type /* ACCESS vs. DEFAULT */); | ||
300 | extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon, | 305 | extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon, |
301 | const unsigned char *searchName, | 306 | const unsigned char *searchName, |
302 | char *acl_inf, const int buflen,const int acl_type, | 307 | char *acl_inf, const int buflen,const int acl_type, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 6867e556d37e..217323b0c896 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include "cifsproto.h" | 37 | #include "cifsproto.h" |
38 | #include "cifs_unicode.h" | 38 | #include "cifs_unicode.h" |
39 | #include "cifs_debug.h" | 39 | #include "cifs_debug.h" |
40 | #include "cifsacl.h" | ||
40 | 41 | ||
41 | #ifdef CONFIG_CIFS_POSIX | 42 | #ifdef CONFIG_CIFS_POSIX |
42 | static struct { | 43 | static struct { |
@@ -372,8 +373,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
372 | rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, | 373 | rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, |
373 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 374 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
374 | if (rc == 0) { | 375 | if (rc == 0) { |
375 | server->secMode = pSMBr->SecurityMode; | 376 | server->secMode = pSMBr->SecurityMode; |
376 | server->secType = NTLM; /* BB override default for | 377 | if((server->secMode & SECMODE_USER) == 0) |
378 | cFYI(1,("share mode security")); | ||
379 | server->secType = NTLM; /* BB override default for | ||
377 | NTLMv2 or kerberos v5 */ | 380 | NTLMv2 or kerberos v5 */ |
378 | /* one byte - no need to convert this or EncryptionKeyLen | 381 | /* one byte - no need to convert this or EncryptionKeyLen |
379 | from little endian */ | 382 | from little endian */ |
@@ -383,7 +386,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
383 | min(le32_to_cpu(pSMBr->MaxBufferSize), | 386 | min(le32_to_cpu(pSMBr->MaxBufferSize), |
384 | (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); | 387 | (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); |
385 | server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); | 388 | server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); |
386 | cFYI(0, ("Max buf = %d ", ses->server->maxBuf)); | 389 | cFYI(0, ("Max buf = %d", ses->server->maxBuf)); |
387 | GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); | 390 | GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); |
388 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); | 391 | server->capabilities = le32_to_cpu(pSMBr->Capabilities); |
389 | server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone); | 392 | server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone); |
@@ -411,8 +414,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
411 | (server->server_GUID, | 414 | (server->server_GUID, |
412 | pSMBr->u.extended_response. | 415 | pSMBr->u.extended_response. |
413 | GUID, 16) != 0) { | 416 | GUID, 16) != 0) { |
414 | cFYI(1, | 417 | cFYI(1, ("server UID changed")); |
415 | ("UID of server does not match previous connection to same ip address")); | ||
416 | memcpy(server-> | 418 | memcpy(server-> |
417 | server_GUID, | 419 | server_GUID, |
418 | pSMBr->u. | 420 | pSMBr->u. |
@@ -958,21 +960,19 @@ openRetry: | |||
958 | return rc; | 960 | return rc; |
959 | } | 961 | } |
960 | 962 | ||
961 | /* If no buffer passed in, then caller wants to do the copy | ||
962 | as in the case of readpages so the SMB buffer must be | ||
963 | freed by the caller */ | ||
964 | |||
965 | int | 963 | int |
966 | CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | 964 | CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, |
967 | const int netfid, const unsigned int count, | 965 | const int netfid, const unsigned int count, |
968 | const __u64 lseek, unsigned int *nbytes, char **buf) | 966 | const __u64 lseek, unsigned int *nbytes, char **buf, |
967 | int * pbuf_type) | ||
969 | { | 968 | { |
970 | int rc = -EACCES; | 969 | int rc = -EACCES; |
971 | READ_REQ *pSMB = NULL; | 970 | READ_REQ *pSMB = NULL; |
972 | READ_RSP *pSMBr = NULL; | 971 | READ_RSP *pSMBr = NULL; |
973 | char *pReadData = NULL; | 972 | char *pReadData = NULL; |
974 | int bytes_returned; | ||
975 | int wct; | 973 | int wct; |
974 | int resp_buf_type = 0; | ||
975 | struct kvec iov[1]; | ||
976 | 976 | ||
977 | cFYI(1,("Reading %d bytes on fid %d",count,netfid)); | 977 | cFYI(1,("Reading %d bytes on fid %d",count,netfid)); |
978 | if(tcon->ses->capabilities & CAP_LARGE_FILES) | 978 | if(tcon->ses->capabilities & CAP_LARGE_FILES) |
@@ -981,8 +981,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | |||
981 | wct = 10; /* old style read */ | 981 | wct = 10; /* old style read */ |
982 | 982 | ||
983 | *nbytes = 0; | 983 | *nbytes = 0; |
984 | rc = smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB, | 984 | rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB); |
985 | (void **) &pSMBr); | ||
986 | if (rc) | 985 | if (rc) |
987 | return rc; | 986 | return rc; |
988 | 987 | ||
@@ -990,13 +989,13 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | |||
990 | if (tcon->ses->server == NULL) | 989 | if (tcon->ses->server == NULL) |
991 | return -ECONNABORTED; | 990 | return -ECONNABORTED; |
992 | 991 | ||
993 | pSMB->AndXCommand = 0xFF; /* none */ | 992 | pSMB->AndXCommand = 0xFF; /* none */ |
994 | pSMB->Fid = netfid; | 993 | pSMB->Fid = netfid; |
995 | pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); | 994 | pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); |
996 | if(wct == 12) | 995 | if(wct == 12) |
997 | pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); | 996 | pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); |
998 | else if((lseek >> 32) > 0) /* can not handle this big offset for old */ | 997 | else if((lseek >> 32) > 0) /* can not handle this big offset for old */ |
999 | return -EIO; | 998 | return -EIO; |
1000 | 999 | ||
1001 | pSMB->Remaining = 0; | 1000 | pSMB->Remaining = 0; |
1002 | pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); | 1001 | pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); |
@@ -1005,14 +1004,18 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | |||
1005 | pSMB->ByteCount = 0; /* no need to do le conversion since 0 */ | 1004 | pSMB->ByteCount = 0; /* no need to do le conversion since 0 */ |
1006 | else { | 1005 | else { |
1007 | /* old style read */ | 1006 | /* old style read */ |
1008 | struct smb_com_readx_req * pSMBW = | 1007 | struct smb_com_readx_req * pSMBW = |
1009 | (struct smb_com_readx_req *)pSMB; | 1008 | (struct smb_com_readx_req *)pSMB; |
1010 | pSMBW->ByteCount = 0; | 1009 | pSMBW->ByteCount = 0; |
1011 | } | 1010 | } |
1012 | 1011 | ||
1013 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1012 | iov[0].iov_base = (char *)pSMB; |
1014 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1013 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; |
1014 | rc = SendReceive2(xid, tcon->ses, iov, | ||
1015 | 1 /* num iovecs */, | ||
1016 | &resp_buf_type, 0); | ||
1015 | cifs_stats_inc(&tcon->num_reads); | 1017 | cifs_stats_inc(&tcon->num_reads); |
1018 | pSMBr = (READ_RSP *)iov[0].iov_base; | ||
1016 | if (rc) { | 1019 | if (rc) { |
1017 | cERROR(1, ("Send error in read = %d", rc)); | 1020 | cERROR(1, ("Send error in read = %d", rc)); |
1018 | } else { | 1021 | } else { |
@@ -1022,33 +1025,43 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | |||
1022 | *nbytes = data_length; | 1025 | *nbytes = data_length; |
1023 | 1026 | ||
1024 | /*check that DataLength would not go beyond end of SMB */ | 1027 | /*check that DataLength would not go beyond end of SMB */ |
1025 | if ((data_length > CIFSMaxBufSize) | 1028 | if ((data_length > CIFSMaxBufSize) |
1026 | || (data_length > count)) { | 1029 | || (data_length > count)) { |
1027 | cFYI(1,("bad length %d for count %d",data_length,count)); | 1030 | cFYI(1,("bad length %d for count %d",data_length,count)); |
1028 | rc = -EIO; | 1031 | rc = -EIO; |
1029 | *nbytes = 0; | 1032 | *nbytes = 0; |
1030 | } else { | 1033 | } else { |
1031 | pReadData = | 1034 | pReadData = (char *) (&pSMBr->hdr.Protocol) + |
1032 | (char *) (&pSMBr->hdr.Protocol) + | ||
1033 | le16_to_cpu(pSMBr->DataOffset); | 1035 | le16_to_cpu(pSMBr->DataOffset); |
1034 | /* if(rc = copy_to_user(buf, pReadData, data_length)) { | 1036 | /* if(rc = copy_to_user(buf, pReadData, data_length)) { |
1035 | cERROR(1,("Faulting on read rc = %d",rc)); | 1037 | cERROR(1,("Faulting on read rc = %d",rc)); |
1036 | rc = -EFAULT; | 1038 | rc = -EFAULT; |
1037 | }*/ /* can not use copy_to_user when using page cache*/ | 1039 | }*/ /* can not use copy_to_user when using page cache*/ |
1038 | if(*buf) | 1040 | if(*buf) |
1039 | memcpy(*buf,pReadData,data_length); | 1041 | memcpy(*buf,pReadData,data_length); |
1040 | } | 1042 | } |
1041 | } | 1043 | } |
1042 | if(*buf) | ||
1043 | cifs_buf_release(pSMB); | ||
1044 | else | ||
1045 | *buf = (char *)pSMB; | ||
1046 | 1044 | ||
1047 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 1045 | cifs_small_buf_release(pSMB); |
1046 | if(*buf) { | ||
1047 | if(resp_buf_type == CIFS_SMALL_BUFFER) | ||
1048 | cifs_small_buf_release(iov[0].iov_base); | ||
1049 | else if(resp_buf_type == CIFS_LARGE_BUFFER) | ||
1050 | cifs_buf_release(iov[0].iov_base); | ||
1051 | } else /* return buffer to caller to free */ /* BB FIXME how do we tell caller if it is not a large buffer */ { | ||
1052 | *buf = iov[0].iov_base; | ||
1053 | if(resp_buf_type == CIFS_SMALL_BUFFER) | ||
1054 | *pbuf_type = CIFS_SMALL_BUFFER; | ||
1055 | else if(resp_buf_type == CIFS_LARGE_BUFFER) | ||
1056 | *pbuf_type = CIFS_LARGE_BUFFER; | ||
1057 | } | ||
1058 | |||
1059 | /* Note: On -EAGAIN error only caller can retry on handle based calls | ||
1048 | since file handle passed in no longer valid */ | 1060 | since file handle passed in no longer valid */ |
1049 | return rc; | 1061 | return rc; |
1050 | } | 1062 | } |
1051 | 1063 | ||
1064 | |||
1052 | int | 1065 | int |
1053 | CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | 1066 | CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, |
1054 | const int netfid, const unsigned int count, | 1067 | const int netfid, const unsigned int count, |
@@ -1155,7 +1168,6 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
1155 | return rc; | 1168 | return rc; |
1156 | } | 1169 | } |
1157 | 1170 | ||
1158 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
1159 | int | 1171 | int |
1160 | CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | 1172 | CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, |
1161 | const int netfid, const unsigned int count, | 1173 | const int netfid, const unsigned int count, |
@@ -1164,10 +1176,10 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | |||
1164 | { | 1176 | { |
1165 | int rc = -EACCES; | 1177 | int rc = -EACCES; |
1166 | WRITE_REQ *pSMB = NULL; | 1178 | WRITE_REQ *pSMB = NULL; |
1167 | int bytes_returned, wct; | 1179 | int wct; |
1168 | int smb_hdr_len; | 1180 | int smb_hdr_len; |
1181 | int resp_buf_type = 0; | ||
1169 | 1182 | ||
1170 | /* BB removeme BB */ | ||
1171 | cFYI(1,("write2 at %lld %d bytes", (long long)offset, count)); | 1183 | cFYI(1,("write2 at %lld %d bytes", (long long)offset, count)); |
1172 | 1184 | ||
1173 | if(tcon->ses->capabilities & CAP_LARGE_FILES) | 1185 | if(tcon->ses->capabilities & CAP_LARGE_FILES) |
@@ -1210,22 +1222,34 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | |||
1210 | pSMBW->ByteCount = cpu_to_le16(count + 5); | 1222 | pSMBW->ByteCount = cpu_to_le16(count + 5); |
1211 | } | 1223 | } |
1212 | iov[0].iov_base = pSMB; | 1224 | iov[0].iov_base = pSMB; |
1213 | iov[0].iov_len = smb_hdr_len + 4; | 1225 | if(wct == 14) |
1226 | iov[0].iov_len = smb_hdr_len + 4; | ||
1227 | else /* wct == 12 pad bigger by four bytes */ | ||
1228 | iov[0].iov_len = smb_hdr_len + 8; | ||
1229 | |||
1214 | 1230 | ||
1215 | rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &bytes_returned, | 1231 | rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, |
1216 | long_op); | 1232 | long_op); |
1217 | cifs_stats_inc(&tcon->num_writes); | 1233 | cifs_stats_inc(&tcon->num_writes); |
1218 | if (rc) { | 1234 | if (rc) { |
1219 | cFYI(1, ("Send error Write2 = %d", rc)); | 1235 | cFYI(1, ("Send error Write2 = %d", rc)); |
1220 | *nbytes = 0; | 1236 | *nbytes = 0; |
1237 | } else if(resp_buf_type == 0) { | ||
1238 | /* presumably this can not happen, but best to be safe */ | ||
1239 | rc = -EIO; | ||
1240 | *nbytes = 0; | ||
1221 | } else { | 1241 | } else { |
1222 | WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB; | 1242 | WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base; |
1223 | *nbytes = le16_to_cpu(pSMBr->CountHigh); | 1243 | *nbytes = le16_to_cpu(pSMBr->CountHigh); |
1224 | *nbytes = (*nbytes) << 16; | 1244 | *nbytes = (*nbytes) << 16; |
1225 | *nbytes += le16_to_cpu(pSMBr->Count); | 1245 | *nbytes += le16_to_cpu(pSMBr->Count); |
1226 | } | 1246 | } |
1227 | 1247 | ||
1228 | cifs_small_buf_release(pSMB); | 1248 | cifs_small_buf_release(pSMB); |
1249 | if(resp_buf_type == CIFS_SMALL_BUFFER) | ||
1250 | cifs_small_buf_release(iov[0].iov_base); | ||
1251 | else if(resp_buf_type == CIFS_LARGE_BUFFER) | ||
1252 | cifs_buf_release(iov[0].iov_base); | ||
1229 | 1253 | ||
1230 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 1254 | /* Note: On -EAGAIN error only caller can retry on handle based calls |
1231 | since file handle passed in no longer valid */ | 1255 | since file handle passed in no longer valid */ |
@@ -1234,8 +1258,6 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | |||
1234 | } | 1258 | } |
1235 | 1259 | ||
1236 | 1260 | ||
1237 | #endif /* CIFS_EXPERIMENTAL */ | ||
1238 | |||
1239 | int | 1261 | int |
1240 | CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | 1262 | CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, |
1241 | const __u16 smb_file_id, const __u64 len, | 1263 | const __u16 smb_file_id, const __u64 len, |
@@ -1906,6 +1928,90 @@ querySymLinkRetry: | |||
1906 | return rc; | 1928 | return rc; |
1907 | } | 1929 | } |
1908 | 1930 | ||
1931 | /* Initialize NT TRANSACT SMB into small smb request buffer. | ||
1932 | This assumes that all NT TRANSACTS that we init here have | ||
1933 | total parm and data under about 400 bytes (to fit in small cifs | ||
1934 | buffer size), which is the case so far, it easily fits. NB: | ||
1935 | Setup words themselves and ByteCount | ||
1936 | MaxSetupCount (size of returned setup area) and | ||
1937 | MaxParameterCount (returned parms size) must be set by caller */ | ||
1938 | static int | ||
1939 | smb_init_ntransact(const __u16 sub_command, const int setup_count, | ||
1940 | const int parm_len, struct cifsTconInfo *tcon, | ||
1941 | void ** ret_buf) | ||
1942 | { | ||
1943 | int rc; | ||
1944 | __u32 temp_offset; | ||
1945 | struct smb_com_ntransact_req * pSMB; | ||
1946 | |||
1947 | rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon, | ||
1948 | (void **)&pSMB); | ||
1949 | if (rc) | ||
1950 | return rc; | ||
1951 | *ret_buf = (void *)pSMB; | ||
1952 | pSMB->Reserved = 0; | ||
1953 | pSMB->TotalParameterCount = cpu_to_le32(parm_len); | ||
1954 | pSMB->TotalDataCount = 0; | ||
1955 | pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - | ||
1956 | MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); | ||
1957 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
1958 | pSMB->DataCount = pSMB->TotalDataCount; | ||
1959 | temp_offset = offsetof(struct smb_com_ntransact_req, Parms) + | ||
1960 | (setup_count * 2) - 4 /* for rfc1001 length itself */; | ||
1961 | pSMB->ParameterOffset = cpu_to_le32(temp_offset); | ||
1962 | pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len); | ||
1963 | pSMB->SetupCount = setup_count; /* no need to le convert byte fields */ | ||
1964 | pSMB->SubCommand = cpu_to_le16(sub_command); | ||
1965 | return 0; | ||
1966 | } | ||
1967 | |||
1968 | static int | ||
1969 | validate_ntransact(char * buf, char ** ppparm, char ** ppdata, | ||
1970 | int * pdatalen, int * pparmlen) | ||
1971 | { | ||
1972 | char * end_of_smb; | ||
1973 | __u32 data_count, data_offset, parm_count, parm_offset; | ||
1974 | struct smb_com_ntransact_rsp * pSMBr; | ||
1975 | |||
1976 | if(buf == NULL) | ||
1977 | return -EINVAL; | ||
1978 | |||
1979 | pSMBr = (struct smb_com_ntransact_rsp *)buf; | ||
1980 | |||
1981 | /* ByteCount was converted from little endian in SendReceive */ | ||
1982 | end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount + | ||
1983 | (char *)&pSMBr->ByteCount; | ||
1984 | |||
1985 | |||
1986 | data_offset = le32_to_cpu(pSMBr->DataOffset); | ||
1987 | data_count = le32_to_cpu(pSMBr->DataCount); | ||
1988 | parm_offset = le32_to_cpu(pSMBr->ParameterOffset); | ||
1989 | parm_count = le32_to_cpu(pSMBr->ParameterCount); | ||
1990 | |||
1991 | *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset; | ||
1992 | *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset; | ||
1993 | |||
1994 | /* should we also check that parm and data areas do not overlap? */ | ||
1995 | if(*ppparm > end_of_smb) { | ||
1996 | cFYI(1,("parms start after end of smb")); | ||
1997 | return -EINVAL; | ||
1998 | } else if(parm_count + *ppparm > end_of_smb) { | ||
1999 | cFYI(1,("parm end after end of smb")); | ||
2000 | return -EINVAL; | ||
2001 | } else if(*ppdata > end_of_smb) { | ||
2002 | cFYI(1,("data starts after end of smb")); | ||
2003 | return -EINVAL; | ||
2004 | } else if(data_count + *ppdata > end_of_smb) { | ||
2005 | cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p", | ||
2006 | *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */ | ||
2007 | return -EINVAL; | ||
2008 | } else if(parm_count + data_count > pSMBr->ByteCount) { | ||
2009 | cFYI(1,("parm count and data count larger than SMB")); | ||
2010 | return -EINVAL; | ||
2011 | } | ||
2012 | return 0; | ||
2013 | } | ||
2014 | |||
1909 | int | 2015 | int |
1910 | CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, | 2016 | CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, |
1911 | const unsigned char *searchName, | 2017 | const unsigned char *searchName, |
@@ -1928,7 +2034,8 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, | |||
1928 | pSMB->TotalDataCount = 0; | 2034 | pSMB->TotalDataCount = 0; |
1929 | pSMB->MaxParameterCount = cpu_to_le32(2); | 2035 | pSMB->MaxParameterCount = cpu_to_le32(2); |
1930 | /* BB find exact data count max from sess structure BB */ | 2036 | /* BB find exact data count max from sess structure BB */ |
1931 | pSMB->MaxDataCount = cpu_to_le32(4000); | 2037 | pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - |
2038 | MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); | ||
1932 | pSMB->MaxSetupCount = 4; | 2039 | pSMB->MaxSetupCount = 4; |
1933 | pSMB->Reserved = 0; | 2040 | pSMB->Reserved = 0; |
1934 | pSMB->ParameterOffset = 0; | 2041 | pSMB->ParameterOffset = 0; |
@@ -1955,7 +2062,9 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, | |||
1955 | rc = -EIO; /* bad smb */ | 2062 | rc = -EIO; /* bad smb */ |
1956 | else { | 2063 | else { |
1957 | if(data_count && (data_count < 2048)) { | 2064 | if(data_count && (data_count < 2048)) { |
1958 | char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount; | 2065 | char * end_of_smb = 2 /* sizeof byte count */ + |
2066 | pSMBr->ByteCount + | ||
2067 | (char *)&pSMBr->ByteCount; | ||
1959 | 2068 | ||
1960 | struct reparse_data * reparse_buf = (struct reparse_data *) | 2069 | struct reparse_data * reparse_buf = (struct reparse_data *) |
1961 | ((char *)&pSMBr->hdr.Protocol + data_offset); | 2070 | ((char *)&pSMBr->hdr.Protocol + data_offset); |
@@ -2199,6 +2308,7 @@ queryAclRetry: | |||
2199 | 2308 | ||
2200 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 2309 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
2201 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 2310 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
2311 | cifs_stats_inc(&tcon->num_acl_get); | ||
2202 | if (rc) { | 2312 | if (rc) { |
2203 | cFYI(1, ("Send error in Query POSIX ACL = %d", rc)); | 2313 | cFYI(1, ("Send error in Query POSIX ACL = %d", rc)); |
2204 | } else { | 2314 | } else { |
@@ -2386,6 +2496,92 @@ GetExtAttrOut: | |||
2386 | 2496 | ||
2387 | #endif /* CONFIG_POSIX */ | 2497 | #endif /* CONFIG_POSIX */ |
2388 | 2498 | ||
2499 | |||
2500 | /* security id for everyone */ | ||
2501 | const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}}; | ||
2502 | /* group users */ | ||
2503 | const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}}; | ||
2504 | |||
2505 | /* Convert CIFS ACL to POSIX form */ | ||
2506 | static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len) | ||
2507 | { | ||
2508 | return 0; | ||
2509 | } | ||
2510 | |||
2511 | /* Get Security Descriptor (by handle) from remote server for a file or dir */ | ||
2512 | int | ||
2513 | CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, | ||
2514 | /* BB fix up return info */ char *acl_inf, const int buflen, | ||
2515 | const int acl_type /* ACCESS/DEFAULT not sure implication */) | ||
2516 | { | ||
2517 | int rc = 0; | ||
2518 | int buf_type = 0; | ||
2519 | QUERY_SEC_DESC_REQ * pSMB; | ||
2520 | struct kvec iov[1]; | ||
2521 | |||
2522 | cFYI(1, ("GetCifsACL")); | ||
2523 | |||
2524 | rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0, | ||
2525 | 8 /* parm len */, tcon, (void **) &pSMB); | ||
2526 | if (rc) | ||
2527 | return rc; | ||
2528 | |||
2529 | pSMB->MaxParameterCount = cpu_to_le32(4); | ||
2530 | /* BB TEST with big acls that might need to be e.g. larger than 16K */ | ||
2531 | pSMB->MaxSetupCount = 0; | ||
2532 | pSMB->Fid = fid; /* file handle always le */ | ||
2533 | pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP | | ||
2534 | CIFS_ACL_DACL); | ||
2535 | pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */ | ||
2536 | pSMB->hdr.smb_buf_length += 11; | ||
2537 | iov[0].iov_base = (char *)pSMB; | ||
2538 | iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; | ||
2539 | |||
2540 | rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0); | ||
2541 | cifs_stats_inc(&tcon->num_acl_get); | ||
2542 | if (rc) { | ||
2543 | cFYI(1, ("Send error in QuerySecDesc = %d", rc)); | ||
2544 | } else { /* decode response */ | ||
2545 | struct cifs_sid * psec_desc; | ||
2546 | __le32 * parm; | ||
2547 | int parm_len; | ||
2548 | int data_len; | ||
2549 | int acl_len; | ||
2550 | struct smb_com_ntransact_rsp * pSMBr; | ||
2551 | |||
2552 | /* validate_nttransact */ | ||
2553 | rc = validate_ntransact(iov[0].iov_base, (char **)&parm, | ||
2554 | (char **)&psec_desc, | ||
2555 | &parm_len, &data_len); | ||
2556 | |||
2557 | if(rc) | ||
2558 | goto qsec_out; | ||
2559 | pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base; | ||
2560 | |||
2561 | cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */ | ||
2562 | |||
2563 | if (le32_to_cpu(pSMBr->ParameterCount) != 4) { | ||
2564 | rc = -EIO; /* bad smb */ | ||
2565 | goto qsec_out; | ||
2566 | } | ||
2567 | |||
2568 | /* BB check that data area is minimum length and as big as acl_len */ | ||
2569 | |||
2570 | acl_len = le32_to_cpu(*(__le32 *)parm); | ||
2571 | /* BB check if(acl_len > bufsize) */ | ||
2572 | |||
2573 | parse_sec_desc(psec_desc, acl_len); | ||
2574 | } | ||
2575 | qsec_out: | ||
2576 | if(buf_type == CIFS_SMALL_BUFFER) | ||
2577 | cifs_small_buf_release(iov[0].iov_base); | ||
2578 | else if(buf_type == CIFS_LARGE_BUFFER) | ||
2579 | cifs_buf_release(iov[0].iov_base); | ||
2580 | cifs_small_buf_release(pSMB); | ||
2581 | return rc; | ||
2582 | } | ||
2583 | |||
2584 | |||
2389 | /* Legacy Query Path Information call for lookup to old servers such | 2585 | /* Legacy Query Path Information call for lookup to old servers such |
2390 | as Win9x/WinME */ | 2586 | as Win9x/WinME */ |
2391 | int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, | 2587 | int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, |
@@ -4284,7 +4480,7 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | |||
4284 | { | 4480 | { |
4285 | int rc = 0; | 4481 | int rc = 0; |
4286 | struct smb_com_transaction_change_notify_req * pSMB = NULL; | 4482 | struct smb_com_transaction_change_notify_req * pSMB = NULL; |
4287 | struct smb_com_transaction_change_notify_rsp * pSMBr = NULL; | 4483 | struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL; |
4288 | struct dir_notify_req *dnotify_req; | 4484 | struct dir_notify_req *dnotify_req; |
4289 | int bytes_returned; | 4485 | int bytes_returned; |
4290 | 4486 | ||
@@ -4299,6 +4495,10 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | |||
4299 | pSMB->MaxParameterCount = cpu_to_le32(2); | 4495 | pSMB->MaxParameterCount = cpu_to_le32(2); |
4300 | /* BB find exact data count max from sess structure BB */ | 4496 | /* BB find exact data count max from sess structure BB */ |
4301 | pSMB->MaxDataCount = 0; /* same in little endian or be */ | 4497 | pSMB->MaxDataCount = 0; /* same in little endian or be */ |
4498 | /* BB VERIFY verify which is correct for above BB */ | ||
4499 | pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - | ||
4500 | MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); | ||
4501 | |||
4302 | pSMB->MaxSetupCount = 4; | 4502 | pSMB->MaxSetupCount = 4; |
4303 | pSMB->Reserved = 0; | 4503 | pSMB->Reserved = 0; |
4304 | pSMB->ParameterOffset = 0; | 4504 | pSMB->ParameterOffset = 0; |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index c467de857610..88f60aa52058 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -76,12 +76,19 @@ struct smb_vol { | |||
76 | unsigned setuids:1; | 76 | unsigned setuids:1; |
77 | unsigned noperm:1; | 77 | unsigned noperm:1; |
78 | unsigned no_psx_acl:1; /* set if posix acl support should be disabled */ | 78 | unsigned no_psx_acl:1; /* set if posix acl support should be disabled */ |
79 | unsigned cifs_acl:1; | ||
79 | unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/ | 80 | unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/ |
80 | unsigned server_ino:1; /* use inode numbers from server ie UniqueId */ | 81 | unsigned server_ino:1; /* use inode numbers from server ie UniqueId */ |
81 | unsigned direct_io:1; | 82 | unsigned direct_io:1; |
82 | unsigned remap:1; /* set to remap seven reserved chars in filenames */ | 83 | unsigned remap:1; /* set to remap seven reserved chars in filenames */ |
83 | unsigned posix_paths:1; /* unset to not ask for posix pathnames. */ | 84 | unsigned posix_paths:1; /* unset to not ask for posix pathnames. */ |
84 | unsigned sfu_emul:1; | 85 | unsigned sfu_emul:1; |
86 | unsigned krb5:1; | ||
87 | unsigned ntlm:1; | ||
88 | unsigned ntlmv2:1; | ||
89 | unsigned nullauth:1; /* attempt to authenticate with null user */ | ||
90 | unsigned sign:1; | ||
91 | unsigned seal:1; /* encrypt */ | ||
85 | unsigned nocase; /* request case insensitive filenames */ | 92 | unsigned nocase; /* request case insensitive filenames */ |
86 | unsigned nobrl; /* disable sending byte range locks to srv */ | 93 | unsigned nobrl; /* disable sending byte range locks to srv */ |
87 | unsigned int rsize; | 94 | unsigned int rsize; |
@@ -508,7 +515,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
508 | /* else length ok */ | 515 | /* else length ok */ |
509 | reconnect = 0; | 516 | reconnect = 0; |
510 | 517 | ||
511 | if(pdu_length > MAX_CIFS_HDR_SIZE - 4) { | 518 | if(pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) { |
512 | isLargeBuf = TRUE; | 519 | isLargeBuf = TRUE; |
513 | memcpy(bigbuf, smallbuf, 4); | 520 | memcpy(bigbuf, smallbuf, 4); |
514 | smb_buffer = bigbuf; | 521 | smb_buffer = bigbuf; |
@@ -777,7 +784,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
777 | 784 | ||
778 | /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ | 785 | /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ |
779 | vol->rw = TRUE; | 786 | vol->rw = TRUE; |
780 | 787 | vol->ntlm = TRUE; | |
781 | /* default is always to request posix paths. */ | 788 | /* default is always to request posix paths. */ |
782 | vol->posix_paths = 1; | 789 | vol->posix_paths = 1; |
783 | 790 | ||
@@ -903,6 +910,39 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
903 | printk(KERN_WARNING "CIFS: ip address too long\n"); | 910 | printk(KERN_WARNING "CIFS: ip address too long\n"); |
904 | return 1; | 911 | return 1; |
905 | } | 912 | } |
913 | } else if (strnicmp(data, "sec", 3) == 0) { | ||
914 | if (!value || !*value) { | ||
915 | cERROR(1,("no security value specified")); | ||
916 | continue; | ||
917 | } else if (strnicmp(value, "krb5i", 5) == 0) { | ||
918 | vol->sign = 1; | ||
919 | vol->krb5 = 1; | ||
920 | } else if (strnicmp(value, "krb5p", 5) == 0) { | ||
921 | /* vol->seal = 1; | ||
922 | vol->krb5 = 1; */ | ||
923 | cERROR(1,("Krb5 cifs privacy not supported")); | ||
924 | return 1; | ||
925 | } else if (strnicmp(value, "krb5", 4) == 0) { | ||
926 | vol->krb5 = 1; | ||
927 | } else if (strnicmp(value, "ntlmv2i", 7) == 0) { | ||
928 | vol->ntlmv2 = 1; | ||
929 | vol->sign = 1; | ||
930 | } else if (strnicmp(value, "ntlmv2", 6) == 0) { | ||
931 | vol->ntlmv2 = 1; | ||
932 | } else if (strnicmp(value, "ntlmi", 5) == 0) { | ||
933 | vol->ntlm = 1; | ||
934 | vol->sign = 1; | ||
935 | } else if (strnicmp(value, "ntlm", 4) == 0) { | ||
936 | /* ntlm is default so can be turned off too */ | ||
937 | vol->ntlm = 1; | ||
938 | } else if (strnicmp(value, "nontlm", 6) == 0) { | ||
939 | vol->ntlm = 0; | ||
940 | } else if (strnicmp(value, "none", 4) == 0) { | ||
941 | vol->nullauth = 1; | ||
942 | } else { | ||
943 | cERROR(1,("bad security option: %s", value)); | ||
944 | return 1; | ||
945 | } | ||
906 | } else if ((strnicmp(data, "unc", 3) == 0) | 946 | } else if ((strnicmp(data, "unc", 3) == 0) |
907 | || (strnicmp(data, "target", 6) == 0) | 947 | || (strnicmp(data, "target", 6) == 0) |
908 | || (strnicmp(data, "path", 4) == 0)) { | 948 | || (strnicmp(data, "path", 4) == 0)) { |
@@ -1120,6 +1160,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
1120 | vol->server_ino = 1; | 1160 | vol->server_ino = 1; |
1121 | } else if (strnicmp(data, "noserverino",9) == 0) { | 1161 | } else if (strnicmp(data, "noserverino",9) == 0) { |
1122 | vol->server_ino = 0; | 1162 | vol->server_ino = 0; |
1163 | } else if (strnicmp(data, "cifsacl",7) == 0) { | ||
1164 | vol->cifs_acl = 1; | ||
1165 | } else if (strnicmp(data, "nocifsacl", 9) == 0) { | ||
1166 | vol->cifs_acl = 0; | ||
1123 | } else if (strnicmp(data, "acl",3) == 0) { | 1167 | } else if (strnicmp(data, "acl",3) == 0) { |
1124 | vol->no_psx_acl = 0; | 1168 | vol->no_psx_acl = 0; |
1125 | } else if (strnicmp(data, "noacl",5) == 0) { | 1169 | } else if (strnicmp(data, "noacl",5) == 0) { |
@@ -1546,7 +1590,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1546 | cFYI(1, ("Username: %s ", volume_info.username)); | 1590 | cFYI(1, ("Username: %s ", volume_info.username)); |
1547 | 1591 | ||
1548 | } else { | 1592 | } else { |
1549 | cifserror("No username specified "); | 1593 | cifserror("No username specified"); |
1550 | /* In userspace mount helper we can get user name from alternate | 1594 | /* In userspace mount helper we can get user name from alternate |
1551 | locations such as env variables and files on disk */ | 1595 | locations such as env variables and files on disk */ |
1552 | kfree(volume_info.UNC); | 1596 | kfree(volume_info.UNC); |
@@ -1587,7 +1631,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1587 | return -EINVAL; | 1631 | return -EINVAL; |
1588 | } else /* which servers DFS root would we conect to */ { | 1632 | } else /* which servers DFS root would we conect to */ { |
1589 | cERROR(1, | 1633 | cERROR(1, |
1590 | ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified ")); | 1634 | ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified")); |
1591 | kfree(volume_info.UNC); | 1635 | kfree(volume_info.UNC); |
1592 | kfree(volume_info.password); | 1636 | kfree(volume_info.password); |
1593 | FreeXid(xid); | 1637 | FreeXid(xid); |
@@ -1626,7 +1670,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1626 | 1670 | ||
1627 | 1671 | ||
1628 | if (srvTcp) { | 1672 | if (srvTcp) { |
1629 | cFYI(1, ("Existing tcp session with server found ")); | 1673 | cFYI(1, ("Existing tcp session with server found")); |
1630 | } else { /* create socket */ | 1674 | } else { /* create socket */ |
1631 | if(volume_info.port) | 1675 | if(volume_info.port) |
1632 | sin_server.sin_port = htons(volume_info.port); | 1676 | sin_server.sin_port = htons(volume_info.port); |
@@ -1689,11 +1733,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1689 | 1733 | ||
1690 | if (existingCifsSes) { | 1734 | if (existingCifsSes) { |
1691 | pSesInfo = existingCifsSes; | 1735 | pSesInfo = existingCifsSes; |
1692 | cFYI(1, ("Existing smb sess found ")); | 1736 | cFYI(1, ("Existing smb sess found")); |
1693 | kfree(volume_info.password); | 1737 | kfree(volume_info.password); |
1694 | /* volume_info.UNC freed at end of function */ | 1738 | /* volume_info.UNC freed at end of function */ |
1695 | } else if (!rc) { | 1739 | } else if (!rc) { |
1696 | cFYI(1, ("Existing smb sess not found ")); | 1740 | cFYI(1, ("Existing smb sess not found")); |
1697 | pSesInfo = sesInfoAlloc(); | 1741 | pSesInfo = sesInfoAlloc(); |
1698 | if (pSesInfo == NULL) | 1742 | if (pSesInfo == NULL) |
1699 | rc = -ENOMEM; | 1743 | rc = -ENOMEM; |
@@ -1751,7 +1795,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1751 | cifs_sb->mnt_gid = volume_info.linux_gid; | 1795 | cifs_sb->mnt_gid = volume_info.linux_gid; |
1752 | cifs_sb->mnt_file_mode = volume_info.file_mode; | 1796 | cifs_sb->mnt_file_mode = volume_info.file_mode; |
1753 | cifs_sb->mnt_dir_mode = volume_info.dir_mode; | 1797 | cifs_sb->mnt_dir_mode = volume_info.dir_mode; |
1754 | cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode)); | 1798 | cFYI(1,("file mode: 0x%x dir mode: 0x%x", |
1799 | cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode)); | ||
1755 | 1800 | ||
1756 | if(volume_info.noperm) | 1801 | if(volume_info.noperm) |
1757 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; | 1802 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; |
@@ -1767,6 +1812,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1767 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL; | 1812 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL; |
1768 | if(volume_info.nobrl) | 1813 | if(volume_info.nobrl) |
1769 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL; | 1814 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL; |
1815 | if(volume_info.cifs_acl) | ||
1816 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; | ||
1770 | 1817 | ||
1771 | if(volume_info.direct_io) { | 1818 | if(volume_info.direct_io) { |
1772 | cFYI(1,("mounting share using direct i/o")); | 1819 | cFYI(1,("mounting share using direct i/o")); |
@@ -1777,7 +1824,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1777 | find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, | 1824 | find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, |
1778 | volume_info.username); | 1825 | volume_info.username); |
1779 | if (tcon) { | 1826 | if (tcon) { |
1780 | cFYI(1, ("Found match on UNC path ")); | 1827 | cFYI(1, ("Found match on UNC path")); |
1781 | /* we can have only one retry value for a connection | 1828 | /* we can have only one retry value for a connection |
1782 | to a share so for resources mounted more than once | 1829 | to a share so for resources mounted more than once |
1783 | to the same server share the last value passed in | 1830 | to the same server share the last value passed in |
@@ -1926,7 +1973,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
1926 | __u32 capabilities; | 1973 | __u32 capabilities; |
1927 | __u16 count; | 1974 | __u16 count; |
1928 | 1975 | ||
1929 | cFYI(1, ("In sesssetup ")); | 1976 | cFYI(1, ("In sesssetup")); |
1930 | if(ses == NULL) | 1977 | if(ses == NULL) |
1931 | return -EINVAL; | 1978 | return -EINVAL; |
1932 | user = ses->userName; | 1979 | user = ses->userName; |
@@ -3202,9 +3249,26 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
3202 | 3249 | ||
3203 | pSMB->AndXCommand = 0xFF; | 3250 | pSMB->AndXCommand = 0xFF; |
3204 | pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO); | 3251 | pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO); |
3205 | pSMB->PasswordLength = cpu_to_le16(1); /* minimum */ | ||
3206 | bcc_ptr = &pSMB->Password[0]; | 3252 | bcc_ptr = &pSMB->Password[0]; |
3207 | bcc_ptr++; /* skip password */ | 3253 | if((ses->server->secMode) & SECMODE_USER) { |
3254 | pSMB->PasswordLength = cpu_to_le16(1); /* minimum */ | ||
3255 | bcc_ptr++; /* skip password */ | ||
3256 | } else { | ||
3257 | pSMB->PasswordLength = cpu_to_le16(CIFS_SESSION_KEY_SIZE); | ||
3258 | /* BB FIXME add code to fail this if NTLMv2 or Kerberos | ||
3259 | specified as required (when that support is added to | ||
3260 | the vfs in the future) as only NTLM or the much | ||
3261 | weaker LANMAN (which we do not send) is accepted | ||
3262 | by Samba (not sure whether other servers allow | ||
3263 | NTLMv2 password here) */ | ||
3264 | SMBNTencrypt(ses->password, | ||
3265 | ses->server->cryptKey, | ||
3266 | bcc_ptr); | ||
3267 | |||
3268 | bcc_ptr += CIFS_SESSION_KEY_SIZE; | ||
3269 | *bcc_ptr = 0; | ||
3270 | bcc_ptr++; /* align */ | ||
3271 | } | ||
3208 | 3272 | ||
3209 | if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 3273 | if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) |
3210 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | 3274 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; |
@@ -3222,7 +3286,6 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
3222 | bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */ | 3286 | bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */ |
3223 | bcc_ptr += 2; /* skip trailing null */ | 3287 | bcc_ptr += 2; /* skip trailing null */ |
3224 | } else { /* ASCII */ | 3288 | } else { /* ASCII */ |
3225 | |||
3226 | strcpy(bcc_ptr, tree); | 3289 | strcpy(bcc_ptr, tree); |
3227 | bcc_ptr += strlen(tree) + 1; | 3290 | bcc_ptr += strlen(tree) + 1; |
3228 | } | 3291 | } |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 32cc96cafa3e..fed55e3c53df 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * vfs operations that deal with dentries | 4 | * vfs operations that deal with dentries |
5 | * | 5 | * |
6 | * Copyright (C) International Business Machines Corp., 2002,2003 | 6 | * Copyright (C) International Business Machines Corp., 2002,2005 |
7 | * Author(s): Steve French (sfrench@us.ibm.com) | 7 | * Author(s): Steve French (sfrench@us.ibm.com) |
8 | * | 8 | * |
9 | * This library is free software; you can redistribute it and/or modify | 9 | * This library is free software; you can redistribute it and/or modify |
@@ -200,8 +200,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
200 | (oplock & CIFS_CREATE_ACTION)) | 200 | (oplock & CIFS_CREATE_ACTION)) |
201 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | 201 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { |
202 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, | 202 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, |
203 | (__u64)current->euid, | 203 | (__u64)current->fsuid, |
204 | (__u64)current->egid, | 204 | (__u64)current->fsgid, |
205 | 0 /* dev */, | 205 | 0 /* dev */, |
206 | cifs_sb->local_nls, | 206 | cifs_sb->local_nls, |
207 | cifs_sb->mnt_cifs_flags & | 207 | cifs_sb->mnt_cifs_flags & |
@@ -325,7 +325,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, | |||
325 | else if (pTcon->ses->capabilities & CAP_UNIX) { | 325 | else if (pTcon->ses->capabilities & CAP_UNIX) { |
326 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | 326 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { |
327 | rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, | 327 | rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, |
328 | mode,(__u64)current->euid,(__u64)current->egid, | 328 | mode,(__u64)current->fsuid,(__u64)current->fsgid, |
329 | device_number, cifs_sb->local_nls, | 329 | device_number, cifs_sb->local_nls, |
330 | cifs_sb->mnt_cifs_flags & | 330 | cifs_sb->mnt_cifs_flags & |
331 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 331 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 5ade53d7bca8..77c990f0cb98 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -553,13 +553,13 @@ int cifs_closedir(struct inode *inode, struct file *file) | |||
553 | } | 553 | } |
554 | ptmp = pCFileStruct->srch_inf.ntwrk_buf_start; | 554 | ptmp = pCFileStruct->srch_inf.ntwrk_buf_start; |
555 | if (ptmp) { | 555 | if (ptmp) { |
556 | /* BB removeme BB */ cFYI(1, ("freeing smb buf in srch struct in closedir")); | 556 | cFYI(1, ("closedir free smb buf in srch struct")); |
557 | pCFileStruct->srch_inf.ntwrk_buf_start = NULL; | 557 | pCFileStruct->srch_inf.ntwrk_buf_start = NULL; |
558 | cifs_buf_release(ptmp); | 558 | cifs_buf_release(ptmp); |
559 | } | 559 | } |
560 | ptmp = pCFileStruct->search_resume_name; | 560 | ptmp = pCFileStruct->search_resume_name; |
561 | if (ptmp) { | 561 | if (ptmp) { |
562 | /* BB removeme BB */ cFYI(1, ("freeing resume name in closedir")); | 562 | cFYI(1, ("closedir free resume name")); |
563 | pCFileStruct->search_resume_name = NULL; | 563 | pCFileStruct->search_resume_name = NULL; |
564 | kfree(ptmp); | 564 | kfree(ptmp); |
565 | } | 565 | } |
@@ -868,10 +868,9 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
868 | if (rc != 0) | 868 | if (rc != 0) |
869 | break; | 869 | break; |
870 | } | 870 | } |
871 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
872 | /* BB FIXME We can not sign across two buffers yet */ | 871 | /* BB FIXME We can not sign across two buffers yet */ |
873 | if((experimEnabled) && ((pTcon->ses->server->secMode & | 872 | if((pTcon->ses->server->secMode & |
874 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0)) { | 873 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0) { |
875 | struct kvec iov[2]; | 874 | struct kvec iov[2]; |
876 | unsigned int len; | 875 | unsigned int len; |
877 | 876 | ||
@@ -887,7 +886,6 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
887 | iov, 1, long_op); | 886 | iov, 1, long_op); |
888 | } else | 887 | } else |
889 | /* BB FIXME fixup indentation of line below */ | 888 | /* BB FIXME fixup indentation of line below */ |
890 | #endif | ||
891 | rc = CIFSSMBWrite(xid, pTcon, | 889 | rc = CIFSSMBWrite(xid, pTcon, |
892 | open_file->netfid, | 890 | open_file->netfid, |
893 | min_t(const int, cifs_sb->wsize, | 891 | min_t(const int, cifs_sb->wsize, |
@@ -1024,7 +1022,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
1024 | return rc; | 1022 | return rc; |
1025 | } | 1023 | } |
1026 | 1024 | ||
1027 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
1028 | static int cifs_writepages(struct address_space *mapping, | 1025 | static int cifs_writepages(struct address_space *mapping, |
1029 | struct writeback_control *wbc) | 1026 | struct writeback_control *wbc) |
1030 | { | 1027 | { |
@@ -1227,7 +1224,6 @@ retry: | |||
1227 | 1224 | ||
1228 | return rc; | 1225 | return rc; |
1229 | } | 1226 | } |
1230 | #endif | ||
1231 | 1227 | ||
1232 | static int cifs_writepage(struct page* page, struct writeback_control *wbc) | 1228 | static int cifs_writepage(struct page* page, struct writeback_control *wbc) |
1233 | { | 1229 | { |
@@ -1426,6 +1422,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
1426 | rc = -EAGAIN; | 1422 | rc = -EAGAIN; |
1427 | smb_read_data = NULL; | 1423 | smb_read_data = NULL; |
1428 | while (rc == -EAGAIN) { | 1424 | while (rc == -EAGAIN) { |
1425 | int buf_type = CIFS_NO_BUFFER; | ||
1429 | if ((open_file->invalidHandle) && | 1426 | if ((open_file->invalidHandle) && |
1430 | (!open_file->closePend)) { | 1427 | (!open_file->closePend)) { |
1431 | rc = cifs_reopen_file(file->f_dentry->d_inode, | 1428 | rc = cifs_reopen_file(file->f_dentry->d_inode, |
@@ -1434,20 +1431,22 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
1434 | break; | 1431 | break; |
1435 | } | 1432 | } |
1436 | rc = CIFSSMBRead(xid, pTcon, | 1433 | rc = CIFSSMBRead(xid, pTcon, |
1437 | open_file->netfid, | 1434 | open_file->netfid, |
1438 | current_read_size, *poffset, | 1435 | current_read_size, *poffset, |
1439 | &bytes_read, &smb_read_data); | 1436 | &bytes_read, &smb_read_data, |
1437 | &buf_type); | ||
1440 | pSMBr = (struct smb_com_read_rsp *)smb_read_data; | 1438 | pSMBr = (struct smb_com_read_rsp *)smb_read_data; |
1441 | if (copy_to_user(current_offset, | 1439 | if (copy_to_user(current_offset, |
1442 | smb_read_data + 4 /* RFC1001 hdr */ | 1440 | smb_read_data + 4 /* RFC1001 hdr */ |
1443 | + le16_to_cpu(pSMBr->DataOffset), | 1441 | + le16_to_cpu(pSMBr->DataOffset), |
1444 | bytes_read)) { | 1442 | bytes_read)) { |
1445 | rc = -EFAULT; | 1443 | rc = -EFAULT; |
1446 | FreeXid(xid); | 1444 | } |
1447 | return rc; | ||
1448 | } | ||
1449 | if (smb_read_data) { | 1445 | if (smb_read_data) { |
1450 | cifs_buf_release(smb_read_data); | 1446 | if(buf_type == CIFS_SMALL_BUFFER) |
1447 | cifs_small_buf_release(smb_read_data); | ||
1448 | else if(buf_type == CIFS_LARGE_BUFFER) | ||
1449 | cifs_buf_release(smb_read_data); | ||
1451 | smb_read_data = NULL; | 1450 | smb_read_data = NULL; |
1452 | } | 1451 | } |
1453 | } | 1452 | } |
@@ -1480,6 +1479,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1480 | int xid; | 1479 | int xid; |
1481 | char *current_offset; | 1480 | char *current_offset; |
1482 | struct cifsFileInfo *open_file; | 1481 | struct cifsFileInfo *open_file; |
1482 | int buf_type = CIFS_NO_BUFFER; | ||
1483 | 1483 | ||
1484 | xid = GetXid(); | 1484 | xid = GetXid(); |
1485 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | 1485 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); |
@@ -1516,9 +1516,10 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
1516 | break; | 1516 | break; |
1517 | } | 1517 | } |
1518 | rc = CIFSSMBRead(xid, pTcon, | 1518 | rc = CIFSSMBRead(xid, pTcon, |
1519 | open_file->netfid, | 1519 | open_file->netfid, |
1520 | current_read_size, *poffset, | 1520 | current_read_size, *poffset, |
1521 | &bytes_read, ¤t_offset); | 1521 | &bytes_read, ¤t_offset, |
1522 | &buf_type); | ||
1522 | } | 1523 | } |
1523 | if (rc || (bytes_read == 0)) { | 1524 | if (rc || (bytes_read == 0)) { |
1524 | if (total_read) { | 1525 | if (total_read) { |
@@ -1616,6 +1617,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1616 | struct smb_com_read_rsp *pSMBr; | 1617 | struct smb_com_read_rsp *pSMBr; |
1617 | struct pagevec lru_pvec; | 1618 | struct pagevec lru_pvec; |
1618 | struct cifsFileInfo *open_file; | 1619 | struct cifsFileInfo *open_file; |
1620 | int buf_type = CIFS_NO_BUFFER; | ||
1619 | 1621 | ||
1620 | xid = GetXid(); | 1622 | xid = GetXid(); |
1621 | if (file->private_data == NULL) { | 1623 | if (file->private_data == NULL) { |
@@ -1672,14 +1674,17 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1672 | } | 1674 | } |
1673 | 1675 | ||
1674 | rc = CIFSSMBRead(xid, pTcon, | 1676 | rc = CIFSSMBRead(xid, pTcon, |
1675 | open_file->netfid, | 1677 | open_file->netfid, |
1676 | read_size, offset, | 1678 | read_size, offset, |
1677 | &bytes_read, &smb_read_data); | 1679 | &bytes_read, &smb_read_data, |
1678 | 1680 | &buf_type); | |
1679 | /* BB more RC checks ? */ | 1681 | /* BB more RC checks ? */ |
1680 | if (rc== -EAGAIN) { | 1682 | if (rc== -EAGAIN) { |
1681 | if (smb_read_data) { | 1683 | if (smb_read_data) { |
1682 | cifs_buf_release(smb_read_data); | 1684 | if(buf_type == CIFS_SMALL_BUFFER) |
1685 | cifs_small_buf_release(smb_read_data); | ||
1686 | else if(buf_type == CIFS_LARGE_BUFFER) | ||
1687 | cifs_buf_release(smb_read_data); | ||
1683 | smb_read_data = NULL; | 1688 | smb_read_data = NULL; |
1684 | } | 1689 | } |
1685 | } | 1690 | } |
@@ -1736,7 +1741,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1736 | break; | 1741 | break; |
1737 | } | 1742 | } |
1738 | if (smb_read_data) { | 1743 | if (smb_read_data) { |
1739 | cifs_buf_release(smb_read_data); | 1744 | if(buf_type == CIFS_SMALL_BUFFER) |
1745 | cifs_small_buf_release(smb_read_data); | ||
1746 | else if(buf_type == CIFS_LARGE_BUFFER) | ||
1747 | cifs_buf_release(smb_read_data); | ||
1740 | smb_read_data = NULL; | 1748 | smb_read_data = NULL; |
1741 | } | 1749 | } |
1742 | bytes_read = 0; | 1750 | bytes_read = 0; |
@@ -1746,7 +1754,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1746 | 1754 | ||
1747 | /* need to free smb_read_data buf before exit */ | 1755 | /* need to free smb_read_data buf before exit */ |
1748 | if (smb_read_data) { | 1756 | if (smb_read_data) { |
1749 | cifs_buf_release(smb_read_data); | 1757 | if(buf_type == CIFS_SMALL_BUFFER) |
1758 | cifs_small_buf_release(smb_read_data); | ||
1759 | else if(buf_type == CIFS_LARGE_BUFFER) | ||
1760 | cifs_buf_release(smb_read_data); | ||
1750 | smb_read_data = NULL; | 1761 | smb_read_data = NULL; |
1751 | } | 1762 | } |
1752 | 1763 | ||
@@ -1825,10 +1836,20 @@ int is_size_safe_to_change(struct cifsInodeInfo *cifsInode) | |||
1825 | open_file = find_writable_file(cifsInode); | 1836 | open_file = find_writable_file(cifsInode); |
1826 | 1837 | ||
1827 | if(open_file) { | 1838 | if(open_file) { |
1839 | struct cifs_sb_info *cifs_sb; | ||
1840 | |||
1828 | /* there is not actually a write pending so let | 1841 | /* there is not actually a write pending so let |
1829 | this handle go free and allow it to | 1842 | this handle go free and allow it to |
1830 | be closable if needed */ | 1843 | be closable if needed */ |
1831 | atomic_dec(&open_file->wrtPending); | 1844 | atomic_dec(&open_file->wrtPending); |
1845 | |||
1846 | cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb); | ||
1847 | if ( cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO ) { | ||
1848 | /* since no page cache to corrupt on directio | ||
1849 | we can change size safely */ | ||
1850 | return 1; | ||
1851 | } | ||
1852 | |||
1832 | return 0; | 1853 | return 0; |
1833 | } else | 1854 | } else |
1834 | return 1; | 1855 | return 1; |
@@ -1873,9 +1894,7 @@ struct address_space_operations cifs_addr_ops = { | |||
1873 | .readpage = cifs_readpage, | 1894 | .readpage = cifs_readpage, |
1874 | .readpages = cifs_readpages, | 1895 | .readpages = cifs_readpages, |
1875 | .writepage = cifs_writepage, | 1896 | .writepage = cifs_writepage, |
1876 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
1877 | .writepages = cifs_writepages, | 1897 | .writepages = cifs_writepages, |
1878 | #endif | ||
1879 | .prepare_write = cifs_prepare_write, | 1898 | .prepare_write = cifs_prepare_write, |
1880 | .commit_write = cifs_commit_write, | 1899 | .commit_write = cifs_commit_write, |
1881 | .set_page_dirty = __set_page_dirty_nobuffers, | 1900 | .set_page_dirty = __set_page_dirty_nobuffers, |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 3ebce9430f4a..59359911f481 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -229,11 +229,12 @@ static int decode_sfu_inode(struct inode * inode, __u64 size, | |||
229 | cifs_sb->mnt_cifs_flags & | 229 | cifs_sb->mnt_cifs_flags & |
230 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 230 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
231 | if (rc==0) { | 231 | if (rc==0) { |
232 | int buf_type = CIFS_NO_BUFFER; | ||
232 | /* Read header */ | 233 | /* Read header */ |
233 | rc = CIFSSMBRead(xid, pTcon, | 234 | rc = CIFSSMBRead(xid, pTcon, |
234 | netfid, | 235 | netfid, |
235 | 24 /* length */, 0 /* offset */, | 236 | 24 /* length */, 0 /* offset */, |
236 | &bytes_read, &pbuf); | 237 | &bytes_read, &pbuf, &buf_type); |
237 | if((rc == 0) && (bytes_read >= 8)) { | 238 | if((rc == 0) && (bytes_read >= 8)) { |
238 | if(memcmp("IntxBLK", pbuf, 8) == 0) { | 239 | if(memcmp("IntxBLK", pbuf, 8) == 0) { |
239 | cFYI(1,("Block device")); | 240 | cFYI(1,("Block device")); |
@@ -267,7 +268,7 @@ static int decode_sfu_inode(struct inode * inode, __u64 size, | |||
267 | } else { | 268 | } else { |
268 | inode->i_mode |= S_IFREG; /* then it is a file */ | 269 | inode->i_mode |= S_IFREG; /* then it is a file */ |
269 | rc = -EOPNOTSUPP; /* or some unknown SFU type */ | 270 | rc = -EOPNOTSUPP; /* or some unknown SFU type */ |
270 | } | 271 | } |
271 | CIFSSMBClose(xid, pTcon, netfid); | 272 | CIFSSMBClose(xid, pTcon, netfid); |
272 | } | 273 | } |
273 | return rc; | 274 | return rc; |
@@ -750,8 +751,8 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
750 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | 751 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { |
751 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, | 752 | CIFSSMBUnixSetPerms(xid, pTcon, full_path, |
752 | mode, | 753 | mode, |
753 | (__u64)current->euid, | 754 | (__u64)current->fsuid, |
754 | (__u64)current->egid, | 755 | (__u64)current->fsgid, |
755 | 0 /* dev_t */, | 756 | 0 /* dev_t */, |
756 | cifs_sb->local_nls, | 757 | cifs_sb->local_nls, |
757 | cifs_sb->mnt_cifs_flags & | 758 | cifs_sb->mnt_cifs_flags & |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 94baf6c8ecbd..812c6bb0fe38 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * fs/cifs/misc.c | 2 | * fs/cifs/misc.c |
3 | * | 3 | * |
4 | * Copyright (C) International Business Machines Corp., 2002,2004 | 4 | * Copyright (C) International Business Machines Corp., 2002,2005 |
5 | * Author(s): Steve French (sfrench@us.ibm.com) | 5 | * Author(s): Steve French (sfrench@us.ibm.com) |
6 | * | 6 | * |
7 | * This library is free software; you can redistribute it and/or modify | 7 | * This library is free software; you can redistribute it and/or modify |
@@ -161,6 +161,9 @@ cifs_buf_get(void) | |||
161 | if (ret_buf) { | 161 | if (ret_buf) { |
162 | memset(ret_buf, 0, sizeof(struct smb_hdr) + 3); | 162 | memset(ret_buf, 0, sizeof(struct smb_hdr) + 3); |
163 | atomic_inc(&bufAllocCount); | 163 | atomic_inc(&bufAllocCount); |
164 | #ifdef CONFIG_CIFS_STATS2 | ||
165 | atomic_inc(&totBufAllocCount); | ||
166 | #endif /* CONFIG_CIFS_STATS2 */ | ||
164 | } | 167 | } |
165 | 168 | ||
166 | return ret_buf; | 169 | return ret_buf; |
@@ -195,6 +198,10 @@ cifs_small_buf_get(void) | |||
195 | /* No need to clear memory here, cleared in header assemble */ | 198 | /* No need to clear memory here, cleared in header assemble */ |
196 | /* memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/ | 199 | /* memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/ |
197 | atomic_inc(&smBufAllocCount); | 200 | atomic_inc(&smBufAllocCount); |
201 | #ifdef CONFIG_CIFS_STATS2 | ||
202 | atomic_inc(&totSmBufAllocCount); | ||
203 | #endif /* CONFIG_CIFS_STATS2 */ | ||
204 | |||
198 | } | 205 | } |
199 | return ret_buf; | 206 | return ret_buf; |
200 | } | 207 | } |
@@ -292,7 +299,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
292 | struct cifsSesInfo * ses; | 299 | struct cifsSesInfo * ses; |
293 | char *temp = (char *) buffer; | 300 | char *temp = (char *) buffer; |
294 | 301 | ||
295 | memset(temp,0,MAX_CIFS_HDR_SIZE); | 302 | memset(temp,0,256); /* bigger than MAX_CIFS_HDR_SIZE */ |
296 | 303 | ||
297 | buffer->smb_buf_length = | 304 | buffer->smb_buf_length = |
298 | (2 * word_count) + sizeof (struct smb_hdr) - | 305 | (2 * word_count) + sizeof (struct smb_hdr) - |
@@ -348,12 +355,12 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
348 | /* BB Add support for establishing new tCon and SMB Session */ | 355 | /* BB Add support for establishing new tCon and SMB Session */ |
349 | /* with userid/password pairs found on the smb session */ | 356 | /* with userid/password pairs found on the smb session */ |
350 | /* for other target tcp/ip addresses BB */ | 357 | /* for other target tcp/ip addresses BB */ |
351 | if(current->uid != treeCon->ses->linux_uid) { | 358 | if(current->fsuid != treeCon->ses->linux_uid) { |
352 | cFYI(1,("Multiuser mode and UID did not match tcon uid ")); | 359 | cFYI(1,("Multiuser mode and UID did not match tcon uid")); |
353 | read_lock(&GlobalSMBSeslock); | 360 | read_lock(&GlobalSMBSeslock); |
354 | list_for_each(temp_item, &GlobalSMBSessionList) { | 361 | list_for_each(temp_item, &GlobalSMBSessionList) { |
355 | ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList); | 362 | ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList); |
356 | if(ses->linux_uid == current->uid) { | 363 | if(ses->linux_uid == current->fsuid) { |
357 | if(ses->server == treeCon->ses->server) { | 364 | if(ses->server == treeCon->ses->server) { |
358 | cFYI(1,("found matching uid substitute right smb_uid")); | 365 | cFYI(1,("found matching uid substitute right smb_uid")); |
359 | buffer->Uid = ses->Suid; | 366 | buffer->Uid = ses->Suid; |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 9bdaaecae36f..288cc048d37f 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -214,8 +214,7 @@ static void fill_in_inode(struct inode *tmp_inode, | |||
214 | tmp_inode->i_fop = &cifs_file_nobrl_ops; | 214 | tmp_inode->i_fop = &cifs_file_nobrl_ops; |
215 | else | 215 | else |
216 | tmp_inode->i_fop = &cifs_file_ops; | 216 | tmp_inode->i_fop = &cifs_file_ops; |
217 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | 217 | |
218 | tmp_inode->i_fop->lock = NULL; | ||
219 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | 218 | tmp_inode->i_data.a_ops = &cifs_addr_ops; |
220 | if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && | 219 | if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && |
221 | (cifs_sb->tcon->ses->server->maxBuf < | 220 | (cifs_sb->tcon->ses->server->maxBuf < |
@@ -327,12 +326,18 @@ static void unix_fill_in_inode(struct inode *tmp_inode, | |||
327 | if (S_ISREG(tmp_inode->i_mode)) { | 326 | if (S_ISREG(tmp_inode->i_mode)) { |
328 | cFYI(1, ("File inode")); | 327 | cFYI(1, ("File inode")); |
329 | tmp_inode->i_op = &cifs_file_inode_ops; | 328 | tmp_inode->i_op = &cifs_file_inode_ops; |
330 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) | 329 | |
331 | tmp_inode->i_fop = &cifs_file_direct_ops; | 330 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { |
331 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
332 | tmp_inode->i_fop = &cifs_file_direct_nobrl_ops; | ||
333 | else | ||
334 | tmp_inode->i_fop = &cifs_file_direct_ops; | ||
335 | |||
336 | } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
337 | tmp_inode->i_fop = &cifs_file_nobrl_ops; | ||
332 | else | 338 | else |
333 | tmp_inode->i_fop = &cifs_file_ops; | 339 | tmp_inode->i_fop = &cifs_file_ops; |
334 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | 340 | |
335 | tmp_inode->i_fop->lock = NULL; | ||
336 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | 341 | tmp_inode->i_data.a_ops = &cifs_addr_ops; |
337 | if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && | 342 | if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && |
338 | (cifs_sb->tcon->ses->server->maxBuf < | 343 | (cifs_sb->tcon->ses->server->maxBuf < |
diff --git a/fs/cifs/rfc1002pdu.h b/fs/cifs/rfc1002pdu.h index 9222033cad8e..aede606132aa 100644 --- a/fs/cifs/rfc1002pdu.h +++ b/fs/cifs/rfc1002pdu.h | |||
@@ -24,11 +24,11 @@ | |||
24 | /* NB: unlike smb/cifs packets, the RFC1002 structures are big endian */ | 24 | /* NB: unlike smb/cifs packets, the RFC1002 structures are big endian */ |
25 | 25 | ||
26 | /* RFC 1002 session packet types */ | 26 | /* RFC 1002 session packet types */ |
27 | #define RFC1002_SESSION_MESASAGE 0x00 | 27 | #define RFC1002_SESSION_MESSAGE 0x00 |
28 | #define RFC1002_SESSION_REQUEST 0x81 | 28 | #define RFC1002_SESSION_REQUEST 0x81 |
29 | #define RFC1002_POSITIVE_SESSION_RESPONSE 0x82 | 29 | #define RFC1002_POSITIVE_SESSION_RESPONSE 0x82 |
30 | #define RFC1002_NEGATIVE_SESSION_RESPONSE 0x83 | 30 | #define RFC1002_NEGATIVE_SESSION_RESPONSE 0x83 |
31 | #define RFC1002_RETARGET_SESSION_RESPONSE 0x83 | 31 | #define RFC1002_RETARGET_SESSION_RESPONSE 0x84 |
32 | #define RFC1002_SESSION_KEEP_ALIVE 0x85 | 32 | #define RFC1002_SESSION_KEEP_ALIVE 0x85 |
33 | 33 | ||
34 | /* RFC 1002 flags (only one defined */ | 34 | /* RFC 1002 flags (only one defined */ |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index f8871196098c..7b98792150ea 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -206,7 +206,6 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
206 | return rc; | 206 | return rc; |
207 | } | 207 | } |
208 | 208 | ||
209 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
210 | static int | 209 | static int |
211 | smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, | 210 | smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, |
212 | struct sockaddr *sin) | 211 | struct sockaddr *sin) |
@@ -299,7 +298,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, | |||
299 | 298 | ||
300 | int | 299 | int |
301 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | 300 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, |
302 | struct kvec *iov, int n_vec, int *pbytes_returned, | 301 | struct kvec *iov, int n_vec, int * pRespBufType /* ret */, |
303 | const int long_op) | 302 | const int long_op) |
304 | { | 303 | { |
305 | int rc = 0; | 304 | int rc = 0; |
@@ -307,6 +306,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
307 | unsigned long timeout; | 306 | unsigned long timeout; |
308 | struct mid_q_entry *midQ; | 307 | struct mid_q_entry *midQ; |
309 | struct smb_hdr *in_buf = iov[0].iov_base; | 308 | struct smb_hdr *in_buf = iov[0].iov_base; |
309 | |||
310 | *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */ | ||
310 | 311 | ||
311 | if (ses == NULL) { | 312 | if (ses == NULL) { |
312 | cERROR(1,("Null smb session")); | 313 | cERROR(1,("Null smb session")); |
@@ -392,8 +393,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
392 | return -ENOMEM; | 393 | return -ENOMEM; |
393 | } | 394 | } |
394 | 395 | ||
395 | /* BB FIXME */ | 396 | rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); |
396 | /* rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); */ | ||
397 | 397 | ||
398 | midQ->midState = MID_REQUEST_SUBMITTED; | 398 | midQ->midState = MID_REQUEST_SUBMITTED; |
399 | #ifdef CONFIG_CIFS_STATS2 | 399 | #ifdef CONFIG_CIFS_STATS2 |
@@ -489,21 +489,23 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
489 | receive_len, xid)); | 489 | receive_len, xid)); |
490 | rc = -EIO; | 490 | rc = -EIO; |
491 | } else { /* rcvd frame is ok */ | 491 | } else { /* rcvd frame is ok */ |
492 | |||
493 | if (midQ->resp_buf && | 492 | if (midQ->resp_buf && |
494 | (midQ->midState == MID_RESPONSE_RECEIVED)) { | 493 | (midQ->midState == MID_RESPONSE_RECEIVED)) { |
495 | in_buf->smb_buf_length = receive_len; | ||
496 | /* BB verify that length would not overrun small buf */ | ||
497 | memcpy((char *)in_buf + 4, | ||
498 | (char *)midQ->resp_buf + 4, | ||
499 | receive_len); | ||
500 | 494 | ||
501 | dump_smb(in_buf, 80); | 495 | iov[0].iov_base = (char *)midQ->resp_buf; |
496 | if(midQ->largeBuf) | ||
497 | *pRespBufType = CIFS_LARGE_BUFFER; | ||
498 | else | ||
499 | *pRespBufType = CIFS_SMALL_BUFFER; | ||
500 | iov[0].iov_len = receive_len + 4; | ||
501 | iov[1].iov_len = 0; | ||
502 | |||
503 | dump_smb(midQ->resp_buf, 80); | ||
502 | /* convert the length into a more usable form */ | 504 | /* convert the length into a more usable form */ |
503 | if((receive_len > 24) && | 505 | if((receive_len > 24) && |
504 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | 506 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | |
505 | SECMODE_SIGN_ENABLED))) { | 507 | SECMODE_SIGN_ENABLED))) { |
506 | rc = cifs_verify_signature(in_buf, | 508 | rc = cifs_verify_signature(midQ->resp_buf, |
507 | ses->server->mac_signing_key, | 509 | ses->server->mac_signing_key, |
508 | midQ->sequence_number+1); | 510 | midQ->sequence_number+1); |
509 | if(rc) { | 511 | if(rc) { |
@@ -512,18 +514,19 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
512 | } | 514 | } |
513 | } | 515 | } |
514 | 516 | ||
515 | *pbytes_returned = in_buf->smb_buf_length; | ||
516 | |||
517 | /* BB special case reconnect tid and uid here? */ | 517 | /* BB special case reconnect tid and uid here? */ |
518 | /* BB special case Errbadpassword and pwdexpired here */ | 518 | /* BB special case Errbadpassword and pwdexpired here */ |
519 | rc = map_smb_to_linux_error(in_buf); | 519 | rc = map_smb_to_linux_error(midQ->resp_buf); |
520 | 520 | ||
521 | /* convert ByteCount if necessary */ | 521 | /* convert ByteCount if necessary */ |
522 | if (receive_len >= | 522 | if (receive_len >= |
523 | sizeof (struct smb_hdr) - | 523 | sizeof (struct smb_hdr) - |
524 | 4 /* do not count RFC1001 header */ + | 524 | 4 /* do not count RFC1001 header */ + |
525 | (2 * in_buf->WordCount) + 2 /* bcc */ ) | 525 | (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) |
526 | BCC(in_buf) = le16_to_cpu(BCC_LE(in_buf)); | 526 | BCC(midQ->resp_buf) = |
527 | le16_to_cpu(BCC_LE(midQ->resp_buf)); | ||
528 | midQ->resp_buf = NULL; /* mark it so will not be freed | ||
529 | by DeleteMidQEntry */ | ||
527 | } else { | 530 | } else { |
528 | rc = -EIO; | 531 | rc = -EIO; |
529 | cFYI(1,("Bad MID state?")); | 532 | cFYI(1,("Bad MID state?")); |
@@ -549,7 +552,6 @@ out_unlock2: | |||
549 | 552 | ||
550 | return rc; | 553 | return rc; |
551 | } | 554 | } |
552 | #endif /* CIFS_EXPERIMENTAL */ | ||
553 | 555 | ||
554 | int | 556 | int |
555 | SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | 557 | SendReceive(const unsigned int xid, struct cifsSesInfo *ses, |
@@ -790,7 +792,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
790 | BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); | 792 | BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); |
791 | } else { | 793 | } else { |
792 | rc = -EIO; | 794 | rc = -EIO; |
793 | cERROR(1,("Bad MID state? ")); | 795 | cERROR(1,("Bad MID state?")); |
794 | } | 796 | } |
795 | } | 797 | } |
796 | cifs_no_response_exit: | 798 | cifs_no_response_exit: |
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index f375f87c7dbd..777e3363c2a4 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c | |||
@@ -254,7 +254,8 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name, | |||
254 | rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value, | 254 | rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value, |
255 | buf_size, cifs_sb->local_nls, | 255 | buf_size, cifs_sb->local_nls, |
256 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 256 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
257 | } else if(strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,strlen(POSIX_ACL_XATTR_ACCESS)) == 0) { | 257 | } else if(strncmp(ea_name,POSIX_ACL_XATTR_ACCESS, |
258 | strlen(POSIX_ACL_XATTR_ACCESS)) == 0) { | ||
258 | #ifdef CONFIG_CIFS_POSIX | 259 | #ifdef CONFIG_CIFS_POSIX |
259 | if(sb->s_flags & MS_POSIXACL) | 260 | if(sb->s_flags & MS_POSIXACL) |
260 | rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, | 261 | rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, |
@@ -262,10 +263,27 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name, | |||
262 | cifs_sb->local_nls, | 263 | cifs_sb->local_nls, |
263 | cifs_sb->mnt_cifs_flags & | 264 | cifs_sb->mnt_cifs_flags & |
264 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 265 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
266 | /* else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { | ||
267 | __u16 fid; | ||
268 | int oplock = FALSE; | ||
269 | rc = CIFSSMBOpen(xid, pTcon, full_path, | ||
270 | FILE_OPEN, GENERIC_READ, 0, &fid, | ||
271 | &oplock, NULL, cifs_sb->local_nls, | ||
272 | cifs_sb->mnt_cifs_flags & | ||
273 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
274 | if(rc == 0) { | ||
275 | rc = CIFSSMBGetCIFSACL(xid, pTcon, fid, | ||
276 | ea_value, buf_size, | ||
277 | ACL_TYPE_ACCESS); | ||
278 | CIFSSMBClose(xid, pTcon, fid) | ||
279 | } | ||
280 | } */ /* BB enable after fixing up return data */ | ||
281 | |||
265 | #else | 282 | #else |
266 | cFYI(1,("query POSIX ACL not supported yet")); | 283 | cFYI(1,("query POSIX ACL not supported yet")); |
267 | #endif /* CONFIG_CIFS_POSIX */ | 284 | #endif /* CONFIG_CIFS_POSIX */ |
268 | } else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { | 285 | } else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT, |
286 | strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { | ||
269 | #ifdef CONFIG_CIFS_POSIX | 287 | #ifdef CONFIG_CIFS_POSIX |
270 | if(sb->s_flags & MS_POSIXACL) | 288 | if(sb->s_flags & MS_POSIXACL) |
271 | rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, | 289 | rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, |
diff --git a/fs/compat.c b/fs/compat.c index 2468ac1df2f0..ff0bafcff720 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
@@ -53,6 +53,8 @@ | |||
53 | #include <asm/mmu_context.h> | 53 | #include <asm/mmu_context.h> |
54 | #include <asm/ioctls.h> | 54 | #include <asm/ioctls.h> |
55 | 55 | ||
56 | extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat); | ||
57 | |||
56 | /* | 58 | /* |
57 | * Not all architectures have sys_utime, so implement this in terms | 59 | * Not all architectures have sys_utime, so implement this in terms |
58 | * of sys_utimes. | 60 | * of sys_utimes. |
@@ -68,10 +70,10 @@ asmlinkage long compat_sys_utime(char __user *filename, struct compat_utimbuf __ | |||
68 | tv[0].tv_usec = 0; | 70 | tv[0].tv_usec = 0; |
69 | tv[1].tv_usec = 0; | 71 | tv[1].tv_usec = 0; |
70 | } | 72 | } |
71 | return do_utimes(filename, t ? tv : NULL); | 73 | return do_utimes(AT_FDCWD, filename, t ? tv : NULL); |
72 | } | 74 | } |
73 | 75 | ||
74 | asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval __user *t) | 76 | asmlinkage long compat_sys_futimesat(int dfd, char __user *filename, struct compat_timeval __user *t) |
75 | { | 77 | { |
76 | struct timeval tv[2]; | 78 | struct timeval tv[2]; |
77 | 79 | ||
@@ -82,14 +84,19 @@ asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval _ | |||
82 | get_user(tv[1].tv_usec, &t[1].tv_usec)) | 84 | get_user(tv[1].tv_usec, &t[1].tv_usec)) |
83 | return -EFAULT; | 85 | return -EFAULT; |
84 | } | 86 | } |
85 | return do_utimes(filename, t ? tv : NULL); | 87 | return do_utimes(dfd, filename, t ? tv : NULL); |
88 | } | ||
89 | |||
90 | asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval __user *t) | ||
91 | { | ||
92 | return compat_sys_futimesat(AT_FDCWD, filename, t); | ||
86 | } | 93 | } |
87 | 94 | ||
88 | asmlinkage long compat_sys_newstat(char __user * filename, | 95 | asmlinkage long compat_sys_newstat(char __user * filename, |
89 | struct compat_stat __user *statbuf) | 96 | struct compat_stat __user *statbuf) |
90 | { | 97 | { |
91 | struct kstat stat; | 98 | struct kstat stat; |
92 | int error = vfs_stat(filename, &stat); | 99 | int error = vfs_stat_fd(AT_FDCWD, filename, &stat); |
93 | 100 | ||
94 | if (!error) | 101 | if (!error) |
95 | error = cp_compat_stat(&stat, statbuf); | 102 | error = cp_compat_stat(&stat, statbuf); |
@@ -100,10 +107,31 @@ asmlinkage long compat_sys_newlstat(char __user * filename, | |||
100 | struct compat_stat __user *statbuf) | 107 | struct compat_stat __user *statbuf) |
101 | { | 108 | { |
102 | struct kstat stat; | 109 | struct kstat stat; |
103 | int error = vfs_lstat(filename, &stat); | 110 | int error = vfs_lstat_fd(AT_FDCWD, filename, &stat); |
111 | |||
112 | if (!error) | ||
113 | error = cp_compat_stat(&stat, statbuf); | ||
114 | return error; | ||
115 | } | ||
116 | |||
117 | asmlinkage long compat_sys_newfstatat(int dfd, char __user *filename, | ||
118 | struct compat_stat __user *statbuf, int flag) | ||
119 | { | ||
120 | struct kstat stat; | ||
121 | int error = -EINVAL; | ||
122 | |||
123 | if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0) | ||
124 | goto out; | ||
125 | |||
126 | if (flag & AT_SYMLINK_NOFOLLOW) | ||
127 | error = vfs_lstat_fd(dfd, filename, &stat); | ||
128 | else | ||
129 | error = vfs_stat_fd(dfd, filename, &stat); | ||
104 | 130 | ||
105 | if (!error) | 131 | if (!error) |
106 | error = cp_compat_stat(&stat, statbuf); | 132 | error = cp_compat_stat(&stat, statbuf); |
133 | |||
134 | out: | ||
107 | return error; | 135 | return error; |
108 | } | 136 | } |
109 | 137 | ||
@@ -1290,7 +1318,17 @@ out: | |||
1290 | asmlinkage long | 1318 | asmlinkage long |
1291 | compat_sys_open(const char __user *filename, int flags, int mode) | 1319 | compat_sys_open(const char __user *filename, int flags, int mode) |
1292 | { | 1320 | { |
1293 | return do_sys_open(filename, flags, mode); | 1321 | return do_sys_open(AT_FDCWD, filename, flags, mode); |
1322 | } | ||
1323 | |||
1324 | /* | ||
1325 | * Exactly like fs/open.c:sys_openat(), except that it doesn't set the | ||
1326 | * O_LARGEFILE flag. | ||
1327 | */ | ||
1328 | asmlinkage long | ||
1329 | compat_sys_openat(int dfd, const char __user *filename, int flags, int mode) | ||
1330 | { | ||
1331 | return do_sys_open(dfd, filename, flags, mode); | ||
1294 | } | 1332 | } |
1295 | 1333 | ||
1296 | /* | 1334 | /* |
@@ -1621,36 +1659,14 @@ static void select_bits_free(void *bits, int size) | |||
1621 | #define MAX_SELECT_SECONDS \ | 1659 | #define MAX_SELECT_SECONDS \ |
1622 | ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) | 1660 | ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) |
1623 | 1661 | ||
1624 | asmlinkage long | 1662 | int compat_core_sys_select(int n, compat_ulong_t __user *inp, |
1625 | compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp, | 1663 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, s64 *timeout) |
1626 | compat_ulong_t __user *exp, struct compat_timeval __user *tvp) | ||
1627 | { | 1664 | { |
1628 | fd_set_bits fds; | 1665 | fd_set_bits fds; |
1629 | char *bits; | 1666 | char *bits; |
1630 | long timeout; | ||
1631 | int size, max_fdset, ret = -EINVAL; | 1667 | int size, max_fdset, ret = -EINVAL; |
1632 | struct fdtable *fdt; | 1668 | struct fdtable *fdt; |
1633 | 1669 | ||
1634 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
1635 | if (tvp) { | ||
1636 | time_t sec, usec; | ||
1637 | |||
1638 | if (!access_ok(VERIFY_READ, tvp, sizeof(*tvp)) | ||
1639 | || __get_user(sec, &tvp->tv_sec) | ||
1640 | || __get_user(usec, &tvp->tv_usec)) { | ||
1641 | ret = -EFAULT; | ||
1642 | goto out_nofds; | ||
1643 | } | ||
1644 | |||
1645 | if (sec < 0 || usec < 0) | ||
1646 | goto out_nofds; | ||
1647 | |||
1648 | if ((unsigned long) sec < MAX_SELECT_SECONDS) { | ||
1649 | timeout = ROUND_UP(usec, 1000000/HZ); | ||
1650 | timeout += sec * (unsigned long) HZ; | ||
1651 | } | ||
1652 | } | ||
1653 | |||
1654 | if (n < 0) | 1670 | if (n < 0) |
1655 | goto out_nofds; | 1671 | goto out_nofds; |
1656 | 1672 | ||
@@ -1687,19 +1703,7 @@ compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp | |||
1687 | zero_fd_set(n, fds.res_out); | 1703 | zero_fd_set(n, fds.res_out); |
1688 | zero_fd_set(n, fds.res_ex); | 1704 | zero_fd_set(n, fds.res_ex); |
1689 | 1705 | ||
1690 | ret = do_select(n, &fds, &timeout); | 1706 | ret = do_select(n, &fds, timeout); |
1691 | |||
1692 | if (tvp && !(current->personality & STICKY_TIMEOUTS)) { | ||
1693 | time_t sec = 0, usec = 0; | ||
1694 | if (timeout) { | ||
1695 | sec = timeout / HZ; | ||
1696 | usec = timeout % HZ; | ||
1697 | usec *= (1000000/HZ); | ||
1698 | } | ||
1699 | if (put_user(sec, &tvp->tv_sec) || | ||
1700 | put_user(usec, &tvp->tv_usec)) | ||
1701 | ret = -EFAULT; | ||
1702 | } | ||
1703 | 1707 | ||
1704 | if (ret < 0) | 1708 | if (ret < 0) |
1705 | goto out; | 1709 | goto out; |
@@ -1720,6 +1724,224 @@ out_nofds: | |||
1720 | return ret; | 1724 | return ret; |
1721 | } | 1725 | } |
1722 | 1726 | ||
1727 | asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp, | ||
1728 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, | ||
1729 | struct compat_timeval __user *tvp) | ||
1730 | { | ||
1731 | s64 timeout = -1; | ||
1732 | struct compat_timeval tv; | ||
1733 | int ret; | ||
1734 | |||
1735 | if (tvp) { | ||
1736 | if (copy_from_user(&tv, tvp, sizeof(tv))) | ||
1737 | return -EFAULT; | ||
1738 | |||
1739 | if (tv.tv_sec < 0 || tv.tv_usec < 0) | ||
1740 | return -EINVAL; | ||
1741 | |||
1742 | /* Cast to u64 to make GCC stop complaining */ | ||
1743 | if ((u64)tv.tv_sec >= (u64)MAX_INT64_SECONDS) | ||
1744 | timeout = -1; /* infinite */ | ||
1745 | else { | ||
1746 | timeout = ROUND_UP(tv.tv_usec, 1000000/HZ); | ||
1747 | timeout += tv.tv_sec * HZ; | ||
1748 | } | ||
1749 | } | ||
1750 | |||
1751 | ret = compat_core_sys_select(n, inp, outp, exp, &timeout); | ||
1752 | |||
1753 | if (tvp) { | ||
1754 | if (current->personality & STICKY_TIMEOUTS) | ||
1755 | goto sticky; | ||
1756 | tv.tv_usec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ)); | ||
1757 | tv.tv_sec = timeout; | ||
1758 | if (copy_to_user(tvp, &tv, sizeof(tv))) { | ||
1759 | sticky: | ||
1760 | /* | ||
1761 | * If an application puts its timeval in read-only | ||
1762 | * memory, we don't want the Linux-specific update to | ||
1763 | * the timeval to cause a fault after the select has | ||
1764 | * completed successfully. However, because we're not | ||
1765 | * updating the timeval, we can't restart the system | ||
1766 | * call. | ||
1767 | */ | ||
1768 | if (ret == -ERESTARTNOHAND) | ||
1769 | ret = -EINTR; | ||
1770 | } | ||
1771 | } | ||
1772 | |||
1773 | return ret; | ||
1774 | } | ||
1775 | |||
1776 | #ifdef TIF_RESTORE_SIGMASK | ||
1777 | asmlinkage long compat_sys_pselect7(int n, compat_ulong_t __user *inp, | ||
1778 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, | ||
1779 | struct compat_timespec __user *tsp, compat_sigset_t __user *sigmask, | ||
1780 | compat_size_t sigsetsize) | ||
1781 | { | ||
1782 | compat_sigset_t ss32; | ||
1783 | sigset_t ksigmask, sigsaved; | ||
1784 | long timeout = MAX_SCHEDULE_TIMEOUT; | ||
1785 | struct compat_timespec ts; | ||
1786 | int ret; | ||
1787 | |||
1788 | if (tsp) { | ||
1789 | if (copy_from_user(&ts, tsp, sizeof(ts))) | ||
1790 | return -EFAULT; | ||
1791 | |||
1792 | if (ts.tv_sec < 0 || ts.tv_nsec < 0) | ||
1793 | return -EINVAL; | ||
1794 | } | ||
1795 | |||
1796 | if (sigmask) { | ||
1797 | if (sigsetsize != sizeof(compat_sigset_t)) | ||
1798 | return -EINVAL; | ||
1799 | if (copy_from_user(&ss32, sigmask, sizeof(ss32))) | ||
1800 | return -EFAULT; | ||
1801 | sigset_from_compat(&ksigmask, &ss32); | ||
1802 | |||
1803 | sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); | ||
1804 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | ||
1805 | } | ||
1806 | |||
1807 | do { | ||
1808 | if (tsp) { | ||
1809 | if ((unsigned long)ts.tv_sec < MAX_SELECT_SECONDS) { | ||
1810 | timeout = ROUND_UP(ts.tv_nsec, 1000000000/HZ); | ||
1811 | timeout += ts.tv_sec * (unsigned long)HZ; | ||
1812 | ts.tv_sec = 0; | ||
1813 | ts.tv_nsec = 0; | ||
1814 | } else { | ||
1815 | ts.tv_sec -= MAX_SELECT_SECONDS; | ||
1816 | timeout = MAX_SELECT_SECONDS * HZ; | ||
1817 | } | ||
1818 | } | ||
1819 | |||
1820 | ret = compat_core_sys_select(n, inp, outp, exp, &timeout); | ||
1821 | |||
1822 | } while (!ret && !timeout && tsp && (ts.tv_sec || ts.tv_nsec)); | ||
1823 | |||
1824 | if (tsp && !(current->personality & STICKY_TIMEOUTS)) { | ||
1825 | ts.tv_sec += timeout / HZ; | ||
1826 | ts.tv_nsec += (timeout % HZ) * (1000000000/HZ); | ||
1827 | if (ts.tv_nsec >= 1000000000) { | ||
1828 | ts.tv_sec++; | ||
1829 | ts.tv_nsec -= 1000000000; | ||
1830 | } | ||
1831 | (void)copy_to_user(tsp, &ts, sizeof(ts)); | ||
1832 | } | ||
1833 | |||
1834 | if (ret == -ERESTARTNOHAND) { | ||
1835 | /* | ||
1836 | * Don't restore the signal mask yet. Let do_signal() deliver | ||
1837 | * the signal on the way back to userspace, before the signal | ||
1838 | * mask is restored. | ||
1839 | */ | ||
1840 | if (sigmask) { | ||
1841 | memcpy(¤t->saved_sigmask, &sigsaved, | ||
1842 | sizeof(sigsaved)); | ||
1843 | set_thread_flag(TIF_RESTORE_SIGMASK); | ||
1844 | } | ||
1845 | } else if (sigmask) | ||
1846 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
1847 | |||
1848 | return ret; | ||
1849 | } | ||
1850 | |||
1851 | asmlinkage long compat_sys_pselect6(int n, compat_ulong_t __user *inp, | ||
1852 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, | ||
1853 | struct compat_timespec __user *tsp, void __user *sig) | ||
1854 | { | ||
1855 | compat_size_t sigsetsize = 0; | ||
1856 | compat_uptr_t up = 0; | ||
1857 | |||
1858 | if (sig) { | ||
1859 | if (!access_ok(VERIFY_READ, sig, | ||
1860 | sizeof(compat_uptr_t)+sizeof(compat_size_t)) || | ||
1861 | __get_user(up, (compat_uptr_t __user *)sig) || | ||
1862 | __get_user(sigsetsize, | ||
1863 | (compat_size_t __user *)(sig+sizeof(up)))) | ||
1864 | return -EFAULT; | ||
1865 | } | ||
1866 | return compat_sys_pselect7(n, inp, outp, exp, tsp, compat_ptr(up), | ||
1867 | sigsetsize); | ||
1868 | } | ||
1869 | |||
1870 | asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds, | ||
1871 | unsigned int nfds, struct compat_timespec __user *tsp, | ||
1872 | const compat_sigset_t __user *sigmask, compat_size_t sigsetsize) | ||
1873 | { | ||
1874 | compat_sigset_t ss32; | ||
1875 | sigset_t ksigmask, sigsaved; | ||
1876 | struct compat_timespec ts; | ||
1877 | s64 timeout = -1; | ||
1878 | int ret; | ||
1879 | |||
1880 | if (tsp) { | ||
1881 | if (copy_from_user(&ts, tsp, sizeof(ts))) | ||
1882 | return -EFAULT; | ||
1883 | |||
1884 | /* We assume that ts.tv_sec is always lower than | ||
1885 | the number of seconds that can be expressed in | ||
1886 | an s64. Otherwise the compiler bitches at us */ | ||
1887 | timeout = ROUND_UP(ts.tv_nsec, 1000000000/HZ); | ||
1888 | timeout += ts.tv_sec * HZ; | ||
1889 | } | ||
1890 | |||
1891 | if (sigmask) { | ||
1892 | if (sigsetsize |= sizeof(compat_sigset_t)) | ||
1893 | return -EINVAL; | ||
1894 | if (copy_from_user(&ss32, sigmask, sizeof(ss32))) | ||
1895 | return -EFAULT; | ||
1896 | sigset_from_compat(&ksigmask, &ss32); | ||
1897 | |||
1898 | sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); | ||
1899 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | ||
1900 | } | ||
1901 | |||
1902 | ret = do_sys_poll(ufds, nfds, &timeout); | ||
1903 | |||
1904 | /* We can restart this syscall, usually */ | ||
1905 | if (ret == -EINTR) { | ||
1906 | /* | ||
1907 | * Don't restore the signal mask yet. Let do_signal() deliver | ||
1908 | * the signal on the way back to userspace, before the signal | ||
1909 | * mask is restored. | ||
1910 | */ | ||
1911 | if (sigmask) { | ||
1912 | memcpy(¤t->saved_sigmask, &sigsaved, | ||
1913 | sizeof(sigsaved)); | ||
1914 | set_thread_flag(TIF_RESTORE_SIGMASK); | ||
1915 | } | ||
1916 | ret = -ERESTARTNOHAND; | ||
1917 | } else if (sigmask) | ||
1918 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
1919 | |||
1920 | if (tsp && timeout >= 0) { | ||
1921 | if (current->personality & STICKY_TIMEOUTS) | ||
1922 | goto sticky; | ||
1923 | /* Yes, we know it's actually an s64, but it's also positive. */ | ||
1924 | ts.tv_nsec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ)) * 1000; | ||
1925 | ts.tv_sec = timeout; | ||
1926 | if (copy_to_user(tsp, &ts, sizeof(ts))) { | ||
1927 | sticky: | ||
1928 | /* | ||
1929 | * If an application puts its timeval in read-only | ||
1930 | * memory, we don't want the Linux-specific update to | ||
1931 | * the timeval to cause a fault after the select has | ||
1932 | * completed successfully. However, because we're not | ||
1933 | * updating the timeval, we can't restart the system | ||
1934 | * call. | ||
1935 | */ | ||
1936 | if (ret == -ERESTARTNOHAND && timeout >= 0) | ||
1937 | ret = -EINTR; | ||
1938 | } | ||
1939 | } | ||
1940 | |||
1941 | return ret; | ||
1942 | } | ||
1943 | #endif /* TIF_RESTORE_SIGMASK */ | ||
1944 | |||
1723 | #if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE) | 1945 | #if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE) |
1724 | /* Stuff for NFS server syscalls... */ | 1946 | /* Stuff for NFS server syscalls... */ |
1725 | struct compat_nfsctl_svc { | 1947 | struct compat_nfsctl_svc { |
@@ -477,7 +477,7 @@ struct file *open_exec(const char *name) | |||
477 | int err; | 477 | int err; |
478 | struct file *file; | 478 | struct file *file; |
479 | 479 | ||
480 | err = path_lookup_open(name, LOOKUP_FOLLOW, &nd, FMODE_READ); | 480 | err = path_lookup_open(AT_FDCWD, name, LOOKUP_FOLLOW, &nd, FMODE_READ); |
481 | file = ERR_PTR(err); | 481 | file = ERR_PTR(err); |
482 | 482 | ||
483 | if (!err) { | 483 | if (!err) { |
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index 5bfe40085fbc..b06b54f1bbbb 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c | |||
@@ -11,6 +11,33 @@ struct export_operations export_op_default; | |||
11 | 11 | ||
12 | #define dprintk(fmt, args...) do{}while(0) | 12 | #define dprintk(fmt, args...) do{}while(0) |
13 | 13 | ||
14 | static struct dentry * | ||
15 | find_acceptable_alias(struct dentry *result, | ||
16 | int (*acceptable)(void *context, struct dentry *dentry), | ||
17 | void *context) | ||
18 | { | ||
19 | struct dentry *dentry, *toput = NULL; | ||
20 | |||
21 | spin_lock(&dcache_lock); | ||
22 | list_for_each_entry(dentry, &result->d_inode->i_dentry, d_alias) { | ||
23 | dget_locked(dentry); | ||
24 | spin_unlock(&dcache_lock); | ||
25 | if (toput) | ||
26 | dput(toput); | ||
27 | if (dentry != result && acceptable(context, dentry)) { | ||
28 | dput(result); | ||
29 | return dentry; | ||
30 | } | ||
31 | spin_lock(&dcache_lock); | ||
32 | toput = dentry; | ||
33 | } | ||
34 | spin_unlock(&dcache_lock); | ||
35 | |||
36 | if (toput) | ||
37 | dput(toput); | ||
38 | return NULL; | ||
39 | } | ||
40 | |||
14 | /** | 41 | /** |
15 | * find_exported_dentry - helper routine to implement export_operations->decode_fh | 42 | * find_exported_dentry - helper routine to implement export_operations->decode_fh |
16 | * @sb: The &super_block identifying the filesystem | 43 | * @sb: The &super_block identifying the filesystem |
@@ -52,8 +79,7 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
52 | struct dentry *target_dir; | 79 | struct dentry *target_dir; |
53 | int err; | 80 | int err; |
54 | struct export_operations *nops = sb->s_export_op; | 81 | struct export_operations *nops = sb->s_export_op; |
55 | struct list_head *le, *head; | 82 | struct dentry *alias; |
56 | struct dentry *toput = NULL; | ||
57 | int noprogress; | 83 | int noprogress; |
58 | char nbuf[NAME_MAX+1]; | 84 | char nbuf[NAME_MAX+1]; |
59 | 85 | ||
@@ -79,27 +105,10 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
79 | /* there is no other dentry, so fail */ | 105 | /* there is no other dentry, so fail */ |
80 | goto err_result; | 106 | goto err_result; |
81 | } | 107 | } |
82 | /* try any other aliases */ | 108 | |
83 | spin_lock(&dcache_lock); | 109 | alias = find_acceptable_alias(result, acceptable, context); |
84 | head = &result->d_inode->i_dentry; | 110 | if (alias) |
85 | list_for_each(le, head) { | 111 | return alias; |
86 | struct dentry *dentry = list_entry(le, struct dentry, d_alias); | ||
87 | dget_locked(dentry); | ||
88 | spin_unlock(&dcache_lock); | ||
89 | if (toput) | ||
90 | dput(toput); | ||
91 | toput = NULL; | ||
92 | if (dentry != result && | ||
93 | acceptable(context, dentry)) { | ||
94 | dput(result); | ||
95 | return dentry; | ||
96 | } | ||
97 | spin_lock(&dcache_lock); | ||
98 | toput = dentry; | ||
99 | } | ||
100 | spin_unlock(&dcache_lock); | ||
101 | if (toput) | ||
102 | dput(toput); | ||
103 | } | 112 | } |
104 | 113 | ||
105 | /* It's a directory, or we are required to confirm the file's | 114 | /* It's a directory, or we are required to confirm the file's |
@@ -258,26 +267,10 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
258 | /* now result is properly connected, it is our best bet */ | 267 | /* now result is properly connected, it is our best bet */ |
259 | if (acceptable(context, result)) | 268 | if (acceptable(context, result)) |
260 | return result; | 269 | return result; |
261 | /* one last try of the aliases.. */ | 270 | |
262 | spin_lock(&dcache_lock); | 271 | alias = find_acceptable_alias(result, acceptable, context); |
263 | toput = NULL; | 272 | if (alias) |
264 | head = &result->d_inode->i_dentry; | 273 | return alias; |
265 | list_for_each(le, head) { | ||
266 | struct dentry *dentry = list_entry(le, struct dentry, d_alias); | ||
267 | dget_locked(dentry); | ||
268 | spin_unlock(&dcache_lock); | ||
269 | if (toput) dput(toput); | ||
270 | if (dentry != result && | ||
271 | acceptable(context, dentry)) { | ||
272 | dput(result); | ||
273 | return dentry; | ||
274 | } | ||
275 | spin_lock(&dcache_lock); | ||
276 | toput = dentry; | ||
277 | } | ||
278 | spin_unlock(&dcache_lock); | ||
279 | if (toput) | ||
280 | dput(toput); | ||
281 | 274 | ||
282 | /* drat - I just cannot find anything acceptable */ | 275 | /* drat - I just cannot find anything acceptable */ |
283 | dput(result); | 276 | dput(result); |
diff --git a/fs/hfs/bfind.c b/fs/hfs/bfind.c index 89450ae32228..f13f1494d4fe 100644 --- a/fs/hfs/bfind.c +++ b/fs/hfs/bfind.c | |||
@@ -64,7 +64,6 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd) | |||
64 | else | 64 | else |
65 | e = rec - 1; | 65 | e = rec - 1; |
66 | } while (b <= e); | 66 | } while (b <= e); |
67 | //printk("%d: %d,%d,%d\n", bnode->this, b, e, rec); | ||
68 | if (rec != e && e >= 0) { | 67 | if (rec != e && e >= 0) { |
69 | len = hfs_brec_lenoff(bnode, e, &off); | 68 | len = hfs_brec_lenoff(bnode, e, &off); |
70 | keylen = hfs_brec_keylen(bnode, e); | 69 | keylen = hfs_brec_keylen(bnode, e); |
@@ -127,7 +126,7 @@ int hfs_brec_find(struct hfs_find_data *fd) | |||
127 | return res; | 126 | return res; |
128 | 127 | ||
129 | invalid: | 128 | invalid: |
130 | printk("HFS: inconsistency in B*Tree (%d,%d,%d,%u,%u)\n", | 129 | printk(KERN_ERR "hfs: inconsistency in B*Tree (%d,%d,%d,%u,%u)\n", |
131 | height, bnode->height, bnode->type, nidx, parent); | 130 | height, bnode->height, bnode->type, nidx, parent); |
132 | res = -EIO; | 131 | res = -EIO; |
133 | release: | 132 | release: |
diff --git a/fs/hfs/bnode.c b/fs/hfs/bnode.c index 3d5cdc6847c0..a7a7d77f3fd3 100644 --- a/fs/hfs/bnode.c +++ b/fs/hfs/bnode.c | |||
@@ -198,7 +198,7 @@ void hfs_bnode_unlink(struct hfs_bnode *node) | |||
198 | 198 | ||
199 | // move down? | 199 | // move down? |
200 | if (!node->prev && !node->next) { | 200 | if (!node->prev && !node->next) { |
201 | printk("hfs_btree_del_level\n"); | 201 | printk(KERN_DEBUG "hfs_btree_del_level\n"); |
202 | } | 202 | } |
203 | if (!node->parent) { | 203 | if (!node->parent) { |
204 | tree->root = 0; | 204 | tree->root = 0; |
@@ -219,7 +219,7 @@ struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *tree, u32 cnid) | |||
219 | struct hfs_bnode *node; | 219 | struct hfs_bnode *node; |
220 | 220 | ||
221 | if (cnid >= tree->node_count) { | 221 | if (cnid >= tree->node_count) { |
222 | printk("HFS: request for non-existent node %d in B*Tree\n", cnid); | 222 | printk(KERN_ERR "hfs: request for non-existent node %d in B*Tree\n", cnid); |
223 | return NULL; | 223 | return NULL; |
224 | } | 224 | } |
225 | 225 | ||
@@ -242,7 +242,7 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid) | |||
242 | loff_t off; | 242 | loff_t off; |
243 | 243 | ||
244 | if (cnid >= tree->node_count) { | 244 | if (cnid >= tree->node_count) { |
245 | printk("HFS: request for non-existent node %d in B*Tree\n", cnid); | 245 | printk(KERN_ERR "hfs: request for non-existent node %d in B*Tree\n", cnid); |
246 | return NULL; | 246 | return NULL; |
247 | } | 247 | } |
248 | 248 | ||
diff --git a/fs/hfs/brec.c b/fs/hfs/brec.c index 7d8fff2c25fc..5c87cf4801fc 100644 --- a/fs/hfs/brec.c +++ b/fs/hfs/brec.c | |||
@@ -362,7 +362,7 @@ again: | |||
362 | end_off = hfs_bnode_read_u16(parent, end_rec_off); | 362 | end_off = hfs_bnode_read_u16(parent, end_rec_off); |
363 | if (end_rec_off - end_off < diff) { | 363 | if (end_rec_off - end_off < diff) { |
364 | 364 | ||
365 | printk("splitting index node...\n"); | 365 | printk(KERN_DEBUG "hfs: splitting index node...\n"); |
366 | fd->bnode = parent; | 366 | fd->bnode = parent; |
367 | new_node = hfs_bnode_split(fd); | 367 | new_node = hfs_bnode_split(fd); |
368 | if (IS_ERR(new_node)) | 368 | if (IS_ERR(new_node)) |
diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c index 394725efa1c8..7bb11edd1488 100644 --- a/fs/hfs/btree.c +++ b/fs/hfs/btree.c | |||
@@ -111,7 +111,7 @@ void hfs_btree_close(struct hfs_btree *tree) | |||
111 | while ((node = tree->node_hash[i])) { | 111 | while ((node = tree->node_hash[i])) { |
112 | tree->node_hash[i] = node->next_hash; | 112 | tree->node_hash[i] = node->next_hash; |
113 | if (atomic_read(&node->refcnt)) | 113 | if (atomic_read(&node->refcnt)) |
114 | printk("HFS: node %d:%d still has %d user(s)!\n", | 114 | printk(KERN_ERR "hfs: node %d:%d still has %d user(s)!\n", |
115 | node->tree->cnid, node->this, atomic_read(&node->refcnt)); | 115 | node->tree->cnid, node->this, atomic_read(&node->refcnt)); |
116 | hfs_bnode_free(node); | 116 | hfs_bnode_free(node); |
117 | tree->node_hash_cnt--; | 117 | tree->node_hash_cnt--; |
@@ -252,7 +252,7 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree) | |||
252 | kunmap(*pagep); | 252 | kunmap(*pagep); |
253 | nidx = node->next; | 253 | nidx = node->next; |
254 | if (!nidx) { | 254 | if (!nidx) { |
255 | printk("create new bmap node...\n"); | 255 | printk(KERN_DEBUG "hfs: create new bmap node...\n"); |
256 | next_node = hfs_bmap_new_bmap(node, idx); | 256 | next_node = hfs_bmap_new_bmap(node, idx); |
257 | } else | 257 | } else |
258 | next_node = hfs_bnode_find(tree, nidx); | 258 | next_node = hfs_bnode_find(tree, nidx); |
@@ -292,7 +292,7 @@ void hfs_bmap_free(struct hfs_bnode *node) | |||
292 | hfs_bnode_put(node); | 292 | hfs_bnode_put(node); |
293 | if (!i) { | 293 | if (!i) { |
294 | /* panic */; | 294 | /* panic */; |
295 | printk("HFS: unable to free bnode %u. bmap not found!\n", node->this); | 295 | printk(KERN_CRIT "hfs: unable to free bnode %u. bmap not found!\n", node->this); |
296 | return; | 296 | return; |
297 | } | 297 | } |
298 | node = hfs_bnode_find(tree, i); | 298 | node = hfs_bnode_find(tree, i); |
@@ -300,7 +300,7 @@ void hfs_bmap_free(struct hfs_bnode *node) | |||
300 | return; | 300 | return; |
301 | if (node->type != HFS_NODE_MAP) { | 301 | if (node->type != HFS_NODE_MAP) { |
302 | /* panic */; | 302 | /* panic */; |
303 | printk("HFS: invalid bmap found! (%u,%d)\n", node->this, node->type); | 303 | printk(KERN_CRIT "hfs: invalid bmap found! (%u,%d)\n", node->this, node->type); |
304 | hfs_bnode_put(node); | 304 | hfs_bnode_put(node); |
305 | return; | 305 | return; |
306 | } | 306 | } |
@@ -313,7 +313,7 @@ void hfs_bmap_free(struct hfs_bnode *node) | |||
313 | m = 1 << (~nidx & 7); | 313 | m = 1 << (~nidx & 7); |
314 | byte = data[off]; | 314 | byte = data[off]; |
315 | if (!(byte & m)) { | 315 | if (!(byte & m)) { |
316 | printk("HFS: trying to free free bnode %u(%d)\n", node->this, node->type); | 316 | printk(KERN_CRIT "hfs: trying to free free bnode %u(%d)\n", node->this, node->type); |
317 | kunmap(page); | 317 | kunmap(page); |
318 | hfs_bnode_put(node); | 318 | hfs_bnode_put(node); |
319 | return; | 319 | return; |
diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c index 2fcd679f0238..ba851576ebb1 100644 --- a/fs/hfs/catalog.c +++ b/fs/hfs/catalog.c | |||
@@ -184,7 +184,7 @@ int hfs_cat_find_brec(struct super_block *sb, u32 cnid, | |||
184 | 184 | ||
185 | type = rec.type; | 185 | type = rec.type; |
186 | if (type != HFS_CDR_THD && type != HFS_CDR_FTH) { | 186 | if (type != HFS_CDR_THD && type != HFS_CDR_FTH) { |
187 | printk("HFS-fs: Found bad thread record in catalog\n"); | 187 | printk(KERN_ERR "hfs: found bad thread record in catalog\n"); |
188 | return -EIO; | 188 | return -EIO; |
189 | } | 189 | } |
190 | 190 | ||
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index e1f24befba58..534e5a7480ef 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c | |||
@@ -81,12 +81,12 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
81 | case 1: | 81 | case 1: |
82 | hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); | 82 | hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); |
83 | if (entry.type != HFS_CDR_THD) { | 83 | if (entry.type != HFS_CDR_THD) { |
84 | printk("HFS: bad catalog folder thread\n"); | 84 | printk(KERN_ERR "hfs: bad catalog folder thread\n"); |
85 | err = -EIO; | 85 | err = -EIO; |
86 | goto out; | 86 | goto out; |
87 | } | 87 | } |
88 | //if (fd.entrylength < HFS_MIN_THREAD_SZ) { | 88 | //if (fd.entrylength < HFS_MIN_THREAD_SZ) { |
89 | // printk("HFS: truncated catalog thread\n"); | 89 | // printk(KERN_ERR "hfs: truncated catalog thread\n"); |
90 | // err = -EIO; | 90 | // err = -EIO; |
91 | // goto out; | 91 | // goto out; |
92 | //} | 92 | //} |
@@ -105,7 +105,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
105 | 105 | ||
106 | for (;;) { | 106 | for (;;) { |
107 | if (be32_to_cpu(fd.key->cat.ParID) != inode->i_ino) { | 107 | if (be32_to_cpu(fd.key->cat.ParID) != inode->i_ino) { |
108 | printk("HFS: walked past end of dir\n"); | 108 | printk(KERN_ERR "hfs: walked past end of dir\n"); |
109 | err = -EIO; | 109 | err = -EIO; |
110 | goto out; | 110 | goto out; |
111 | } | 111 | } |
@@ -114,7 +114,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
114 | len = hfs_mac2asc(sb, strbuf, &fd.key->cat.CName); | 114 | len = hfs_mac2asc(sb, strbuf, &fd.key->cat.CName); |
115 | if (type == HFS_CDR_DIR) { | 115 | if (type == HFS_CDR_DIR) { |
116 | if (fd.entrylength < sizeof(struct hfs_cat_dir)) { | 116 | if (fd.entrylength < sizeof(struct hfs_cat_dir)) { |
117 | printk("HFS: small dir entry\n"); | 117 | printk(KERN_ERR "hfs: small dir entry\n"); |
118 | err = -EIO; | 118 | err = -EIO; |
119 | goto out; | 119 | goto out; |
120 | } | 120 | } |
@@ -123,7 +123,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
123 | break; | 123 | break; |
124 | } else if (type == HFS_CDR_FIL) { | 124 | } else if (type == HFS_CDR_FIL) { |
125 | if (fd.entrylength < sizeof(struct hfs_cat_file)) { | 125 | if (fd.entrylength < sizeof(struct hfs_cat_file)) { |
126 | printk("HFS: small file entry\n"); | 126 | printk(KERN_ERR "hfs: small file entry\n"); |
127 | err = -EIO; | 127 | err = -EIO; |
128 | goto out; | 128 | goto out; |
129 | } | 129 | } |
@@ -131,7 +131,7 @@ static int hfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
131 | be32_to_cpu(entry.file.FlNum), DT_REG)) | 131 | be32_to_cpu(entry.file.FlNum), DT_REG)) |
132 | break; | 132 | break; |
133 | } else { | 133 | } else { |
134 | printk("HFS: bad catalog entry type %d\n", type); | 134 | printk(KERN_ERR "hfs: bad catalog entry type %d\n", type); |
135 | err = -EIO; | 135 | err = -EIO; |
136 | goto out; | 136 | goto out; |
137 | } | 137 | } |
diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h index cc5dcd52e23d..18ce47ab1b71 100644 --- a/fs/hfs/hfs_fs.h +++ b/fs/hfs/hfs_fs.h | |||
@@ -35,9 +35,6 @@ | |||
35 | #define dprint(flg, fmt, args...) \ | 35 | #define dprint(flg, fmt, args...) \ |
36 | if (flg & DBG_MASK) printk(fmt , ## args) | 36 | if (flg & DBG_MASK) printk(fmt , ## args) |
37 | 37 | ||
38 | #define hfs_warn(format, args...) printk(KERN_WARNING format , ## args) | ||
39 | #define hfs_error(format, args...) printk(KERN_ERR format , ## args) | ||
40 | |||
41 | /* | 38 | /* |
42 | * struct hfs_inode_info | 39 | * struct hfs_inode_info |
43 | * | 40 | * |
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index 050a49276499..39fd85b9b916 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c | |||
@@ -95,7 +95,6 @@ static int hfs_releasepage(struct page *page, gfp_t mask) | |||
95 | } while (--i && nidx < tree->node_count); | 95 | } while (--i && nidx < tree->node_count); |
96 | spin_unlock(&tree->hash_lock); | 96 | spin_unlock(&tree->hash_lock); |
97 | } | 97 | } |
98 | //printk("releasepage: %lu,%x = %d\n", page->index, mask, res); | ||
99 | return res ? try_to_free_buffers(page) : 0; | 98 | return res ? try_to_free_buffers(page) : 0; |
100 | } | 99 | } |
101 | 100 | ||
diff --git a/fs/hfs/mdb.c b/fs/hfs/mdb.c index 0a473f79c89f..b4651e128d7f 100644 --- a/fs/hfs/mdb.c +++ b/fs/hfs/mdb.c | |||
@@ -47,7 +47,7 @@ static int hfs_get_last_session(struct super_block *sb, | |||
47 | *start = (sector_t)te.cdte_addr.lba << 2; | 47 | *start = (sector_t)te.cdte_addr.lba << 2; |
48 | return 0; | 48 | return 0; |
49 | } | 49 | } |
50 | printk(KERN_ERR "HFS: Invalid session number or type of track\n"); | 50 | printk(KERN_ERR "hfs: invalid session number or type of track\n"); |
51 | return -EINVAL; | 51 | return -EINVAL; |
52 | } | 52 | } |
53 | ms_info.addr_format = CDROM_LBA; | 53 | ms_info.addr_format = CDROM_LBA; |
@@ -100,7 +100,7 @@ int hfs_mdb_get(struct super_block *sb) | |||
100 | 100 | ||
101 | HFS_SB(sb)->alloc_blksz = size = be32_to_cpu(mdb->drAlBlkSiz); | 101 | HFS_SB(sb)->alloc_blksz = size = be32_to_cpu(mdb->drAlBlkSiz); |
102 | if (!size || (size & (HFS_SECTOR_SIZE - 1))) { | 102 | if (!size || (size & (HFS_SECTOR_SIZE - 1))) { |
103 | hfs_warn("hfs_fs: bad allocation block size %d\n", size); | 103 | printk(KERN_ERR "hfs: bad allocation block size %d\n", size); |
104 | goto out_bh; | 104 | goto out_bh; |
105 | } | 105 | } |
106 | 106 | ||
@@ -117,7 +117,7 @@ int hfs_mdb_get(struct super_block *sb) | |||
117 | size >>= 1; | 117 | size >>= 1; |
118 | brelse(bh); | 118 | brelse(bh); |
119 | if (!sb_set_blocksize(sb, size)) { | 119 | if (!sb_set_blocksize(sb, size)) { |
120 | printk("hfs_fs: unable to set blocksize to %u\n", size); | 120 | printk(KERN_ERR "hfs: unable to set blocksize to %u\n", size); |
121 | goto out; | 121 | goto out; |
122 | } | 122 | } |
123 | 123 | ||
@@ -161,8 +161,8 @@ int hfs_mdb_get(struct super_block *sb) | |||
161 | } | 161 | } |
162 | 162 | ||
163 | if (!HFS_SB(sb)->alt_mdb) { | 163 | if (!HFS_SB(sb)->alt_mdb) { |
164 | hfs_warn("hfs_fs: unable to locate alternate MDB\n"); | 164 | printk(KERN_WARNING "hfs: unable to locate alternate MDB\n"); |
165 | hfs_warn("hfs_fs: continuing without an alternate MDB\n"); | 165 | printk(KERN_WARNING "hfs: continuing without an alternate MDB\n"); |
166 | } | 166 | } |
167 | 167 | ||
168 | HFS_SB(sb)->bitmap = (__be32 *)__get_free_pages(GFP_KERNEL, PAGE_SIZE < 8192 ? 1 : 0); | 168 | HFS_SB(sb)->bitmap = (__be32 *)__get_free_pages(GFP_KERNEL, PAGE_SIZE < 8192 ? 1 : 0); |
@@ -177,7 +177,7 @@ int hfs_mdb_get(struct super_block *sb) | |||
177 | while (size) { | 177 | while (size) { |
178 | bh = sb_bread(sb, off >> sb->s_blocksize_bits); | 178 | bh = sb_bread(sb, off >> sb->s_blocksize_bits); |
179 | if (!bh) { | 179 | if (!bh) { |
180 | hfs_warn("hfs_fs: unable to read volume bitmap\n"); | 180 | printk(KERN_ERR "hfs: unable to read volume bitmap\n"); |
181 | goto out; | 181 | goto out; |
182 | } | 182 | } |
183 | off2 = off & (sb->s_blocksize - 1); | 183 | off2 = off & (sb->s_blocksize - 1); |
@@ -191,23 +191,23 @@ int hfs_mdb_get(struct super_block *sb) | |||
191 | 191 | ||
192 | HFS_SB(sb)->ext_tree = hfs_btree_open(sb, HFS_EXT_CNID, hfs_ext_keycmp); | 192 | HFS_SB(sb)->ext_tree = hfs_btree_open(sb, HFS_EXT_CNID, hfs_ext_keycmp); |
193 | if (!HFS_SB(sb)->ext_tree) { | 193 | if (!HFS_SB(sb)->ext_tree) { |
194 | hfs_warn("hfs_fs: unable to open extent tree\n"); | 194 | printk(KERN_ERR "hfs: unable to open extent tree\n"); |
195 | goto out; | 195 | goto out; |
196 | } | 196 | } |
197 | HFS_SB(sb)->cat_tree = hfs_btree_open(sb, HFS_CAT_CNID, hfs_cat_keycmp); | 197 | HFS_SB(sb)->cat_tree = hfs_btree_open(sb, HFS_CAT_CNID, hfs_cat_keycmp); |
198 | if (!HFS_SB(sb)->cat_tree) { | 198 | if (!HFS_SB(sb)->cat_tree) { |
199 | hfs_warn("hfs_fs: unable to open catalog tree\n"); | 199 | printk(KERN_ERR "hfs: unable to open catalog tree\n"); |
200 | goto out; | 200 | goto out; |
201 | } | 201 | } |
202 | 202 | ||
203 | attrib = mdb->drAtrb; | 203 | attrib = mdb->drAtrb; |
204 | if (!(attrib & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))) { | 204 | if (!(attrib & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))) { |
205 | hfs_warn("HFS-fs warning: Filesystem was not cleanly unmounted, " | 205 | printk(KERN_WARNING "hfs: filesystem was not cleanly unmounted, " |
206 | "running fsck.hfs is recommended. mounting read-only.\n"); | 206 | "running fsck.hfs is recommended. mounting read-only.\n"); |
207 | sb->s_flags |= MS_RDONLY; | 207 | sb->s_flags |= MS_RDONLY; |
208 | } | 208 | } |
209 | if ((attrib & cpu_to_be16(HFS_SB_ATTRIB_SLOCK))) { | 209 | if ((attrib & cpu_to_be16(HFS_SB_ATTRIB_SLOCK))) { |
210 | hfs_warn("HFS-fs: Filesystem is marked locked, mounting read-only.\n"); | 210 | printk(KERN_WARNING "hfs: filesystem is marked locked, mounting read-only.\n"); |
211 | sb->s_flags |= MS_RDONLY; | 211 | sb->s_flags |= MS_RDONLY; |
212 | } | 212 | } |
213 | if (!(sb->s_flags & MS_RDONLY)) { | 213 | if (!(sb->s_flags & MS_RDONLY)) { |
@@ -303,7 +303,7 @@ void hfs_mdb_commit(struct super_block *sb) | |||
303 | while (size) { | 303 | while (size) { |
304 | bh = sb_bread(sb, block); | 304 | bh = sb_bread(sb, block); |
305 | if (!bh) { | 305 | if (!bh) { |
306 | hfs_warn("hfs_fs: unable to read volume bitmap\n"); | 306 | printk(KERN_ERR "hfs: unable to read volume bitmap\n"); |
307 | break; | 307 | break; |
308 | } | 308 | } |
309 | len = min((int)sb->s_blocksize - off, size); | 309 | len = min((int)sb->s_blocksize - off, size); |
diff --git a/fs/hfs/super.c b/fs/hfs/super.c index c5074aeafcae..1181d116117d 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c | |||
@@ -101,12 +101,12 @@ static int hfs_remount(struct super_block *sb, int *flags, char *data) | |||
101 | return 0; | 101 | return 0; |
102 | if (!(*flags & MS_RDONLY)) { | 102 | if (!(*flags & MS_RDONLY)) { |
103 | if (!(HFS_SB(sb)->mdb->drAtrb & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))) { | 103 | if (!(HFS_SB(sb)->mdb->drAtrb & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))) { |
104 | printk("HFS-fs warning: Filesystem was not cleanly unmounted, " | 104 | printk(KERN_WARNING "hfs: filesystem was not cleanly unmounted, " |
105 | "running fsck.hfs is recommended. leaving read-only.\n"); | 105 | "running fsck.hfs is recommended. leaving read-only.\n"); |
106 | sb->s_flags |= MS_RDONLY; | 106 | sb->s_flags |= MS_RDONLY; |
107 | *flags |= MS_RDONLY; | 107 | *flags |= MS_RDONLY; |
108 | } else if (HFS_SB(sb)->mdb->drAtrb & cpu_to_be16(HFS_SB_ATTRIB_SLOCK)) { | 108 | } else if (HFS_SB(sb)->mdb->drAtrb & cpu_to_be16(HFS_SB_ATTRIB_SLOCK)) { |
109 | printk("HFS-fs: Filesystem is marked locked, leaving read-only.\n"); | 109 | printk(KERN_WARNING "hfs: filesystem is marked locked, leaving read-only.\n"); |
110 | sb->s_flags |= MS_RDONLY; | 110 | sb->s_flags |= MS_RDONLY; |
111 | *flags |= MS_RDONLY; | 111 | *flags |= MS_RDONLY; |
112 | } | 112 | } |
@@ -229,21 +229,21 @@ static int parse_options(char *options, struct hfs_sb_info *hsb) | |||
229 | switch (token) { | 229 | switch (token) { |
230 | case opt_uid: | 230 | case opt_uid: |
231 | if (match_int(&args[0], &tmp)) { | 231 | if (match_int(&args[0], &tmp)) { |
232 | printk("HFS: uid requires an argument\n"); | 232 | printk(KERN_ERR "hfs: uid requires an argument\n"); |
233 | return 0; | 233 | return 0; |
234 | } | 234 | } |
235 | hsb->s_uid = (uid_t)tmp; | 235 | hsb->s_uid = (uid_t)tmp; |
236 | break; | 236 | break; |
237 | case opt_gid: | 237 | case opt_gid: |
238 | if (match_int(&args[0], &tmp)) { | 238 | if (match_int(&args[0], &tmp)) { |
239 | printk("HFS: gid requires an argument\n"); | 239 | printk(KERN_ERR "hfs: gid requires an argument\n"); |
240 | return 0; | 240 | return 0; |
241 | } | 241 | } |
242 | hsb->s_gid = (gid_t)tmp; | 242 | hsb->s_gid = (gid_t)tmp; |
243 | break; | 243 | break; |
244 | case opt_umask: | 244 | case opt_umask: |
245 | if (match_octal(&args[0], &tmp)) { | 245 | if (match_octal(&args[0], &tmp)) { |
246 | printk("HFS: umask requires a value\n"); | 246 | printk(KERN_ERR "hfs: umask requires a value\n"); |
247 | return 0; | 247 | return 0; |
248 | } | 248 | } |
249 | hsb->s_file_umask = (umode_t)tmp; | 249 | hsb->s_file_umask = (umode_t)tmp; |
@@ -251,39 +251,39 @@ static int parse_options(char *options, struct hfs_sb_info *hsb) | |||
251 | break; | 251 | break; |
252 | case opt_file_umask: | 252 | case opt_file_umask: |
253 | if (match_octal(&args[0], &tmp)) { | 253 | if (match_octal(&args[0], &tmp)) { |
254 | printk("HFS: file_umask requires a value\n"); | 254 | printk(KERN_ERR "hfs: file_umask requires a value\n"); |
255 | return 0; | 255 | return 0; |
256 | } | 256 | } |
257 | hsb->s_file_umask = (umode_t)tmp; | 257 | hsb->s_file_umask = (umode_t)tmp; |
258 | break; | 258 | break; |
259 | case opt_dir_umask: | 259 | case opt_dir_umask: |
260 | if (match_octal(&args[0], &tmp)) { | 260 | if (match_octal(&args[0], &tmp)) { |
261 | printk("HFS: dir_umask requires a value\n"); | 261 | printk(KERN_ERR "hfs: dir_umask requires a value\n"); |
262 | return 0; | 262 | return 0; |
263 | } | 263 | } |
264 | hsb->s_dir_umask = (umode_t)tmp; | 264 | hsb->s_dir_umask = (umode_t)tmp; |
265 | break; | 265 | break; |
266 | case opt_part: | 266 | case opt_part: |
267 | if (match_int(&args[0], &hsb->part)) { | 267 | if (match_int(&args[0], &hsb->part)) { |
268 | printk("HFS: part requires an argument\n"); | 268 | printk(KERN_ERR "hfs: part requires an argument\n"); |
269 | return 0; | 269 | return 0; |
270 | } | 270 | } |
271 | break; | 271 | break; |
272 | case opt_session: | 272 | case opt_session: |
273 | if (match_int(&args[0], &hsb->session)) { | 273 | if (match_int(&args[0], &hsb->session)) { |
274 | printk("HFS: session requires an argument\n"); | 274 | printk(KERN_ERR "hfs: session requires an argument\n"); |
275 | return 0; | 275 | return 0; |
276 | } | 276 | } |
277 | break; | 277 | break; |
278 | case opt_type: | 278 | case opt_type: |
279 | if (match_fourchar(&args[0], &hsb->s_type)) { | 279 | if (match_fourchar(&args[0], &hsb->s_type)) { |
280 | printk("HFS+-fs: type requires a 4 character value\n"); | 280 | printk(KERN_ERR "hfs: type requires a 4 character value\n"); |
281 | return 0; | 281 | return 0; |
282 | } | 282 | } |
283 | break; | 283 | break; |
284 | case opt_creator: | 284 | case opt_creator: |
285 | if (match_fourchar(&args[0], &hsb->s_creator)) { | 285 | if (match_fourchar(&args[0], &hsb->s_creator)) { |
286 | printk("HFS+-fs: creator requires a 4 character value\n"); | 286 | printk(KERN_ERR "hfs: creator requires a 4 character value\n"); |
287 | return 0; | 287 | return 0; |
288 | } | 288 | } |
289 | break; | 289 | break; |
@@ -292,13 +292,13 @@ static int parse_options(char *options, struct hfs_sb_info *hsb) | |||
292 | break; | 292 | break; |
293 | case opt_codepage: | 293 | case opt_codepage: |
294 | if (hsb->nls_disk) { | 294 | if (hsb->nls_disk) { |
295 | printk("HFS+-fs: unable to change codepage\n"); | 295 | printk(KERN_ERR "hfs: unable to change codepage\n"); |
296 | return 0; | 296 | return 0; |
297 | } | 297 | } |
298 | p = match_strdup(&args[0]); | 298 | p = match_strdup(&args[0]); |
299 | hsb->nls_disk = load_nls(p); | 299 | hsb->nls_disk = load_nls(p); |
300 | if (!hsb->nls_disk) { | 300 | if (!hsb->nls_disk) { |
301 | printk("HFS+-fs: unable to load codepage \"%s\"\n", p); | 301 | printk(KERN_ERR "hfs: unable to load codepage \"%s\"\n", p); |
302 | kfree(p); | 302 | kfree(p); |
303 | return 0; | 303 | return 0; |
304 | } | 304 | } |
@@ -306,13 +306,13 @@ static int parse_options(char *options, struct hfs_sb_info *hsb) | |||
306 | break; | 306 | break; |
307 | case opt_iocharset: | 307 | case opt_iocharset: |
308 | if (hsb->nls_io) { | 308 | if (hsb->nls_io) { |
309 | printk("HFS: unable to change iocharset\n"); | 309 | printk(KERN_ERR "hfs: unable to change iocharset\n"); |
310 | return 0; | 310 | return 0; |
311 | } | 311 | } |
312 | p = match_strdup(&args[0]); | 312 | p = match_strdup(&args[0]); |
313 | hsb->nls_io = load_nls(p); | 313 | hsb->nls_io = load_nls(p); |
314 | if (!hsb->nls_io) { | 314 | if (!hsb->nls_io) { |
315 | printk("HFS: unable to load iocharset \"%s\"\n", p); | 315 | printk(KERN_ERR "hfs: unable to load iocharset \"%s\"\n", p); |
316 | kfree(p); | 316 | kfree(p); |
317 | return 0; | 317 | return 0; |
318 | } | 318 | } |
@@ -326,7 +326,7 @@ static int parse_options(char *options, struct hfs_sb_info *hsb) | |||
326 | if (hsb->nls_disk && !hsb->nls_io) { | 326 | if (hsb->nls_disk && !hsb->nls_io) { |
327 | hsb->nls_io = load_nls_default(); | 327 | hsb->nls_io = load_nls_default(); |
328 | if (!hsb->nls_io) { | 328 | if (!hsb->nls_io) { |
329 | printk("HFS: unable to load default iocharset\n"); | 329 | printk(KERN_ERR "hfs: unable to load default iocharset\n"); |
330 | return 0; | 330 | return 0; |
331 | } | 331 | } |
332 | } | 332 | } |
@@ -364,7 +364,7 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent) | |||
364 | 364 | ||
365 | res = -EINVAL; | 365 | res = -EINVAL; |
366 | if (!parse_options((char *)data, sbi)) { | 366 | if (!parse_options((char *)data, sbi)) { |
367 | hfs_warn("hfs_fs: unable to parse mount options.\n"); | 367 | printk(KERN_ERR "hfs: unable to parse mount options.\n"); |
368 | goto bail; | 368 | goto bail; |
369 | } | 369 | } |
370 | 370 | ||
@@ -375,7 +375,7 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent) | |||
375 | res = hfs_mdb_get(sb); | 375 | res = hfs_mdb_get(sb); |
376 | if (res) { | 376 | if (res) { |
377 | if (!silent) | 377 | if (!silent) |
378 | hfs_warn("VFS: Can't find a HFS filesystem on dev %s.\n", | 378 | printk(KERN_WARNING "hfs: can't find a HFS filesystem on dev %s.\n", |
379 | hfs_mdb_name(sb)); | 379 | hfs_mdb_name(sb)); |
380 | res = -EINVAL; | 380 | res = -EINVAL; |
381 | goto bail; | 381 | goto bail; |
@@ -407,7 +407,7 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent) | |||
407 | bail_iput: | 407 | bail_iput: |
408 | iput(root_inode); | 408 | iput(root_inode); |
409 | bail_no_root: | 409 | bail_no_root: |
410 | hfs_warn("hfs_fs: get root inode failed.\n"); | 410 | printk(KERN_ERR "hfs: get root inode failed.\n"); |
411 | bail: | 411 | bail: |
412 | hfs_mdb_put(sb); | 412 | hfs_mdb_put(sb); |
413 | return res; | 413 | return res; |
@@ -454,7 +454,7 @@ static void __exit exit_hfs_fs(void) | |||
454 | { | 454 | { |
455 | unregister_filesystem(&hfs_fs_type); | 455 | unregister_filesystem(&hfs_fs_type); |
456 | if (kmem_cache_destroy(hfs_inode_cachep)) | 456 | if (kmem_cache_destroy(hfs_inode_cachep)) |
457 | printk(KERN_INFO "hfs_inode_cache: not all structures were freed\n"); | 457 | printk(KERN_ERR "hfs_inode_cache: not all structures were freed\n"); |
458 | } | 458 | } |
459 | 459 | ||
460 | module_init(init_hfs_fs) | 460 | module_init(init_hfs_fs) |
diff --git a/fs/hfsplus/bfind.c b/fs/hfsplus/bfind.c index 257cdde0514b..5007a41f1be9 100644 --- a/fs/hfsplus/bfind.c +++ b/fs/hfsplus/bfind.c | |||
@@ -64,7 +64,6 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd) | |||
64 | else | 64 | else |
65 | e = rec - 1; | 65 | e = rec - 1; |
66 | } while (b <= e); | 66 | } while (b <= e); |
67 | //printk("%d: %d,%d,%d\n", bnode->this, b, e, rec); | ||
68 | if (rec != e && e >= 0) { | 67 | if (rec != e && e >= 0) { |
69 | len = hfs_brec_lenoff(bnode, e, &off); | 68 | len = hfs_brec_lenoff(bnode, e, &off); |
70 | keylen = hfs_brec_keylen(bnode, e); | 69 | keylen = hfs_brec_keylen(bnode, e); |
@@ -127,7 +126,7 @@ int hfs_brec_find(struct hfs_find_data *fd) | |||
127 | return res; | 126 | return res; |
128 | 127 | ||
129 | invalid: | 128 | invalid: |
130 | printk("HFS+-fs: inconsistency in B*Tree (%d,%d,%d,%u,%u)\n", | 129 | printk(KERN_ERR "hfs: inconsistency in B*Tree (%d,%d,%d,%u,%u)\n", |
131 | height, bnode->height, bnode->type, nidx, parent); | 130 | height, bnode->height, bnode->type, nidx, parent); |
132 | res = -EIO; | 131 | res = -EIO; |
133 | release: | 132 | release: |
diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c index 930cd9212de8..8f07e8fbd03d 100644 --- a/fs/hfsplus/bnode.c +++ b/fs/hfsplus/bnode.c | |||
@@ -358,7 +358,7 @@ void hfs_bnode_unlink(struct hfs_bnode *node) | |||
358 | 358 | ||
359 | // move down? | 359 | // move down? |
360 | if (!node->prev && !node->next) { | 360 | if (!node->prev && !node->next) { |
361 | printk("hfs_btree_del_level\n"); | 361 | printk(KERN_DEBUG "hfs_btree_del_level\n"); |
362 | } | 362 | } |
363 | if (!node->parent) { | 363 | if (!node->parent) { |
364 | tree->root = 0; | 364 | tree->root = 0; |
@@ -379,7 +379,7 @@ struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *tree, u32 cnid) | |||
379 | struct hfs_bnode *node; | 379 | struct hfs_bnode *node; |
380 | 380 | ||
381 | if (cnid >= tree->node_count) { | 381 | if (cnid >= tree->node_count) { |
382 | printk("HFS+-fs: request for non-existent node %d in B*Tree\n", cnid); | 382 | printk(KERN_ERR "hfs: request for non-existent node %d in B*Tree\n", cnid); |
383 | return NULL; | 383 | return NULL; |
384 | } | 384 | } |
385 | 385 | ||
@@ -402,7 +402,7 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid) | |||
402 | loff_t off; | 402 | loff_t off; |
403 | 403 | ||
404 | if (cnid >= tree->node_count) { | 404 | if (cnid >= tree->node_count) { |
405 | printk("HFS+-fs: request for non-existent node %d in B*Tree\n", cnid); | 405 | printk(KERN_ERR "hfs: request for non-existent node %d in B*Tree\n", cnid); |
406 | return NULL; | 406 | return NULL; |
407 | } | 407 | } |
408 | 408 | ||
@@ -576,8 +576,9 @@ struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num) | |||
576 | node = hfs_bnode_findhash(tree, num); | 576 | node = hfs_bnode_findhash(tree, num); |
577 | spin_unlock(&tree->hash_lock); | 577 | spin_unlock(&tree->hash_lock); |
578 | if (node) { | 578 | if (node) { |
579 | printk("new node %u already hashed?\n", num); | 579 | printk(KERN_CRIT "new node %u already hashed?\n", num); |
580 | BUG(); | 580 | WARN_ON(1); |
581 | return node; | ||
581 | } | 582 | } |
582 | node = __hfs_bnode_create(tree, num); | 583 | node = __hfs_bnode_create(tree, num); |
583 | if (!node) | 584 | if (!node) |
diff --git a/fs/hfsplus/brec.c b/fs/hfsplus/brec.c index 0ccef2ab790c..c88e5d72a402 100644 --- a/fs/hfsplus/brec.c +++ b/fs/hfsplus/brec.c | |||
@@ -360,7 +360,7 @@ again: | |||
360 | end_off = hfs_bnode_read_u16(parent, end_rec_off); | 360 | end_off = hfs_bnode_read_u16(parent, end_rec_off); |
361 | if (end_rec_off - end_off < diff) { | 361 | if (end_rec_off - end_off < diff) { |
362 | 362 | ||
363 | printk("splitting index node...\n"); | 363 | printk(KERN_DEBUG "hfs: splitting index node...\n"); |
364 | fd->bnode = parent; | 364 | fd->bnode = parent; |
365 | new_node = hfs_bnode_split(fd); | 365 | new_node = hfs_bnode_split(fd); |
366 | if (IS_ERR(new_node)) | 366 | if (IS_ERR(new_node)) |
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c index 44326aa2bd34..a67edfa34e9e 100644 --- a/fs/hfsplus/btree.c +++ b/fs/hfsplus/btree.c | |||
@@ -31,17 +31,8 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) | |||
31 | 31 | ||
32 | init_MUTEX(&tree->tree_lock); | 32 | init_MUTEX(&tree->tree_lock); |
33 | spin_lock_init(&tree->hash_lock); | 33 | spin_lock_init(&tree->hash_lock); |
34 | /* Set the correct compare function */ | ||
35 | tree->sb = sb; | 34 | tree->sb = sb; |
36 | tree->cnid = id; | 35 | tree->cnid = id; |
37 | if (id == HFSPLUS_EXT_CNID) { | ||
38 | tree->keycmp = hfsplus_ext_cmp_key; | ||
39 | } else if (id == HFSPLUS_CAT_CNID) { | ||
40 | tree->keycmp = hfsplus_cat_cmp_key; | ||
41 | } else { | ||
42 | printk("HFS+-fs: unknown B*Tree requested\n"); | ||
43 | goto free_tree; | ||
44 | } | ||
45 | tree->inode = iget(sb, id); | 36 | tree->inode = iget(sb, id); |
46 | if (!tree->inode) | 37 | if (!tree->inode) |
47 | goto free_tree; | 38 | goto free_tree; |
@@ -64,6 +55,20 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) | |||
64 | tree->max_key_len = be16_to_cpu(head->max_key_len); | 55 | tree->max_key_len = be16_to_cpu(head->max_key_len); |
65 | tree->depth = be16_to_cpu(head->depth); | 56 | tree->depth = be16_to_cpu(head->depth); |
66 | 57 | ||
58 | /* Set the correct compare function */ | ||
59 | if (id == HFSPLUS_EXT_CNID) { | ||
60 | tree->keycmp = hfsplus_ext_cmp_key; | ||
61 | } else if (id == HFSPLUS_CAT_CNID) { | ||
62 | if ((HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX) && | ||
63 | (head->key_type == HFSPLUS_KEY_BINARY)) | ||
64 | tree->keycmp = hfsplus_cat_bin_cmp_key; | ||
65 | else | ||
66 | tree->keycmp = hfsplus_cat_case_cmp_key; | ||
67 | } else { | ||
68 | printk(KERN_ERR "hfs: unknown B*Tree requested\n"); | ||
69 | goto fail_page; | ||
70 | } | ||
71 | |||
67 | size = tree->node_size; | 72 | size = tree->node_size; |
68 | if (!size || size & (size - 1)) | 73 | if (!size || size & (size - 1)) |
69 | goto fail_page; | 74 | goto fail_page; |
@@ -99,7 +104,7 @@ void hfs_btree_close(struct hfs_btree *tree) | |||
99 | while ((node = tree->node_hash[i])) { | 104 | while ((node = tree->node_hash[i])) { |
100 | tree->node_hash[i] = node->next_hash; | 105 | tree->node_hash[i] = node->next_hash; |
101 | if (atomic_read(&node->refcnt)) | 106 | if (atomic_read(&node->refcnt)) |
102 | printk("HFS+: node %d:%d still has %d user(s)!\n", | 107 | printk(KERN_CRIT "hfs: node %d:%d still has %d user(s)!\n", |
103 | node->tree->cnid, node->this, atomic_read(&node->refcnt)); | 108 | node->tree->cnid, node->this, atomic_read(&node->refcnt)); |
104 | hfs_bnode_free(node); | 109 | hfs_bnode_free(node); |
105 | tree->node_hash_cnt--; | 110 | tree->node_hash_cnt--; |
@@ -223,10 +228,6 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree) | |||
223 | tree->free_nodes--; | 228 | tree->free_nodes--; |
224 | mark_inode_dirty(tree->inode); | 229 | mark_inode_dirty(tree->inode); |
225 | hfs_bnode_put(node); | 230 | hfs_bnode_put(node); |
226 | if (!idx) { | ||
227 | printk("unexpected idx %u (%u)\n", idx, node->this); | ||
228 | BUG(); | ||
229 | } | ||
230 | return hfs_bnode_create(tree, idx); | 231 | return hfs_bnode_create(tree, idx); |
231 | } | 232 | } |
232 | } | 233 | } |
@@ -242,7 +243,7 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree) | |||
242 | kunmap(*pagep); | 243 | kunmap(*pagep); |
243 | nidx = node->next; | 244 | nidx = node->next; |
244 | if (!nidx) { | 245 | if (!nidx) { |
245 | printk("create new bmap node...\n"); | 246 | printk(KERN_DEBUG "hfs: create new bmap node...\n"); |
246 | next_node = hfs_bmap_new_bmap(node, idx); | 247 | next_node = hfs_bmap_new_bmap(node, idx); |
247 | } else | 248 | } else |
248 | next_node = hfs_bnode_find(tree, nidx); | 249 | next_node = hfs_bnode_find(tree, nidx); |
@@ -284,7 +285,7 @@ void hfs_bmap_free(struct hfs_bnode *node) | |||
284 | hfs_bnode_put(node); | 285 | hfs_bnode_put(node); |
285 | if (!i) { | 286 | if (!i) { |
286 | /* panic */; | 287 | /* panic */; |
287 | printk("HFS: unable to free bnode %u. bmap not found!\n", node->this); | 288 | printk(KERN_CRIT "hfs: unable to free bnode %u. bmap not found!\n", node->this); |
288 | return; | 289 | return; |
289 | } | 290 | } |
290 | node = hfs_bnode_find(tree, i); | 291 | node = hfs_bnode_find(tree, i); |
@@ -292,7 +293,7 @@ void hfs_bmap_free(struct hfs_bnode *node) | |||
292 | return; | 293 | return; |
293 | if (node->type != HFS_NODE_MAP) { | 294 | if (node->type != HFS_NODE_MAP) { |
294 | /* panic */; | 295 | /* panic */; |
295 | printk("HFS: invalid bmap found! (%u,%d)\n", node->this, node->type); | 296 | printk(KERN_CRIT "hfs: invalid bmap found! (%u,%d)\n", node->this, node->type); |
296 | hfs_bnode_put(node); | 297 | hfs_bnode_put(node); |
297 | return; | 298 | return; |
298 | } | 299 | } |
@@ -305,7 +306,7 @@ void hfs_bmap_free(struct hfs_bnode *node) | |||
305 | m = 1 << (~nidx & 7); | 306 | m = 1 << (~nidx & 7); |
306 | byte = data[off]; | 307 | byte = data[off]; |
307 | if (!(byte & m)) { | 308 | if (!(byte & m)) { |
308 | printk("HFS: trying to free free bnode %u(%d)\n", node->this, node->type); | 309 | printk(KERN_CRIT "hfs: trying to free free bnode %u(%d)\n", node->this, node->type); |
309 | kunmap(page); | 310 | kunmap(page); |
310 | hfs_bnode_put(node); | 311 | hfs_bnode_put(node); |
311 | return; | 312 | return; |
diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c index 94712790c8b3..f2d7c49ce759 100644 --- a/fs/hfsplus/catalog.c +++ b/fs/hfsplus/catalog.c | |||
@@ -13,7 +13,8 @@ | |||
13 | #include "hfsplus_fs.h" | 13 | #include "hfsplus_fs.h" |
14 | #include "hfsplus_raw.h" | 14 | #include "hfsplus_raw.h" |
15 | 15 | ||
16 | int hfsplus_cat_cmp_key(hfsplus_btree_key *k1, hfsplus_btree_key *k2) | 16 | int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *k1, |
17 | const hfsplus_btree_key *k2) | ||
17 | { | 18 | { |
18 | __be32 k1p, k2p; | 19 | __be32 k1p, k2p; |
19 | 20 | ||
@@ -22,7 +23,20 @@ int hfsplus_cat_cmp_key(hfsplus_btree_key *k1, hfsplus_btree_key *k2) | |||
22 | if (k1p != k2p) | 23 | if (k1p != k2p) |
23 | return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1; | 24 | return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1; |
24 | 25 | ||
25 | return hfsplus_unistrcmp(&k1->cat.name, &k2->cat.name); | 26 | return hfsplus_strcasecmp(&k1->cat.name, &k2->cat.name); |
27 | } | ||
28 | |||
29 | int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *k1, | ||
30 | const hfsplus_btree_key *k2) | ||
31 | { | ||
32 | __be32 k1p, k2p; | ||
33 | |||
34 | k1p = k1->cat.parent; | ||
35 | k2p = k2->cat.parent; | ||
36 | if (k1p != k2p) | ||
37 | return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1; | ||
38 | |||
39 | return hfsplus_strcmp(&k1->cat.name, &k2->cat.name); | ||
26 | } | 40 | } |
27 | 41 | ||
28 | void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *key, | 42 | void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *key, |
@@ -80,8 +94,11 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct i | |||
80 | memset(folder, 0, sizeof(*folder)); | 94 | memset(folder, 0, sizeof(*folder)); |
81 | folder->type = cpu_to_be16(HFSPLUS_FOLDER); | 95 | folder->type = cpu_to_be16(HFSPLUS_FOLDER); |
82 | folder->id = cpu_to_be32(inode->i_ino); | 96 | folder->id = cpu_to_be32(inode->i_ino); |
83 | folder->create_date = folder->content_mod_date = | 97 | HFSPLUS_I(inode).create_date = |
84 | folder->attribute_mod_date = folder->access_date = hfsp_now2mt(); | 98 | folder->create_date = |
99 | folder->content_mod_date = | ||
100 | folder->attribute_mod_date = | ||
101 | folder->access_date = hfsp_now2mt(); | ||
85 | hfsplus_set_perms(inode, &folder->permissions); | 102 | hfsplus_set_perms(inode, &folder->permissions); |
86 | if (inode == HFSPLUS_SB(inode->i_sb).hidden_dir) | 103 | if (inode == HFSPLUS_SB(inode->i_sb).hidden_dir) |
87 | /* invisible and namelocked */ | 104 | /* invisible and namelocked */ |
@@ -95,18 +112,27 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct i | |||
95 | file->type = cpu_to_be16(HFSPLUS_FILE); | 112 | file->type = cpu_to_be16(HFSPLUS_FILE); |
96 | file->flags = cpu_to_be16(HFSPLUS_FILE_THREAD_EXISTS); | 113 | file->flags = cpu_to_be16(HFSPLUS_FILE_THREAD_EXISTS); |
97 | file->id = cpu_to_be32(cnid); | 114 | file->id = cpu_to_be32(cnid); |
98 | file->create_date = file->content_mod_date = | 115 | HFSPLUS_I(inode).create_date = |
99 | file->attribute_mod_date = file->access_date = hfsp_now2mt(); | 116 | file->create_date = |
117 | file->content_mod_date = | ||
118 | file->attribute_mod_date = | ||
119 | file->access_date = hfsp_now2mt(); | ||
100 | if (cnid == inode->i_ino) { | 120 | if (cnid == inode->i_ino) { |
101 | hfsplus_set_perms(inode, &file->permissions); | 121 | hfsplus_set_perms(inode, &file->permissions); |
102 | file->user_info.fdType = cpu_to_be32(HFSPLUS_SB(inode->i_sb).type); | 122 | if (S_ISLNK(inode->i_mode)) { |
103 | file->user_info.fdCreator = cpu_to_be32(HFSPLUS_SB(inode->i_sb).creator); | 123 | file->user_info.fdType = cpu_to_be32(HFSP_SYMLINK_TYPE); |
124 | file->user_info.fdCreator = cpu_to_be32(HFSP_SYMLINK_CREATOR); | ||
125 | } else { | ||
126 | file->user_info.fdType = cpu_to_be32(HFSPLUS_SB(inode->i_sb).type); | ||
127 | file->user_info.fdCreator = cpu_to_be32(HFSPLUS_SB(inode->i_sb).creator); | ||
128 | } | ||
104 | if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE) | 129 | if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE) |
105 | file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED); | 130 | file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED); |
106 | } else { | 131 | } else { |
107 | file->user_info.fdType = cpu_to_be32(HFSP_HARDLINK_TYPE); | 132 | file->user_info.fdType = cpu_to_be32(HFSP_HARDLINK_TYPE); |
108 | file->user_info.fdCreator = cpu_to_be32(HFSP_HFSPLUS_CREATOR); | 133 | file->user_info.fdCreator = cpu_to_be32(HFSP_HFSPLUS_CREATOR); |
109 | file->user_info.fdFlags = cpu_to_be16(0x100); | 134 | file->user_info.fdFlags = cpu_to_be16(0x100); |
135 | file->create_date = HFSPLUS_I(HFSPLUS_SB(inode->i_sb).hidden_dir).create_date; | ||
110 | file->permissions.dev = cpu_to_be32(HFSPLUS_I(inode).dev); | 136 | file->permissions.dev = cpu_to_be32(HFSPLUS_I(inode).dev); |
111 | } | 137 | } |
112 | return sizeof(*file); | 138 | return sizeof(*file); |
@@ -139,7 +165,7 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid, | |||
139 | 165 | ||
140 | type = be16_to_cpu(tmp.type); | 166 | type = be16_to_cpu(tmp.type); |
141 | if (type != HFSPLUS_FOLDER_THREAD && type != HFSPLUS_FILE_THREAD) { | 167 | if (type != HFSPLUS_FOLDER_THREAD && type != HFSPLUS_FILE_THREAD) { |
142 | printk("HFS+-fs: Found bad thread record in catalog\n"); | 168 | printk(KERN_ERR "hfs: found bad thread record in catalog\n"); |
143 | return -EIO; | 169 | return -EIO; |
144 | } | 170 | } |
145 | 171 | ||
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index 50c8f44b6c66..01a6fe3a395c 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c | |||
@@ -66,25 +66,32 @@ again: | |||
66 | } | 66 | } |
67 | cnid = be32_to_cpu(entry.file.id); | 67 | cnid = be32_to_cpu(entry.file.id); |
68 | if (entry.file.user_info.fdType == cpu_to_be32(HFSP_HARDLINK_TYPE) && | 68 | if (entry.file.user_info.fdType == cpu_to_be32(HFSP_HARDLINK_TYPE) && |
69 | entry.file.user_info.fdCreator == cpu_to_be32(HFSP_HFSPLUS_CREATOR)) { | 69 | entry.file.user_info.fdCreator == cpu_to_be32(HFSP_HFSPLUS_CREATOR) && |
70 | (entry.file.create_date == HFSPLUS_I(HFSPLUS_SB(sb).hidden_dir).create_date || | ||
71 | entry.file.create_date == HFSPLUS_I(sb->s_root->d_inode).create_date) && | ||
72 | HFSPLUS_SB(sb).hidden_dir) { | ||
70 | struct qstr str; | 73 | struct qstr str; |
71 | char name[32]; | 74 | char name[32]; |
72 | 75 | ||
73 | if (dentry->d_fsdata) { | 76 | if (dentry->d_fsdata) { |
74 | err = -ENOENT; | 77 | /* |
75 | inode = NULL; | 78 | * We found a link pointing to another link, |
76 | goto out; | 79 | * so ignore it and treat it as regular file. |
80 | */ | ||
81 | cnid = (unsigned long)dentry->d_fsdata; | ||
82 | linkid = 0; | ||
83 | } else { | ||
84 | dentry->d_fsdata = (void *)(unsigned long)cnid; | ||
85 | linkid = be32_to_cpu(entry.file.permissions.dev); | ||
86 | str.len = sprintf(name, "iNode%d", linkid); | ||
87 | str.name = name; | ||
88 | hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_SB(sb).hidden_dir->i_ino, &str); | ||
89 | goto again; | ||
77 | } | 90 | } |
78 | dentry->d_fsdata = (void *)(unsigned long)cnid; | ||
79 | linkid = be32_to_cpu(entry.file.permissions.dev); | ||
80 | str.len = sprintf(name, "iNode%d", linkid); | ||
81 | str.name = name; | ||
82 | hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_SB(sb).hidden_dir->i_ino, &str); | ||
83 | goto again; | ||
84 | } else if (!dentry->d_fsdata) | 91 | } else if (!dentry->d_fsdata) |
85 | dentry->d_fsdata = (void *)(unsigned long)cnid; | 92 | dentry->d_fsdata = (void *)(unsigned long)cnid; |
86 | } else { | 93 | } else { |
87 | printk("HFS+-fs: Illegal catalog entry type in lookup\n"); | 94 | printk(KERN_ERR "hfs: invalid catalog entry type in lookup\n"); |
88 | err = -EIO; | 95 | err = -EIO; |
89 | goto fail; | 96 | goto fail; |
90 | } | 97 | } |
@@ -132,12 +139,12 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
132 | case 1: | 139 | case 1: |
133 | hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); | 140 | hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); |
134 | if (be16_to_cpu(entry.type) != HFSPLUS_FOLDER_THREAD) { | 141 | if (be16_to_cpu(entry.type) != HFSPLUS_FOLDER_THREAD) { |
135 | printk("HFS+-fs: bad catalog folder thread\n"); | 142 | printk(KERN_ERR "hfs: bad catalog folder thread\n"); |
136 | err = -EIO; | 143 | err = -EIO; |
137 | goto out; | 144 | goto out; |
138 | } | 145 | } |
139 | if (fd.entrylength < HFSPLUS_MIN_THREAD_SZ) { | 146 | if (fd.entrylength < HFSPLUS_MIN_THREAD_SZ) { |
140 | printk("HFS+-fs: truncated catalog thread\n"); | 147 | printk(KERN_ERR "hfs: truncated catalog thread\n"); |
141 | err = -EIO; | 148 | err = -EIO; |
142 | goto out; | 149 | goto out; |
143 | } | 150 | } |
@@ -156,7 +163,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
156 | 163 | ||
157 | for (;;) { | 164 | for (;;) { |
158 | if (be32_to_cpu(fd.key->cat.parent) != inode->i_ino) { | 165 | if (be32_to_cpu(fd.key->cat.parent) != inode->i_ino) { |
159 | printk("HFS+-fs: walked past end of dir\n"); | 166 | printk(KERN_ERR "hfs: walked past end of dir\n"); |
160 | err = -EIO; | 167 | err = -EIO; |
161 | goto out; | 168 | goto out; |
162 | } | 169 | } |
@@ -168,7 +175,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
168 | goto out; | 175 | goto out; |
169 | if (type == HFSPLUS_FOLDER) { | 176 | if (type == HFSPLUS_FOLDER) { |
170 | if (fd.entrylength < sizeof(struct hfsplus_cat_folder)) { | 177 | if (fd.entrylength < sizeof(struct hfsplus_cat_folder)) { |
171 | printk("HFS+-fs: small dir entry\n"); | 178 | printk(KERN_ERR "hfs: small dir entry\n"); |
172 | err = -EIO; | 179 | err = -EIO; |
173 | goto out; | 180 | goto out; |
174 | } | 181 | } |
@@ -180,7 +187,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
180 | break; | 187 | break; |
181 | } else if (type == HFSPLUS_FILE) { | 188 | } else if (type == HFSPLUS_FILE) { |
182 | if (fd.entrylength < sizeof(struct hfsplus_cat_file)) { | 189 | if (fd.entrylength < sizeof(struct hfsplus_cat_file)) { |
183 | printk("HFS+-fs: small file entry\n"); | 190 | printk(KERN_ERR "hfs: small file entry\n"); |
184 | err = -EIO; | 191 | err = -EIO; |
185 | goto out; | 192 | goto out; |
186 | } | 193 | } |
@@ -188,7 +195,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
188 | be32_to_cpu(entry.file.id), DT_REG)) | 195 | be32_to_cpu(entry.file.id), DT_REG)) |
189 | break; | 196 | break; |
190 | } else { | 197 | } else { |
191 | printk("HFS+-fs: bad catalog entry type\n"); | 198 | printk(KERN_ERR "hfs: bad catalog entry type\n"); |
192 | err = -EIO; | 199 | err = -EIO; |
193 | goto out; | 200 | goto out; |
194 | } | 201 | } |
@@ -330,7 +337,8 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) | |||
330 | if (res) | 337 | if (res) |
331 | return res; | 338 | return res; |
332 | 339 | ||
333 | inode->i_nlink--; | 340 | if (inode->i_nlink > 0) |
341 | inode->i_nlink--; | ||
334 | hfsplus_delete_inode(inode); | 342 | hfsplus_delete_inode(inode); |
335 | if (inode->i_ino != cnid && !inode->i_nlink) { | 343 | if (inode->i_ino != cnid && !inode->i_nlink) { |
336 | if (!atomic_read(&HFSPLUS_I(inode).opencnt)) { | 344 | if (!atomic_read(&HFSPLUS_I(inode).opencnt)) { |
@@ -339,7 +347,8 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry) | |||
339 | hfsplus_delete_inode(inode); | 347 | hfsplus_delete_inode(inode); |
340 | } else | 348 | } else |
341 | inode->i_flags |= S_DEAD; | 349 | inode->i_flags |= S_DEAD; |
342 | } | 350 | } else |
351 | inode->i_nlink = 0; | ||
343 | inode->i_ctime = CURRENT_TIME_SEC; | 352 | inode->i_ctime = CURRENT_TIME_SEC; |
344 | mark_inode_dirty(inode); | 353 | mark_inode_dirty(inode); |
345 | 354 | ||
diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c index e3ff56a03011..1a7480089e82 100644 --- a/fs/hfsplus/extents.c +++ b/fs/hfsplus/extents.c | |||
@@ -16,7 +16,8 @@ | |||
16 | #include "hfsplus_raw.h" | 16 | #include "hfsplus_raw.h" |
17 | 17 | ||
18 | /* Compare two extents keys, returns 0 on same, pos/neg for difference */ | 18 | /* Compare two extents keys, returns 0 on same, pos/neg for difference */ |
19 | int hfsplus_ext_cmp_key(hfsplus_btree_key *k1, hfsplus_btree_key *k2) | 19 | int hfsplus_ext_cmp_key(const hfsplus_btree_key *k1, |
20 | const hfsplus_btree_key *k2) | ||
20 | { | 21 | { |
21 | __be32 k1id, k2id; | 22 | __be32 k1id, k2id; |
22 | __be32 k1s, k2s; | 23 | __be32 k1s, k2s; |
@@ -349,10 +350,9 @@ int hfsplus_file_extend(struct inode *inode) | |||
349 | 350 | ||
350 | if (HFSPLUS_SB(sb).alloc_file->i_size * 8 < HFSPLUS_SB(sb).total_blocks - HFSPLUS_SB(sb).free_blocks + 8) { | 351 | if (HFSPLUS_SB(sb).alloc_file->i_size * 8 < HFSPLUS_SB(sb).total_blocks - HFSPLUS_SB(sb).free_blocks + 8) { |
351 | // extend alloc file | 352 | // extend alloc file |
352 | printk("extend alloc file! (%Lu,%u,%u)\n", HFSPLUS_SB(sb).alloc_file->i_size * 8, | 353 | printk(KERN_ERR "hfs: extend alloc file! (%Lu,%u,%u)\n", HFSPLUS_SB(sb).alloc_file->i_size * 8, |
353 | HFSPLUS_SB(sb).total_blocks, HFSPLUS_SB(sb).free_blocks); | 354 | HFSPLUS_SB(sb).total_blocks, HFSPLUS_SB(sb).free_blocks); |
354 | return -ENOSPC; | 355 | return -ENOSPC; |
355 | //BUG(); | ||
356 | } | 356 | } |
357 | 357 | ||
358 | down(&HFSPLUS_I(inode).extents_lock); | 358 | down(&HFSPLUS_I(inode).extents_lock); |
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index 0fa1ab6250bf..7ae393637a0c 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h | |||
@@ -36,7 +36,7 @@ | |||
36 | #define HFSPLUS_TYPE_DATA 0x00 | 36 | #define HFSPLUS_TYPE_DATA 0x00 |
37 | #define HFSPLUS_TYPE_RSRC 0xFF | 37 | #define HFSPLUS_TYPE_RSRC 0xFF |
38 | 38 | ||
39 | typedef int (*btree_keycmp)(hfsplus_btree_key *, hfsplus_btree_key *); | 39 | typedef int (*btree_keycmp)(const hfsplus_btree_key *, const hfsplus_btree_key *); |
40 | 40 | ||
41 | #define NODE_HASH_SIZE 256 | 41 | #define NODE_HASH_SIZE 256 |
42 | 42 | ||
@@ -149,6 +149,7 @@ struct hfsplus_sb_info { | |||
149 | #define HFSPLUS_SB_WRITEBACKUP 0x0001 | 149 | #define HFSPLUS_SB_WRITEBACKUP 0x0001 |
150 | #define HFSPLUS_SB_NODECOMPOSE 0x0002 | 150 | #define HFSPLUS_SB_NODECOMPOSE 0x0002 |
151 | #define HFSPLUS_SB_FORCE 0x0004 | 151 | #define HFSPLUS_SB_FORCE 0x0004 |
152 | #define HFSPLUS_SB_HFSX 0x0008 | ||
152 | 153 | ||
153 | 154 | ||
154 | struct hfsplus_inode_info { | 155 | struct hfsplus_inode_info { |
@@ -165,6 +166,7 @@ struct hfsplus_inode_info { | |||
165 | struct inode *rsrc_inode; | 166 | struct inode *rsrc_inode; |
166 | unsigned long flags; | 167 | unsigned long flags; |
167 | 168 | ||
169 | __be32 create_date; | ||
168 | /* Device number in hfsplus_permissions in catalog */ | 170 | /* Device number in hfsplus_permissions in catalog */ |
169 | u32 dev; | 171 | u32 dev; |
170 | /* BSD system and user file flags */ | 172 | /* BSD system and user file flags */ |
@@ -303,7 +305,8 @@ int hfs_brec_read(struct hfs_find_data *, void *, int); | |||
303 | int hfs_brec_goto(struct hfs_find_data *, int); | 305 | int hfs_brec_goto(struct hfs_find_data *, int); |
304 | 306 | ||
305 | /* catalog.c */ | 307 | /* catalog.c */ |
306 | int hfsplus_cat_cmp_key(hfsplus_btree_key *, hfsplus_btree_key *); | 308 | int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); |
309 | int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); | ||
307 | void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *, u32, struct qstr *); | 310 | void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *, u32, struct qstr *); |
308 | int hfsplus_find_cat(struct super_block *, u32, struct hfs_find_data *); | 311 | int hfsplus_find_cat(struct super_block *, u32, struct hfs_find_data *); |
309 | int hfsplus_create_cat(u32, struct inode *, struct qstr *, struct inode *); | 312 | int hfsplus_create_cat(u32, struct inode *, struct qstr *, struct inode *); |
@@ -312,7 +315,7 @@ int hfsplus_rename_cat(u32, struct inode *, struct qstr *, | |||
312 | struct inode *, struct qstr *); | 315 | struct inode *, struct qstr *); |
313 | 316 | ||
314 | /* extents.c */ | 317 | /* extents.c */ |
315 | int hfsplus_ext_cmp_key(hfsplus_btree_key *, hfsplus_btree_key *); | 318 | int hfsplus_ext_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); |
316 | void hfsplus_ext_write_extent(struct inode *); | 319 | void hfsplus_ext_write_extent(struct inode *); |
317 | int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int); | 320 | int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int); |
318 | int hfsplus_free_fork(struct super_block *, u32, struct hfsplus_fork_raw *, int); | 321 | int hfsplus_free_fork(struct super_block *, u32, struct hfsplus_fork_raw *, int); |
@@ -350,7 +353,8 @@ extern u16 hfsplus_decompose_table[]; | |||
350 | extern u16 hfsplus_compose_table[]; | 353 | extern u16 hfsplus_compose_table[]; |
351 | 354 | ||
352 | /* unicode.c */ | 355 | /* unicode.c */ |
353 | int hfsplus_unistrcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); | 356 | int hfsplus_strcasecmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); |
357 | int hfsplus_strcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); | ||
354 | int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *); | 358 | int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *); |
355 | int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int); | 359 | int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int); |
356 | 360 | ||
diff --git a/fs/hfsplus/hfsplus_raw.h b/fs/hfsplus/hfsplus_raw.h index b4fbed633219..49205531a500 100644 --- a/fs/hfsplus/hfsplus_raw.h +++ b/fs/hfsplus/hfsplus_raw.h | |||
@@ -22,8 +22,10 @@ | |||
22 | #define HFSPLUS_SECTOR_SHIFT 9 | 22 | #define HFSPLUS_SECTOR_SHIFT 9 |
23 | #define HFSPLUS_VOLHEAD_SECTOR 2 | 23 | #define HFSPLUS_VOLHEAD_SECTOR 2 |
24 | #define HFSPLUS_VOLHEAD_SIG 0x482b | 24 | #define HFSPLUS_VOLHEAD_SIG 0x482b |
25 | #define HFSPLUS_VOLHEAD_SIGX 0x4858 | ||
25 | #define HFSPLUS_SUPER_MAGIC 0x482b | 26 | #define HFSPLUS_SUPER_MAGIC 0x482b |
26 | #define HFSPLUS_CURRENT_VERSION 4 | 27 | #define HFSPLUS_MIN_VERSION 4 |
28 | #define HFSPLUS_CURRENT_VERSION 5 | ||
27 | 29 | ||
28 | #define HFSP_WRAP_MAGIC 0x4244 | 30 | #define HFSP_WRAP_MAGIC 0x4244 |
29 | #define HFSP_WRAP_ATTRIB_SLOCK 0x8000 | 31 | #define HFSP_WRAP_ATTRIB_SLOCK 0x8000 |
@@ -41,6 +43,9 @@ | |||
41 | #define HFSP_HARDLINK_TYPE 0x686c6e6b /* 'hlnk' */ | 43 | #define HFSP_HARDLINK_TYPE 0x686c6e6b /* 'hlnk' */ |
42 | #define HFSP_HFSPLUS_CREATOR 0x6866732b /* 'hfs+' */ | 44 | #define HFSP_HFSPLUS_CREATOR 0x6866732b /* 'hfs+' */ |
43 | 45 | ||
46 | #define HFSP_SYMLINK_TYPE 0x736c6e6b /* 'slnk' */ | ||
47 | #define HFSP_SYMLINK_CREATOR 0x72686170 /* 'rhap' */ | ||
48 | |||
44 | #define HFSP_MOUNT_VERSION 0x482b4c78 /* 'H+Lx' */ | 49 | #define HFSP_MOUNT_VERSION 0x482b4c78 /* 'H+Lx' */ |
45 | 50 | ||
46 | /* Structures used on disk */ | 51 | /* Structures used on disk */ |
@@ -161,7 +166,7 @@ struct hfs_btree_header_rec { | |||
161 | u16 reserved1; | 166 | u16 reserved1; |
162 | __be32 clump_size; | 167 | __be32 clump_size; |
163 | u8 btree_type; | 168 | u8 btree_type; |
164 | u8 reserved2; | 169 | u8 key_type; |
165 | __be32 attributes; | 170 | __be32 attributes; |
166 | u32 reserved3[16]; | 171 | u32 reserved3[16]; |
167 | } __packed; | 172 | } __packed; |
@@ -186,6 +191,10 @@ struct hfs_btree_header_rec { | |||
186 | #define HFSPLUS_EXCH_CNID 15 /* ExchangeFiles temp id */ | 191 | #define HFSPLUS_EXCH_CNID 15 /* ExchangeFiles temp id */ |
187 | #define HFSPLUS_FIRSTUSER_CNID 16 /* first available user id */ | 192 | #define HFSPLUS_FIRSTUSER_CNID 16 /* first available user id */ |
188 | 193 | ||
194 | /* btree key type */ | ||
195 | #define HFSPLUS_KEY_CASEFOLDING 0xCF /* case-insensitive */ | ||
196 | #define HFSPLUS_KEY_BINARY 0xBC /* case-sensitive */ | ||
197 | |||
189 | /* HFS+ catalog entry key */ | 198 | /* HFS+ catalog entry key */ |
190 | struct hfsplus_cat_key { | 199 | struct hfsplus_cat_key { |
191 | __be16 key_len; | 200 | __be16 key_len; |
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 7acff6c5464f..12ed2b7d046b 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c | |||
@@ -18,13 +18,11 @@ | |||
18 | 18 | ||
19 | static int hfsplus_readpage(struct file *file, struct page *page) | 19 | static int hfsplus_readpage(struct file *file, struct page *page) |
20 | { | 20 | { |
21 | //printk("readpage: %lu\n", page->index); | ||
22 | return block_read_full_page(page, hfsplus_get_block); | 21 | return block_read_full_page(page, hfsplus_get_block); |
23 | } | 22 | } |
24 | 23 | ||
25 | static int hfsplus_writepage(struct page *page, struct writeback_control *wbc) | 24 | static int hfsplus_writepage(struct page *page, struct writeback_control *wbc) |
26 | { | 25 | { |
27 | //printk("writepage: %lu\n", page->index); | ||
28 | return block_write_full_page(page, hfsplus_get_block, wbc); | 26 | return block_write_full_page(page, hfsplus_get_block, wbc); |
29 | } | 27 | } |
30 | 28 | ||
@@ -92,7 +90,6 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask) | |||
92 | } while (--i && nidx < tree->node_count); | 90 | } while (--i && nidx < tree->node_count); |
93 | spin_unlock(&tree->hash_lock); | 91 | spin_unlock(&tree->hash_lock); |
94 | } | 92 | } |
95 | //printk("releasepage: %lu,%x = %d\n", page->index, mask, res); | ||
96 | return res ? try_to_free_buffers(page) : 0; | 93 | return res ? try_to_free_buffers(page) : 0; |
97 | } | 94 | } |
98 | 95 | ||
@@ -434,7 +431,8 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd) | |||
434 | inode->i_size = 2 + be32_to_cpu(folder->valence); | 431 | inode->i_size = 2 + be32_to_cpu(folder->valence); |
435 | inode->i_atime = hfsp_mt2ut(folder->access_date); | 432 | inode->i_atime = hfsp_mt2ut(folder->access_date); |
436 | inode->i_mtime = hfsp_mt2ut(folder->content_mod_date); | 433 | inode->i_mtime = hfsp_mt2ut(folder->content_mod_date); |
437 | inode->i_ctime = inode->i_mtime; | 434 | inode->i_ctime = hfsp_mt2ut(folder->attribute_mod_date); |
435 | HFSPLUS_I(inode).create_date = folder->create_date; | ||
438 | HFSPLUS_I(inode).fs_blocks = 0; | 436 | HFSPLUS_I(inode).fs_blocks = 0; |
439 | inode->i_op = &hfsplus_dir_inode_operations; | 437 | inode->i_op = &hfsplus_dir_inode_operations; |
440 | inode->i_fop = &hfsplus_dir_operations; | 438 | inode->i_fop = &hfsplus_dir_operations; |
@@ -465,9 +463,10 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd) | |||
465 | } | 463 | } |
466 | inode->i_atime = hfsp_mt2ut(file->access_date); | 464 | inode->i_atime = hfsp_mt2ut(file->access_date); |
467 | inode->i_mtime = hfsp_mt2ut(file->content_mod_date); | 465 | inode->i_mtime = hfsp_mt2ut(file->content_mod_date); |
468 | inode->i_ctime = inode->i_mtime; | 466 | inode->i_ctime = hfsp_mt2ut(file->attribute_mod_date); |
467 | HFSPLUS_I(inode).create_date = file->create_date; | ||
469 | } else { | 468 | } else { |
470 | printk("HFS+-fs: bad catalog entry used to create inode\n"); | 469 | printk(KERN_ERR "hfs: bad catalog entry used to create inode\n"); |
471 | res = -EIO; | 470 | res = -EIO; |
472 | } | 471 | } |
473 | return res; | 472 | return res; |
diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c index 935dafba0078..dc64fac00831 100644 --- a/fs/hfsplus/options.c +++ b/fs/hfsplus/options.c | |||
@@ -83,58 +83,58 @@ int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi) | |||
83 | switch (token) { | 83 | switch (token) { |
84 | case opt_creator: | 84 | case opt_creator: |
85 | if (match_fourchar(&args[0], &sbi->creator)) { | 85 | if (match_fourchar(&args[0], &sbi->creator)) { |
86 | printk("HFS+-fs: creator requires a 4 character value\n"); | 86 | printk(KERN_ERR "hfs: creator requires a 4 character value\n"); |
87 | return 0; | 87 | return 0; |
88 | } | 88 | } |
89 | break; | 89 | break; |
90 | case opt_type: | 90 | case opt_type: |
91 | if (match_fourchar(&args[0], &sbi->type)) { | 91 | if (match_fourchar(&args[0], &sbi->type)) { |
92 | printk("HFS+-fs: type requires a 4 character value\n"); | 92 | printk(KERN_ERR "hfs: type requires a 4 character value\n"); |
93 | return 0; | 93 | return 0; |
94 | } | 94 | } |
95 | break; | 95 | break; |
96 | case opt_umask: | 96 | case opt_umask: |
97 | if (match_octal(&args[0], &tmp)) { | 97 | if (match_octal(&args[0], &tmp)) { |
98 | printk("HFS+-fs: umask requires a value\n"); | 98 | printk(KERN_ERR "hfs: umask requires a value\n"); |
99 | return 0; | 99 | return 0; |
100 | } | 100 | } |
101 | sbi->umask = (umode_t)tmp; | 101 | sbi->umask = (umode_t)tmp; |
102 | break; | 102 | break; |
103 | case opt_uid: | 103 | case opt_uid: |
104 | if (match_int(&args[0], &tmp)) { | 104 | if (match_int(&args[0], &tmp)) { |
105 | printk("HFS+-fs: uid requires an argument\n"); | 105 | printk(KERN_ERR "hfs: uid requires an argument\n"); |
106 | return 0; | 106 | return 0; |
107 | } | 107 | } |
108 | sbi->uid = (uid_t)tmp; | 108 | sbi->uid = (uid_t)tmp; |
109 | break; | 109 | break; |
110 | case opt_gid: | 110 | case opt_gid: |
111 | if (match_int(&args[0], &tmp)) { | 111 | if (match_int(&args[0], &tmp)) { |
112 | printk("HFS+-fs: gid requires an argument\n"); | 112 | printk(KERN_ERR "hfs: gid requires an argument\n"); |
113 | return 0; | 113 | return 0; |
114 | } | 114 | } |
115 | sbi->gid = (gid_t)tmp; | 115 | sbi->gid = (gid_t)tmp; |
116 | break; | 116 | break; |
117 | case opt_part: | 117 | case opt_part: |
118 | if (match_int(&args[0], &sbi->part)) { | 118 | if (match_int(&args[0], &sbi->part)) { |
119 | printk("HFS+-fs: part requires an argument\n"); | 119 | printk(KERN_ERR "hfs: part requires an argument\n"); |
120 | return 0; | 120 | return 0; |
121 | } | 121 | } |
122 | break; | 122 | break; |
123 | case opt_session: | 123 | case opt_session: |
124 | if (match_int(&args[0], &sbi->session)) { | 124 | if (match_int(&args[0], &sbi->session)) { |
125 | printk("HFS+-fs: session requires an argument\n"); | 125 | printk(KERN_ERR "hfs: session requires an argument\n"); |
126 | return 0; | 126 | return 0; |
127 | } | 127 | } |
128 | break; | 128 | break; |
129 | case opt_nls: | 129 | case opt_nls: |
130 | if (sbi->nls) { | 130 | if (sbi->nls) { |
131 | printk("HFS+-fs: unable to change nls mapping\n"); | 131 | printk(KERN_ERR "hfs: unable to change nls mapping\n"); |
132 | return 0; | 132 | return 0; |
133 | } | 133 | } |
134 | p = match_strdup(&args[0]); | 134 | p = match_strdup(&args[0]); |
135 | sbi->nls = load_nls(p); | 135 | sbi->nls = load_nls(p); |
136 | if (!sbi->nls) { | 136 | if (!sbi->nls) { |
137 | printk("HFS+-fs: unable to load nls mapping \"%s\"\n", p); | 137 | printk(KERN_ERR "hfs: unable to load nls mapping \"%s\"\n", p); |
138 | kfree(p); | 138 | kfree(p); |
139 | return 0; | 139 | return 0; |
140 | } | 140 | } |
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index d791780def50..7843f792a4b7 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c | |||
@@ -169,7 +169,7 @@ static void hfsplus_write_super(struct super_block *sb) | |||
169 | block = HFSPLUS_SB(sb).blockoffset; | 169 | block = HFSPLUS_SB(sb).blockoffset; |
170 | block += (HFSPLUS_SB(sb).sect_count - 2) >> (sb->s_blocksize_bits - 9); | 170 | block += (HFSPLUS_SB(sb).sect_count - 2) >> (sb->s_blocksize_bits - 9); |
171 | offset = ((HFSPLUS_SB(sb).sect_count - 2) << 9) & (sb->s_blocksize - 1); | 171 | offset = ((HFSPLUS_SB(sb).sect_count - 2) << 9) & (sb->s_blocksize - 1); |
172 | printk("backup: %u,%u,%u,%u\n", HFSPLUS_SB(sb).blockoffset, | 172 | printk(KERN_DEBUG "hfs: backup: %u,%u,%u,%u\n", HFSPLUS_SB(sb).blockoffset, |
173 | HFSPLUS_SB(sb).sect_count, block, offset); | 173 | HFSPLUS_SB(sb).sect_count, block, offset); |
174 | bh = sb_bread(sb, block); | 174 | bh = sb_bread(sb, block); |
175 | if (bh) { | 175 | if (bh) { |
@@ -179,7 +179,7 @@ static void hfsplus_write_super(struct super_block *sb) | |||
179 | mark_buffer_dirty(bh); | 179 | mark_buffer_dirty(bh); |
180 | brelse(bh); | 180 | brelse(bh); |
181 | } else | 181 | } else |
182 | printk("backup not found!\n"); | 182 | printk(KERN_WARNING "hfs: backup not found!\n"); |
183 | } | 183 | } |
184 | } | 184 | } |
185 | HFSPLUS_SB(sb).flags &= ~HFSPLUS_SB_WRITEBACKUP; | 185 | HFSPLUS_SB(sb).flags &= ~HFSPLUS_SB_WRITEBACKUP; |
@@ -240,18 +240,18 @@ static int hfsplus_remount(struct super_block *sb, int *flags, char *data) | |||
240 | return -EINVAL; | 240 | return -EINVAL; |
241 | 241 | ||
242 | if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { | 242 | if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { |
243 | printk("HFS+-fs warning: Filesystem was not cleanly unmounted, " | 243 | printk(KERN_WARNING "hfs: filesystem was not cleanly unmounted, " |
244 | "running fsck.hfsplus is recommended. leaving read-only.\n"); | 244 | "running fsck.hfsplus is recommended. leaving read-only.\n"); |
245 | sb->s_flags |= MS_RDONLY; | 245 | sb->s_flags |= MS_RDONLY; |
246 | *flags |= MS_RDONLY; | 246 | *flags |= MS_RDONLY; |
247 | } else if (sbi.flags & HFSPLUS_SB_FORCE) { | 247 | } else if (sbi.flags & HFSPLUS_SB_FORCE) { |
248 | /* nothing */ | 248 | /* nothing */ |
249 | } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { | 249 | } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { |
250 | printk("HFS+-fs: Filesystem is marked locked, leaving read-only.\n"); | 250 | printk(KERN_WARNING "hfs: filesystem is marked locked, leaving read-only.\n"); |
251 | sb->s_flags |= MS_RDONLY; | 251 | sb->s_flags |= MS_RDONLY; |
252 | *flags |= MS_RDONLY; | 252 | *flags |= MS_RDONLY; |
253 | } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) { | 253 | } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) { |
254 | printk("HFS+-fs: Filesystem is marked journaled, leaving read-only.\n"); | 254 | printk(KERN_WARNING "hfs: filesystem is marked journaled, leaving read-only.\n"); |
255 | sb->s_flags |= MS_RDONLY; | 255 | sb->s_flags |= MS_RDONLY; |
256 | *flags |= MS_RDONLY; | 256 | *flags |= MS_RDONLY; |
257 | } | 257 | } |
@@ -292,8 +292,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
292 | INIT_HLIST_HEAD(&sbi->rsrc_inodes); | 292 | INIT_HLIST_HEAD(&sbi->rsrc_inodes); |
293 | hfsplus_fill_defaults(sbi); | 293 | hfsplus_fill_defaults(sbi); |
294 | if (!hfsplus_parse_options(data, sbi)) { | 294 | if (!hfsplus_parse_options(data, sbi)) { |
295 | if (!silent) | 295 | printk(KERN_ERR "hfs: unable to parse mount options\n"); |
296 | printk("HFS+-fs: unable to parse mount options\n"); | ||
297 | err = -EINVAL; | 296 | err = -EINVAL; |
298 | goto cleanup; | 297 | goto cleanup; |
299 | } | 298 | } |
@@ -302,7 +301,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
302 | nls = sbi->nls; | 301 | nls = sbi->nls; |
303 | sbi->nls = load_nls("utf8"); | 302 | sbi->nls = load_nls("utf8"); |
304 | if (!sbi->nls) { | 303 | if (!sbi->nls) { |
305 | printk("HFS+: unable to load nls for utf8\n"); | 304 | printk(KERN_ERR "hfs: unable to load nls for utf8\n"); |
306 | err = -EINVAL; | 305 | err = -EINVAL; |
307 | goto cleanup; | 306 | goto cleanup; |
308 | } | 307 | } |
@@ -310,17 +309,17 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
310 | /* Grab the volume header */ | 309 | /* Grab the volume header */ |
311 | if (hfsplus_read_wrapper(sb)) { | 310 | if (hfsplus_read_wrapper(sb)) { |
312 | if (!silent) | 311 | if (!silent) |
313 | printk("HFS+-fs: unable to find HFS+ superblock\n"); | 312 | printk(KERN_WARNING "hfs: unable to find HFS+ superblock\n"); |
314 | err = -EINVAL; | 313 | err = -EINVAL; |
315 | goto cleanup; | 314 | goto cleanup; |
316 | } | 315 | } |
317 | vhdr = HFSPLUS_SB(sb).s_vhdr; | 316 | vhdr = HFSPLUS_SB(sb).s_vhdr; |
318 | 317 | ||
319 | /* Copy parts of the volume header into the superblock */ | 318 | /* Copy parts of the volume header into the superblock */ |
320 | sb->s_magic = be16_to_cpu(vhdr->signature); | 319 | sb->s_magic = HFSPLUS_VOLHEAD_SIG; |
321 | if (be16_to_cpu(vhdr->version) != HFSPLUS_CURRENT_VERSION) { | 320 | if (be16_to_cpu(vhdr->version) < HFSPLUS_MIN_VERSION || |
322 | if (!silent) | 321 | be16_to_cpu(vhdr->version) > HFSPLUS_CURRENT_VERSION) { |
323 | printk("HFS+-fs: wrong filesystem version\n"); | 322 | printk(KERN_ERR "hfs: wrong filesystem version\n"); |
324 | goto cleanup; | 323 | goto cleanup; |
325 | } | 324 | } |
326 | HFSPLUS_SB(sb).total_blocks = be32_to_cpu(vhdr->total_blocks); | 325 | HFSPLUS_SB(sb).total_blocks = be32_to_cpu(vhdr->total_blocks); |
@@ -341,20 +340,17 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
341 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 340 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
342 | 341 | ||
343 | if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { | 342 | if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { |
344 | if (!silent) | 343 | printk(KERN_WARNING "hfs: Filesystem was not cleanly unmounted, " |
345 | printk("HFS+-fs warning: Filesystem was not cleanly unmounted, " | 344 | "running fsck.hfsplus is recommended. mounting read-only.\n"); |
346 | "running fsck.hfsplus is recommended. mounting read-only.\n"); | ||
347 | sb->s_flags |= MS_RDONLY; | 345 | sb->s_flags |= MS_RDONLY; |
348 | } else if (sbi->flags & HFSPLUS_SB_FORCE) { | 346 | } else if (sbi->flags & HFSPLUS_SB_FORCE) { |
349 | /* nothing */ | 347 | /* nothing */ |
350 | } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { | 348 | } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { |
351 | if (!silent) | 349 | printk(KERN_WARNING "hfs: Filesystem is marked locked, mounting read-only.\n"); |
352 | printk("HFS+-fs: Filesystem is marked locked, mounting read-only.\n"); | ||
353 | sb->s_flags |= MS_RDONLY; | 350 | sb->s_flags |= MS_RDONLY; |
354 | } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) { | 351 | } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) { |
355 | if (!silent) | 352 | printk(KERN_WARNING "hfs: write access to a jounaled filesystem is not supported, " |
356 | printk("HFS+-fs: write access to a jounaled filesystem is not supported, " | 353 | "use the force option at your own risk, mounting read-only.\n"); |
357 | "use the force option at your own risk, mounting read-only.\n"); | ||
358 | sb->s_flags |= MS_RDONLY; | 354 | sb->s_flags |= MS_RDONLY; |
359 | } | 355 | } |
360 | sbi->flags &= ~HFSPLUS_SB_FORCE; | 356 | sbi->flags &= ~HFSPLUS_SB_FORCE; |
@@ -362,21 +358,18 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
362 | /* Load metadata objects (B*Trees) */ | 358 | /* Load metadata objects (B*Trees) */ |
363 | HFSPLUS_SB(sb).ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID); | 359 | HFSPLUS_SB(sb).ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID); |
364 | if (!HFSPLUS_SB(sb).ext_tree) { | 360 | if (!HFSPLUS_SB(sb).ext_tree) { |
365 | if (!silent) | 361 | printk(KERN_ERR "hfs: failed to load extents file\n"); |
366 | printk("HFS+-fs: failed to load extents file\n"); | ||
367 | goto cleanup; | 362 | goto cleanup; |
368 | } | 363 | } |
369 | HFSPLUS_SB(sb).cat_tree = hfs_btree_open(sb, HFSPLUS_CAT_CNID); | 364 | HFSPLUS_SB(sb).cat_tree = hfs_btree_open(sb, HFSPLUS_CAT_CNID); |
370 | if (!HFSPLUS_SB(sb).cat_tree) { | 365 | if (!HFSPLUS_SB(sb).cat_tree) { |
371 | if (!silent) | 366 | printk(KERN_ERR "hfs: failed to load catalog file\n"); |
372 | printk("HFS+-fs: failed to load catalog file\n"); | ||
373 | goto cleanup; | 367 | goto cleanup; |
374 | } | 368 | } |
375 | 369 | ||
376 | HFSPLUS_SB(sb).alloc_file = iget(sb, HFSPLUS_ALLOC_CNID); | 370 | HFSPLUS_SB(sb).alloc_file = iget(sb, HFSPLUS_ALLOC_CNID); |
377 | if (!HFSPLUS_SB(sb).alloc_file) { | 371 | if (!HFSPLUS_SB(sb).alloc_file) { |
378 | if (!silent) | 372 | printk(KERN_ERR "hfs: failed to load allocation file\n"); |
379 | printk("HFS+-fs: failed to load allocation file\n"); | ||
380 | goto cleanup; | 373 | goto cleanup; |
381 | } | 374 | } |
382 | 375 | ||
@@ -384,8 +377,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
384 | root = iget(sb, HFSPLUS_ROOT_CNID); | 377 | root = iget(sb, HFSPLUS_ROOT_CNID); |
385 | sb->s_root = d_alloc_root(root); | 378 | sb->s_root = d_alloc_root(root); |
386 | if (!sb->s_root) { | 379 | if (!sb->s_root) { |
387 | if (!silent) | 380 | printk(KERN_ERR "hfs: failed to load root directory\n"); |
388 | printk("HFS+-fs: failed to load root directory\n"); | ||
389 | iput(root); | 381 | iput(root); |
390 | goto cleanup; | 382 | goto cleanup; |
391 | } | 383 | } |
@@ -419,7 +411,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
419 | sync_dirty_buffer(HFSPLUS_SB(sb).s_vhbh); | 411 | sync_dirty_buffer(HFSPLUS_SB(sb).s_vhbh); |
420 | 412 | ||
421 | if (!HFSPLUS_SB(sb).hidden_dir) { | 413 | if (!HFSPLUS_SB(sb).hidden_dir) { |
422 | printk("HFS+: create hidden dir...\n"); | 414 | printk(KERN_DEBUG "hfs: create hidden dir...\n"); |
423 | HFSPLUS_SB(sb).hidden_dir = hfsplus_new_inode(sb, S_IFDIR); | 415 | HFSPLUS_SB(sb).hidden_dir = hfsplus_new_inode(sb, S_IFDIR); |
424 | hfsplus_create_cat(HFSPLUS_SB(sb).hidden_dir->i_ino, sb->s_root->d_inode, | 416 | hfsplus_create_cat(HFSPLUS_SB(sb).hidden_dir->i_ino, sb->s_root->d_inode, |
425 | &str, HFSPLUS_SB(sb).hidden_dir); | 417 | &str, HFSPLUS_SB(sb).hidden_dir); |
@@ -499,7 +491,7 @@ static void __exit exit_hfsplus_fs(void) | |||
499 | { | 491 | { |
500 | unregister_filesystem(&hfsplus_fs_type); | 492 | unregister_filesystem(&hfsplus_fs_type); |
501 | if (kmem_cache_destroy(hfsplus_inode_cachep)) | 493 | if (kmem_cache_destroy(hfsplus_inode_cachep)) |
502 | printk(KERN_INFO "hfsplus_inode_cache: not all structures were freed\n"); | 494 | printk(KERN_ERR "hfsplus_inode_cache: not all structures were freed\n"); |
503 | } | 495 | } |
504 | 496 | ||
505 | module_init(init_hfsplus_fs) | 497 | module_init(init_hfsplus_fs) |
diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c index 060c69048c3d..689c8bd721fb 100644 --- a/fs/hfsplus/unicode.c +++ b/fs/hfsplus/unicode.c | |||
@@ -28,7 +28,8 @@ static inline u16 case_fold(u16 c) | |||
28 | } | 28 | } |
29 | 29 | ||
30 | /* Compare unicode strings, return values like normal strcmp */ | 30 | /* Compare unicode strings, return values like normal strcmp */ |
31 | int hfsplus_unistrcmp(const struct hfsplus_unistr *s1, const struct hfsplus_unistr *s2) | 31 | int hfsplus_strcasecmp(const struct hfsplus_unistr *s1, |
32 | const struct hfsplus_unistr *s2) | ||
32 | { | 33 | { |
33 | u16 len1, len2, c1, c2; | 34 | u16 len1, len2, c1, c2; |
34 | const hfsplus_unichr *p1, *p2; | 35 | const hfsplus_unichr *p1, *p2; |
@@ -59,6 +60,33 @@ int hfsplus_unistrcmp(const struct hfsplus_unistr *s1, const struct hfsplus_unis | |||
59 | } | 60 | } |
60 | } | 61 | } |
61 | 62 | ||
63 | /* Compare names as a sequence of 16-bit unsigned integers */ | ||
64 | int hfsplus_strcmp(const struct hfsplus_unistr *s1, | ||
65 | const struct hfsplus_unistr *s2) | ||
66 | { | ||
67 | u16 len1, len2, c1, c2; | ||
68 | const hfsplus_unichr *p1, *p2; | ||
69 | int len; | ||
70 | |||
71 | len1 = be16_to_cpu(s1->length); | ||
72 | len2 = be16_to_cpu(s2->length); | ||
73 | p1 = s1->unicode; | ||
74 | p2 = s2->unicode; | ||
75 | |||
76 | for (len = min(len1, len2); len > 0; len--) { | ||
77 | c1 = be16_to_cpu(*p1); | ||
78 | c2 = be16_to_cpu(*p2); | ||
79 | if (c1 != c2) | ||
80 | return c1 < c2 ? -1 : 1; | ||
81 | p1++; | ||
82 | p2++; | ||
83 | } | ||
84 | |||
85 | return len1 < len2 ? -1 : | ||
86 | len1 > len2 ? 1 : 0; | ||
87 | } | ||
88 | |||
89 | |||
62 | #define Hangul_SBase 0xac00 | 90 | #define Hangul_SBase 0xac00 |
63 | #define Hangul_LBase 0x1100 | 91 | #define Hangul_LBase 0x1100 |
64 | #define Hangul_VBase 0x1161 | 92 | #define Hangul_VBase 0x1161 |
diff --git a/fs/hfsplus/wrapper.c b/fs/hfsplus/wrapper.c index 95455e839231..72cab78f0509 100644 --- a/fs/hfsplus/wrapper.c +++ b/fs/hfsplus/wrapper.c | |||
@@ -28,8 +28,11 @@ static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd) | |||
28 | { | 28 | { |
29 | u32 extent; | 29 | u32 extent; |
30 | u16 attrib; | 30 | u16 attrib; |
31 | __be16 sig; | ||
31 | 32 | ||
32 | if (be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_EMBEDSIG)) != HFSPLUS_VOLHEAD_SIG) | 33 | sig = *(__be16 *)(bufptr + HFSP_WRAPOFF_EMBEDSIG); |
34 | if (sig != cpu_to_be16(HFSPLUS_VOLHEAD_SIG) && | ||
35 | sig != cpu_to_be16(HFSPLUS_VOLHEAD_SIGX)) | ||
33 | return 0; | 36 | return 0; |
34 | 37 | ||
35 | attrib = be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ATTRIB)); | 38 | attrib = be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ATTRIB)); |
@@ -70,7 +73,7 @@ static int hfsplus_get_last_session(struct super_block *sb, | |||
70 | *start = (sector_t)te.cdte_addr.lba << 2; | 73 | *start = (sector_t)te.cdte_addr.lba << 2; |
71 | return 0; | 74 | return 0; |
72 | } | 75 | } |
73 | printk(KERN_ERR "HFS: Invalid session number or type of track\n"); | 76 | printk(KERN_ERR "hfs: invalid session number or type of track\n"); |
74 | return -EINVAL; | 77 | return -EINVAL; |
75 | } | 78 | } |
76 | ms_info.addr_format = CDROM_LBA; | 79 | ms_info.addr_format = CDROM_LBA; |
@@ -114,6 +117,10 @@ int hfsplus_read_wrapper(struct super_block *sb) | |||
114 | } | 117 | } |
115 | if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIG)) | 118 | if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIG)) |
116 | break; | 119 | break; |
120 | if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIGX)) { | ||
121 | HFSPLUS_SB(sb).flags |= HFSPLUS_SB_HFSX; | ||
122 | break; | ||
123 | } | ||
117 | brelse(bh); | 124 | brelse(bh); |
118 | 125 | ||
119 | /* check for a partition block | 126 | /* check for a partition block |
@@ -143,7 +150,7 @@ int hfsplus_read_wrapper(struct super_block *sb) | |||
143 | blocksize >>= 1; | 150 | blocksize >>= 1; |
144 | 151 | ||
145 | if (sb_set_blocksize(sb, blocksize) != blocksize) { | 152 | if (sb_set_blocksize(sb, blocksize) != blocksize) { |
146 | printk("HFS+: unable to blocksize to %u!\n", blocksize); | 153 | printk(KERN_ERR "hfs: unable to set blocksize to %u!\n", blocksize); |
147 | return -EINVAL; | 154 | return -EINVAL; |
148 | } | 155 | } |
149 | 156 | ||
@@ -158,7 +165,9 @@ int hfsplus_read_wrapper(struct super_block *sb) | |||
158 | return -EIO; | 165 | return -EIO; |
159 | 166 | ||
160 | /* should still be the same... */ | 167 | /* should still be the same... */ |
161 | if (be16_to_cpu(vhdr->signature) != HFSPLUS_VOLHEAD_SIG) | 168 | if (vhdr->signature != (HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX ? |
169 | cpu_to_be16(HFSPLUS_VOLHEAD_SIGX) : | ||
170 | cpu_to_be16(HFSPLUS_VOLHEAD_SIG))) | ||
162 | goto error; | 171 | goto error; |
163 | HFSPLUS_SB(sb).s_vhbh = bh; | 172 | HFSPLUS_SB(sb).s_vhbh = bh; |
164 | HFSPLUS_SB(sb).s_vhdr = vhdr; | 173 | HFSPLUS_SB(sb).s_vhdr = vhdr; |
diff --git a/fs/inotify.c b/fs/inotify.c index 2fecb7af4a77..878ccca61213 100644 --- a/fs/inotify.c +++ b/fs/inotify.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/list.h> | 33 | #include <linux/list.h> |
34 | #include <linux/writeback.h> | 34 | #include <linux/writeback.h> |
35 | #include <linux/inotify.h> | 35 | #include <linux/inotify.h> |
36 | #include <linux/syscalls.h> | ||
36 | 37 | ||
37 | #include <asm/ioctls.h> | 38 | #include <asm/ioctls.h> |
38 | 39 | ||
diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c index cb3cef525c3b..e6265a0b56b8 100644 --- a/fs/jbd/checkpoint.c +++ b/fs/jbd/checkpoint.c | |||
@@ -338,7 +338,7 @@ restart: | |||
338 | * done (maybe it's a new transaction, but it fell at the same | 338 | * done (maybe it's a new transaction, but it fell at the same |
339 | * address). | 339 | * address). |
340 | */ | 340 | */ |
341 | if (journal->j_checkpoint_transactions == transaction || | 341 | if (journal->j_checkpoint_transactions == transaction && |
342 | transaction->t_tid == this_tid) { | 342 | transaction->t_tid == this_tid) { |
343 | int batch_count = 0; | 343 | int batch_count = 0; |
344 | struct buffer_head *bhs[NR_BATCH]; | 344 | struct buffer_head *bhs[NR_BATCH]; |
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c index 002ad2bbc769..29e62d98bae6 100644 --- a/fs/jbd/commit.c +++ b/fs/jbd/commit.c | |||
@@ -829,7 +829,8 @@ restart_loop: | |||
829 | journal->j_committing_transaction = NULL; | 829 | journal->j_committing_transaction = NULL; |
830 | spin_unlock(&journal->j_state_lock); | 830 | spin_unlock(&journal->j_state_lock); |
831 | 831 | ||
832 | if (commit_transaction->t_checkpoint_list == NULL) { | 832 | if (commit_transaction->t_checkpoint_list == NULL && |
833 | commit_transaction->t_checkpoint_io_list == NULL) { | ||
833 | __journal_drop_transaction(journal, commit_transaction); | 834 | __journal_drop_transaction(journal, commit_transaction); |
834 | } else { | 835 | } else { |
835 | if (journal->j_checkpoint_transactions == NULL) { | 836 | if (journal->j_checkpoint_transactions == NULL) { |
diff --git a/fs/namei.c b/fs/namei.c index 33fb5bd34a81..4acdac043b6b 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -30,6 +30,8 @@ | |||
30 | #include <linux/audit.h> | 30 | #include <linux/audit.h> |
31 | #include <linux/capability.h> | 31 | #include <linux/capability.h> |
32 | #include <linux/file.h> | 32 | #include <linux/file.h> |
33 | #include <linux/fcntl.h> | ||
34 | #include <linux/namei.h> | ||
33 | #include <asm/namei.h> | 35 | #include <asm/namei.h> |
34 | #include <asm/uaccess.h> | 36 | #include <asm/uaccess.h> |
35 | 37 | ||
@@ -1063,7 +1065,8 @@ set_it: | |||
1063 | } | 1065 | } |
1064 | 1066 | ||
1065 | /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ | 1067 | /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ |
1066 | int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata *nd) | 1068 | static int fastcall do_path_lookup(int dfd, const char *name, |
1069 | unsigned int flags, struct nameidata *nd) | ||
1067 | { | 1070 | { |
1068 | int retval = 0; | 1071 | int retval = 0; |
1069 | 1072 | ||
@@ -1083,9 +1086,38 @@ int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata | |||
1083 | } | 1086 | } |
1084 | nd->mnt = mntget(current->fs->rootmnt); | 1087 | nd->mnt = mntget(current->fs->rootmnt); |
1085 | nd->dentry = dget(current->fs->root); | 1088 | nd->dentry = dget(current->fs->root); |
1086 | } else { | 1089 | } else if (dfd == AT_FDCWD) { |
1087 | nd->mnt = mntget(current->fs->pwdmnt); | 1090 | nd->mnt = mntget(current->fs->pwdmnt); |
1088 | nd->dentry = dget(current->fs->pwd); | 1091 | nd->dentry = dget(current->fs->pwd); |
1092 | } else { | ||
1093 | struct file *file; | ||
1094 | int fput_needed; | ||
1095 | struct dentry *dentry; | ||
1096 | |||
1097 | file = fget_light(dfd, &fput_needed); | ||
1098 | if (!file) { | ||
1099 | retval = -EBADF; | ||
1100 | goto out_fail; | ||
1101 | } | ||
1102 | |||
1103 | dentry = file->f_dentry; | ||
1104 | |||
1105 | if (!S_ISDIR(dentry->d_inode->i_mode)) { | ||
1106 | retval = -ENOTDIR; | ||
1107 | fput_light(file, fput_needed); | ||
1108 | goto out_fail; | ||
1109 | } | ||
1110 | |||
1111 | retval = file_permission(file, MAY_EXEC); | ||
1112 | if (retval) { | ||
1113 | fput_light(file, fput_needed); | ||
1114 | goto out_fail; | ||
1115 | } | ||
1116 | |||
1117 | nd->mnt = mntget(file->f_vfsmnt); | ||
1118 | nd->dentry = dget(dentry); | ||
1119 | |||
1120 | fput_light(file, fput_needed); | ||
1089 | } | 1121 | } |
1090 | read_unlock(¤t->fs->lock); | 1122 | read_unlock(¤t->fs->lock); |
1091 | current->total_link_count = 0; | 1123 | current->total_link_count = 0; |
@@ -1094,11 +1126,19 @@ out: | |||
1094 | if (unlikely(current->audit_context | 1126 | if (unlikely(current->audit_context |
1095 | && nd && nd->dentry && nd->dentry->d_inode)) | 1127 | && nd && nd->dentry && nd->dentry->d_inode)) |
1096 | audit_inode(name, nd->dentry->d_inode, flags); | 1128 | audit_inode(name, nd->dentry->d_inode, flags); |
1129 | out_fail: | ||
1097 | return retval; | 1130 | return retval; |
1098 | } | 1131 | } |
1099 | 1132 | ||
1100 | static int __path_lookup_intent_open(const char *name, unsigned int lookup_flags, | 1133 | int fastcall path_lookup(const char *name, unsigned int flags, |
1101 | struct nameidata *nd, int open_flags, int create_mode) | 1134 | struct nameidata *nd) |
1135 | { | ||
1136 | return do_path_lookup(AT_FDCWD, name, flags, nd); | ||
1137 | } | ||
1138 | |||
1139 | static int __path_lookup_intent_open(int dfd, const char *name, | ||
1140 | unsigned int lookup_flags, struct nameidata *nd, | ||
1141 | int open_flags, int create_mode) | ||
1102 | { | 1142 | { |
1103 | struct file *filp = get_empty_filp(); | 1143 | struct file *filp = get_empty_filp(); |
1104 | int err; | 1144 | int err; |
@@ -1108,7 +1148,7 @@ static int __path_lookup_intent_open(const char *name, unsigned int lookup_flags | |||
1108 | nd->intent.open.file = filp; | 1148 | nd->intent.open.file = filp; |
1109 | nd->intent.open.flags = open_flags; | 1149 | nd->intent.open.flags = open_flags; |
1110 | nd->intent.open.create_mode = create_mode; | 1150 | nd->intent.open.create_mode = create_mode; |
1111 | err = path_lookup(name, lookup_flags|LOOKUP_OPEN, nd); | 1151 | err = do_path_lookup(dfd, name, lookup_flags|LOOKUP_OPEN, nd); |
1112 | if (IS_ERR(nd->intent.open.file)) { | 1152 | if (IS_ERR(nd->intent.open.file)) { |
1113 | if (err == 0) { | 1153 | if (err == 0) { |
1114 | err = PTR_ERR(nd->intent.open.file); | 1154 | err = PTR_ERR(nd->intent.open.file); |
@@ -1126,10 +1166,10 @@ static int __path_lookup_intent_open(const char *name, unsigned int lookup_flags | |||
1126 | * @nd: pointer to nameidata | 1166 | * @nd: pointer to nameidata |
1127 | * @open_flags: open intent flags | 1167 | * @open_flags: open intent flags |
1128 | */ | 1168 | */ |
1129 | int path_lookup_open(const char *name, unsigned int lookup_flags, | 1169 | int path_lookup_open(int dfd, const char *name, unsigned int lookup_flags, |
1130 | struct nameidata *nd, int open_flags) | 1170 | struct nameidata *nd, int open_flags) |
1131 | { | 1171 | { |
1132 | return __path_lookup_intent_open(name, lookup_flags, nd, | 1172 | return __path_lookup_intent_open(dfd, name, lookup_flags, nd, |
1133 | open_flags, 0); | 1173 | open_flags, 0); |
1134 | } | 1174 | } |
1135 | 1175 | ||
@@ -1141,12 +1181,12 @@ int path_lookup_open(const char *name, unsigned int lookup_flags, | |||
1141 | * @open_flags: open intent flags | 1181 | * @open_flags: open intent flags |
1142 | * @create_mode: create intent flags | 1182 | * @create_mode: create intent flags |
1143 | */ | 1183 | */ |
1144 | static int path_lookup_create(const char *name, unsigned int lookup_flags, | 1184 | static int path_lookup_create(int dfd, const char *name, |
1145 | struct nameidata *nd, int open_flags, | 1185 | unsigned int lookup_flags, struct nameidata *nd, |
1146 | int create_mode) | 1186 | int open_flags, int create_mode) |
1147 | { | 1187 | { |
1148 | return __path_lookup_intent_open(name, lookup_flags|LOOKUP_CREATE, nd, | 1188 | return __path_lookup_intent_open(dfd, name, lookup_flags|LOOKUP_CREATE, |
1149 | open_flags, create_mode); | 1189 | nd, open_flags, create_mode); |
1150 | } | 1190 | } |
1151 | 1191 | ||
1152 | int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, | 1192 | int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, |
@@ -1156,7 +1196,7 @@ int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags, | |||
1156 | int err = PTR_ERR(tmp); | 1196 | int err = PTR_ERR(tmp); |
1157 | 1197 | ||
1158 | if (!IS_ERR(tmp)) { | 1198 | if (!IS_ERR(tmp)) { |
1159 | err = __path_lookup_intent_open(tmp, lookup_flags, nd, open_flags, 0); | 1199 | err = __path_lookup_intent_open(AT_FDCWD, tmp, lookup_flags, nd, open_flags, 0); |
1160 | putname(tmp); | 1200 | putname(tmp); |
1161 | } | 1201 | } |
1162 | return err; | 1202 | return err; |
@@ -1248,18 +1288,24 @@ access: | |||
1248 | * that namei follows links, while lnamei does not. | 1288 | * that namei follows links, while lnamei does not. |
1249 | * SMP-safe | 1289 | * SMP-safe |
1250 | */ | 1290 | */ |
1251 | int fastcall __user_walk(const char __user *name, unsigned flags, struct nameidata *nd) | 1291 | int fastcall __user_walk_fd(int dfd, const char __user *name, unsigned flags, |
1292 | struct nameidata *nd) | ||
1252 | { | 1293 | { |
1253 | char *tmp = getname(name); | 1294 | char *tmp = getname(name); |
1254 | int err = PTR_ERR(tmp); | 1295 | int err = PTR_ERR(tmp); |
1255 | 1296 | ||
1256 | if (!IS_ERR(tmp)) { | 1297 | if (!IS_ERR(tmp)) { |
1257 | err = path_lookup(tmp, flags, nd); | 1298 | err = do_path_lookup(dfd, tmp, flags, nd); |
1258 | putname(tmp); | 1299 | putname(tmp); |
1259 | } | 1300 | } |
1260 | return err; | 1301 | return err; |
1261 | } | 1302 | } |
1262 | 1303 | ||
1304 | int fastcall __user_walk(const char __user *name, unsigned flags, struct nameidata *nd) | ||
1305 | { | ||
1306 | return __user_walk_fd(AT_FDCWD, name, flags, nd); | ||
1307 | } | ||
1308 | |||
1263 | /* | 1309 | /* |
1264 | * It's inline, so penalty for filesystems that don't use sticky bit is | 1310 | * It's inline, so penalty for filesystems that don't use sticky bit is |
1265 | * minimal. | 1311 | * minimal. |
@@ -1518,7 +1564,8 @@ int may_open(struct nameidata *nd, int acc_mode, int flag) | |||
1518 | * for symlinks (where the permissions are checked later). | 1564 | * for symlinks (where the permissions are checked later). |
1519 | * SMP-safe | 1565 | * SMP-safe |
1520 | */ | 1566 | */ |
1521 | int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) | 1567 | int open_namei(int dfd, const char *pathname, int flag, |
1568 | int mode, struct nameidata *nd) | ||
1522 | { | 1569 | { |
1523 | int acc_mode, error; | 1570 | int acc_mode, error; |
1524 | struct path path; | 1571 | struct path path; |
@@ -1540,7 +1587,8 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) | |||
1540 | * The simplest case - just a plain lookup. | 1587 | * The simplest case - just a plain lookup. |
1541 | */ | 1588 | */ |
1542 | if (!(flag & O_CREAT)) { | 1589 | if (!(flag & O_CREAT)) { |
1543 | error = path_lookup_open(pathname, lookup_flags(flag), nd, flag); | 1590 | error = path_lookup_open(dfd, pathname, lookup_flags(flag), |
1591 | nd, flag); | ||
1544 | if (error) | 1592 | if (error) |
1545 | return error; | 1593 | return error; |
1546 | goto ok; | 1594 | goto ok; |
@@ -1549,7 +1597,7 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd) | |||
1549 | /* | 1597 | /* |
1550 | * Create - we need to know the parent. | 1598 | * Create - we need to know the parent. |
1551 | */ | 1599 | */ |
1552 | error = path_lookup_create(pathname, LOOKUP_PARENT, nd, flag, mode); | 1600 | error = path_lookup_create(dfd,pathname,LOOKUP_PARENT,nd,flag,mode); |
1553 | if (error) | 1601 | if (error) |
1554 | return error; | 1602 | return error; |
1555 | 1603 | ||
@@ -1744,7 +1792,8 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) | |||
1744 | return error; | 1792 | return error; |
1745 | } | 1793 | } |
1746 | 1794 | ||
1747 | asmlinkage long sys_mknod(const char __user * filename, int mode, unsigned dev) | 1795 | asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode, |
1796 | unsigned dev) | ||
1748 | { | 1797 | { |
1749 | int error = 0; | 1798 | int error = 0; |
1750 | char * tmp; | 1799 | char * tmp; |
@@ -1757,7 +1806,7 @@ asmlinkage long sys_mknod(const char __user * filename, int mode, unsigned dev) | |||
1757 | if (IS_ERR(tmp)) | 1806 | if (IS_ERR(tmp)) |
1758 | return PTR_ERR(tmp); | 1807 | return PTR_ERR(tmp); |
1759 | 1808 | ||
1760 | error = path_lookup(tmp, LOOKUP_PARENT, &nd); | 1809 | error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd); |
1761 | if (error) | 1810 | if (error) |
1762 | goto out; | 1811 | goto out; |
1763 | dentry = lookup_create(&nd, 0); | 1812 | dentry = lookup_create(&nd, 0); |
@@ -1793,6 +1842,11 @@ out: | |||
1793 | return error; | 1842 | return error; |
1794 | } | 1843 | } |
1795 | 1844 | ||
1845 | asmlinkage long sys_mknod(const char __user *filename, int mode, unsigned dev) | ||
1846 | { | ||
1847 | return sys_mknodat(AT_FDCWD, filename, mode, dev); | ||
1848 | } | ||
1849 | |||
1796 | int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | 1850 | int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) |
1797 | { | 1851 | { |
1798 | int error = may_create(dir, dentry, NULL); | 1852 | int error = may_create(dir, dentry, NULL); |
@@ -1815,7 +1869,7 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
1815 | return error; | 1869 | return error; |
1816 | } | 1870 | } |
1817 | 1871 | ||
1818 | asmlinkage long sys_mkdir(const char __user * pathname, int mode) | 1872 | asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, int mode) |
1819 | { | 1873 | { |
1820 | int error = 0; | 1874 | int error = 0; |
1821 | char * tmp; | 1875 | char * tmp; |
@@ -1826,7 +1880,7 @@ asmlinkage long sys_mkdir(const char __user * pathname, int mode) | |||
1826 | struct dentry *dentry; | 1880 | struct dentry *dentry; |
1827 | struct nameidata nd; | 1881 | struct nameidata nd; |
1828 | 1882 | ||
1829 | error = path_lookup(tmp, LOOKUP_PARENT, &nd); | 1883 | error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd); |
1830 | if (error) | 1884 | if (error) |
1831 | goto out; | 1885 | goto out; |
1832 | dentry = lookup_create(&nd, 1); | 1886 | dentry = lookup_create(&nd, 1); |
@@ -1846,6 +1900,11 @@ out: | |||
1846 | return error; | 1900 | return error; |
1847 | } | 1901 | } |
1848 | 1902 | ||
1903 | asmlinkage long sys_mkdir(const char __user *pathname, int mode) | ||
1904 | { | ||
1905 | return sys_mkdirat(AT_FDCWD, pathname, mode); | ||
1906 | } | ||
1907 | |||
1849 | /* | 1908 | /* |
1850 | * We try to drop the dentry early: we should have | 1909 | * We try to drop the dentry early: we should have |
1851 | * a usage count of 2 if we're the only user of this | 1910 | * a usage count of 2 if we're the only user of this |
@@ -1907,7 +1966,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
1907 | return error; | 1966 | return error; |
1908 | } | 1967 | } |
1909 | 1968 | ||
1910 | asmlinkage long sys_rmdir(const char __user * pathname) | 1969 | static long do_rmdir(int dfd, const char __user *pathname) |
1911 | { | 1970 | { |
1912 | int error = 0; | 1971 | int error = 0; |
1913 | char * name; | 1972 | char * name; |
@@ -1918,7 +1977,7 @@ asmlinkage long sys_rmdir(const char __user * pathname) | |||
1918 | if(IS_ERR(name)) | 1977 | if(IS_ERR(name)) |
1919 | return PTR_ERR(name); | 1978 | return PTR_ERR(name); |
1920 | 1979 | ||
1921 | error = path_lookup(name, LOOKUP_PARENT, &nd); | 1980 | error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd); |
1922 | if (error) | 1981 | if (error) |
1923 | goto exit; | 1982 | goto exit; |
1924 | 1983 | ||
@@ -1948,6 +2007,11 @@ exit: | |||
1948 | return error; | 2007 | return error; |
1949 | } | 2008 | } |
1950 | 2009 | ||
2010 | asmlinkage long sys_rmdir(const char __user *pathname) | ||
2011 | { | ||
2012 | return do_rmdir(AT_FDCWD, pathname); | ||
2013 | } | ||
2014 | |||
1951 | int vfs_unlink(struct inode *dir, struct dentry *dentry) | 2015 | int vfs_unlink(struct inode *dir, struct dentry *dentry) |
1952 | { | 2016 | { |
1953 | int error = may_delete(dir, dentry, 0); | 2017 | int error = may_delete(dir, dentry, 0); |
@@ -1984,7 +2048,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) | |||
1984 | * writeout happening, and we don't want to prevent access to the directory | 2048 | * writeout happening, and we don't want to prevent access to the directory |
1985 | * while waiting on the I/O. | 2049 | * while waiting on the I/O. |
1986 | */ | 2050 | */ |
1987 | asmlinkage long sys_unlink(const char __user * pathname) | 2051 | static long do_unlinkat(int dfd, const char __user *pathname) |
1988 | { | 2052 | { |
1989 | int error = 0; | 2053 | int error = 0; |
1990 | char * name; | 2054 | char * name; |
@@ -1996,7 +2060,7 @@ asmlinkage long sys_unlink(const char __user * pathname) | |||
1996 | if(IS_ERR(name)) | 2060 | if(IS_ERR(name)) |
1997 | return PTR_ERR(name); | 2061 | return PTR_ERR(name); |
1998 | 2062 | ||
1999 | error = path_lookup(name, LOOKUP_PARENT, &nd); | 2063 | error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd); |
2000 | if (error) | 2064 | if (error) |
2001 | goto exit; | 2065 | goto exit; |
2002 | error = -EISDIR; | 2066 | error = -EISDIR; |
@@ -2031,6 +2095,22 @@ slashes: | |||
2031 | goto exit2; | 2095 | goto exit2; |
2032 | } | 2096 | } |
2033 | 2097 | ||
2098 | asmlinkage long sys_unlinkat(int dfd, const char __user *pathname, int flag) | ||
2099 | { | ||
2100 | if ((flag & ~AT_REMOVEDIR) != 0) | ||
2101 | return -EINVAL; | ||
2102 | |||
2103 | if (flag & AT_REMOVEDIR) | ||
2104 | return do_rmdir(dfd, pathname); | ||
2105 | |||
2106 | return do_unlinkat(dfd, pathname); | ||
2107 | } | ||
2108 | |||
2109 | asmlinkage long sys_unlink(const char __user *pathname) | ||
2110 | { | ||
2111 | return do_unlinkat(AT_FDCWD, pathname); | ||
2112 | } | ||
2113 | |||
2034 | int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, int mode) | 2114 | int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, int mode) |
2035 | { | 2115 | { |
2036 | int error = may_create(dir, dentry, NULL); | 2116 | int error = may_create(dir, dentry, NULL); |
@@ -2052,7 +2132,8 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, i | |||
2052 | return error; | 2132 | return error; |
2053 | } | 2133 | } |
2054 | 2134 | ||
2055 | asmlinkage long sys_symlink(const char __user * oldname, const char __user * newname) | 2135 | asmlinkage long sys_symlinkat(const char __user *oldname, |
2136 | int newdfd, const char __user *newname) | ||
2056 | { | 2137 | { |
2057 | int error = 0; | 2138 | int error = 0; |
2058 | char * from; | 2139 | char * from; |
@@ -2067,7 +2148,7 @@ asmlinkage long sys_symlink(const char __user * oldname, const char __user * new | |||
2067 | struct dentry *dentry; | 2148 | struct dentry *dentry; |
2068 | struct nameidata nd; | 2149 | struct nameidata nd; |
2069 | 2150 | ||
2070 | error = path_lookup(to, LOOKUP_PARENT, &nd); | 2151 | error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd); |
2071 | if (error) | 2152 | if (error) |
2072 | goto out; | 2153 | goto out; |
2073 | dentry = lookup_create(&nd, 0); | 2154 | dentry = lookup_create(&nd, 0); |
@@ -2085,6 +2166,11 @@ out: | |||
2085 | return error; | 2166 | return error; |
2086 | } | 2167 | } |
2087 | 2168 | ||
2169 | asmlinkage long sys_symlink(const char __user *oldname, const char __user *newname) | ||
2170 | { | ||
2171 | return sys_symlinkat(oldname, AT_FDCWD, newname); | ||
2172 | } | ||
2173 | |||
2088 | int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) | 2174 | int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) |
2089 | { | 2175 | { |
2090 | struct inode *inode = old_dentry->d_inode; | 2176 | struct inode *inode = old_dentry->d_inode; |
@@ -2132,7 +2218,8 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de | |||
2132 | * with linux 2.0, and to avoid hard-linking to directories | 2218 | * with linux 2.0, and to avoid hard-linking to directories |
2133 | * and other special files. --ADM | 2219 | * and other special files. --ADM |
2134 | */ | 2220 | */ |
2135 | asmlinkage long sys_link(const char __user * oldname, const char __user * newname) | 2221 | asmlinkage long sys_linkat(int olddfd, const char __user *oldname, |
2222 | int newdfd, const char __user *newname) | ||
2136 | { | 2223 | { |
2137 | struct dentry *new_dentry; | 2224 | struct dentry *new_dentry; |
2138 | struct nameidata nd, old_nd; | 2225 | struct nameidata nd, old_nd; |
@@ -2143,10 +2230,10 @@ asmlinkage long sys_link(const char __user * oldname, const char __user * newnam | |||
2143 | if (IS_ERR(to)) | 2230 | if (IS_ERR(to)) |
2144 | return PTR_ERR(to); | 2231 | return PTR_ERR(to); |
2145 | 2232 | ||
2146 | error = __user_walk(oldname, 0, &old_nd); | 2233 | error = __user_walk_fd(olddfd, oldname, 0, &old_nd); |
2147 | if (error) | 2234 | if (error) |
2148 | goto exit; | 2235 | goto exit; |
2149 | error = path_lookup(to, LOOKUP_PARENT, &nd); | 2236 | error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd); |
2150 | if (error) | 2237 | if (error) |
2151 | goto out; | 2238 | goto out; |
2152 | error = -EXDEV; | 2239 | error = -EXDEV; |
@@ -2169,6 +2256,11 @@ exit: | |||
2169 | return error; | 2256 | return error; |
2170 | } | 2257 | } |
2171 | 2258 | ||
2259 | asmlinkage long sys_link(const char __user *oldname, const char __user *newname) | ||
2260 | { | ||
2261 | return sys_linkat(AT_FDCWD, oldname, AT_FDCWD, newname); | ||
2262 | } | ||
2263 | |||
2172 | /* | 2264 | /* |
2173 | * The worst of all namespace operations - renaming directory. "Perverted" | 2265 | * The worst of all namespace operations - renaming directory. "Perverted" |
2174 | * doesn't even start to describe it. Somebody in UCB had a heck of a trip... | 2266 | * doesn't even start to describe it. Somebody in UCB had a heck of a trip... |
@@ -2315,7 +2407,8 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2315 | return error; | 2407 | return error; |
2316 | } | 2408 | } |
2317 | 2409 | ||
2318 | static int do_rename(const char * oldname, const char * newname) | 2410 | static int do_rename(int olddfd, const char *oldname, |
2411 | int newdfd, const char *newname) | ||
2319 | { | 2412 | { |
2320 | int error = 0; | 2413 | int error = 0; |
2321 | struct dentry * old_dir, * new_dir; | 2414 | struct dentry * old_dir, * new_dir; |
@@ -2323,11 +2416,11 @@ static int do_rename(const char * oldname, const char * newname) | |||
2323 | struct dentry * trap; | 2416 | struct dentry * trap; |
2324 | struct nameidata oldnd, newnd; | 2417 | struct nameidata oldnd, newnd; |
2325 | 2418 | ||
2326 | error = path_lookup(oldname, LOOKUP_PARENT, &oldnd); | 2419 | error = do_path_lookup(olddfd, oldname, LOOKUP_PARENT, &oldnd); |
2327 | if (error) | 2420 | if (error) |
2328 | goto exit; | 2421 | goto exit; |
2329 | 2422 | ||
2330 | error = path_lookup(newname, LOOKUP_PARENT, &newnd); | 2423 | error = do_path_lookup(newdfd, newname, LOOKUP_PARENT, &newnd); |
2331 | if (error) | 2424 | if (error) |
2332 | goto exit1; | 2425 | goto exit1; |
2333 | 2426 | ||
@@ -2391,7 +2484,8 @@ exit: | |||
2391 | return error; | 2484 | return error; |
2392 | } | 2485 | } |
2393 | 2486 | ||
2394 | asmlinkage long sys_rename(const char __user * oldname, const char __user * newname) | 2487 | asmlinkage long sys_renameat(int olddfd, const char __user *oldname, |
2488 | int newdfd, const char __user *newname) | ||
2395 | { | 2489 | { |
2396 | int error; | 2490 | int error; |
2397 | char * from; | 2491 | char * from; |
@@ -2403,13 +2497,18 @@ asmlinkage long sys_rename(const char __user * oldname, const char __user * newn | |||
2403 | to = getname(newname); | 2497 | to = getname(newname); |
2404 | error = PTR_ERR(to); | 2498 | error = PTR_ERR(to); |
2405 | if (!IS_ERR(to)) { | 2499 | if (!IS_ERR(to)) { |
2406 | error = do_rename(from,to); | 2500 | error = do_rename(olddfd, from, newdfd, to); |
2407 | putname(to); | 2501 | putname(to); |
2408 | } | 2502 | } |
2409 | putname(from); | 2503 | putname(from); |
2410 | return error; | 2504 | return error; |
2411 | } | 2505 | } |
2412 | 2506 | ||
2507 | asmlinkage long sys_rename(const char __user *oldname, const char __user *newname) | ||
2508 | { | ||
2509 | return sys_renameat(AT_FDCWD, oldname, AT_FDCWD, newname); | ||
2510 | } | ||
2511 | |||
2413 | int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen, const char *link) | 2512 | int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen, const char *link) |
2414 | { | 2513 | { |
2415 | int len; | 2514 | int len; |
@@ -2553,6 +2652,7 @@ struct inode_operations page_symlink_inode_operations = { | |||
2553 | }; | 2652 | }; |
2554 | 2653 | ||
2555 | EXPORT_SYMBOL(__user_walk); | 2654 | EXPORT_SYMBOL(__user_walk); |
2655 | EXPORT_SYMBOL(__user_walk_fd); | ||
2556 | EXPORT_SYMBOL(follow_down); | 2656 | EXPORT_SYMBOL(follow_down); |
2557 | EXPORT_SYMBOL(follow_up); | 2657 | EXPORT_SYMBOL(follow_up); |
2558 | EXPORT_SYMBOL(get_write_access); /* binfmt_aout */ | 2658 | EXPORT_SYMBOL(get_write_access); /* binfmt_aout */ |
diff --git a/fs/nfsctl.c b/fs/nfsctl.c index 0b14938b5b62..0d4cf9486068 100644 --- a/fs/nfsctl.c +++ b/fs/nfsctl.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * | 5 | * |
6 | */ | 6 | */ |
7 | #include <linux/config.h> | 7 | #include <linux/config.h> |
8 | #include <linux/types.h> | ||
8 | #include <linux/file.h> | 9 | #include <linux/file.h> |
9 | #include <linux/fs.h> | 10 | #include <linux/fs.h> |
10 | #include <linux/sunrpc/svc.h> | 11 | #include <linux/sunrpc/svc.h> |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 361b4007d4a0..a00fe8686293 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -192,6 +192,14 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open | |||
192 | } | 192 | } |
193 | if (status) | 193 | if (status) |
194 | goto out; | 194 | goto out; |
195 | |||
196 | /* Openowner is now set, so sequence id will get bumped. Now we need | ||
197 | * these checks before we do any creates: */ | ||
198 | if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) | ||
199 | return nfserr_grace; | ||
200 | if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) | ||
201 | return nfserr_no_grace; | ||
202 | |||
195 | switch (open->op_claim_type) { | 203 | switch (open->op_claim_type) { |
196 | case NFS4_OPEN_CLAIM_DELEGATE_CUR: | 204 | case NFS4_OPEN_CLAIM_DELEGATE_CUR: |
197 | status = nfserr_inval; | 205 | status = nfserr_inval; |
@@ -210,6 +218,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open | |||
210 | goto out; | 218 | goto out; |
211 | break; | 219 | break; |
212 | case NFS4_OPEN_CLAIM_PREVIOUS: | 220 | case NFS4_OPEN_CLAIM_PREVIOUS: |
221 | open->op_stateowner->so_confirmed = 1; | ||
213 | /* | 222 | /* |
214 | * The CURRENT_FH is already set to the file being | 223 | * The CURRENT_FH is already set to the file being |
215 | * opened. (1) set open->op_cinfo, (2) set | 224 | * opened. (1) set open->op_cinfo, (2) set |
@@ -221,6 +230,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open | |||
221 | goto out; | 230 | goto out; |
222 | break; | 231 | break; |
223 | case NFS4_OPEN_CLAIM_DELEGATE_PREV: | 232 | case NFS4_OPEN_CLAIM_DELEGATE_PREV: |
233 | open->op_stateowner->so_confirmed = 1; | ||
224 | printk("NFSD: unsupported OPEN claim type %d\n", | 234 | printk("NFSD: unsupported OPEN claim type %d\n", |
225 | open->op_claim_type); | 235 | open->op_claim_type); |
226 | status = nfserr_notsupp; | 236 | status = nfserr_notsupp; |
@@ -584,31 +594,23 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_se | |||
584 | { | 594 | { |
585 | int status = nfs_ok; | 595 | int status = nfs_ok; |
586 | 596 | ||
587 | if (!current_fh->fh_dentry) | ||
588 | return nfserr_nofilehandle; | ||
589 | |||
590 | status = nfs_ok; | ||
591 | if (setattr->sa_iattr.ia_valid & ATTR_SIZE) { | 597 | if (setattr->sa_iattr.ia_valid & ATTR_SIZE) { |
592 | nfs4_lock_state(); | 598 | nfs4_lock_state(); |
593 | if ((status = nfs4_preprocess_stateid_op(current_fh, | 599 | status = nfs4_preprocess_stateid_op(current_fh, |
594 | &setattr->sa_stateid, | 600 | &setattr->sa_stateid, CHECK_FH | WR_STATE, NULL); |
595 | CHECK_FH | WR_STATE, NULL))) { | ||
596 | dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n"); | ||
597 | goto out_unlock; | ||
598 | } | ||
599 | nfs4_unlock_state(); | 601 | nfs4_unlock_state(); |
602 | if (status) { | ||
603 | dprintk("NFSD: nfsd4_setattr: couldn't process stateid!"); | ||
604 | return status; | ||
605 | } | ||
600 | } | 606 | } |
601 | status = nfs_ok; | 607 | status = nfs_ok; |
602 | if (setattr->sa_acl != NULL) | 608 | if (setattr->sa_acl != NULL) |
603 | status = nfsd4_set_nfs4_acl(rqstp, current_fh, setattr->sa_acl); | 609 | status = nfsd4_set_nfs4_acl(rqstp, current_fh, setattr->sa_acl); |
604 | if (status) | 610 | if (status) |
605 | goto out; | 611 | return status; |
606 | status = nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr, | 612 | status = nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr, |
607 | 0, (time_t)0); | 613 | 0, (time_t)0); |
608 | out: | ||
609 | return status; | ||
610 | out_unlock: | ||
611 | nfs4_unlock_state(); | ||
612 | return status; | 614 | return status; |
613 | } | 615 | } |
614 | 616 | ||
@@ -626,15 +628,17 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ | |||
626 | return nfserr_inval; | 628 | return nfserr_inval; |
627 | 629 | ||
628 | nfs4_lock_state(); | 630 | nfs4_lock_state(); |
629 | if ((status = nfs4_preprocess_stateid_op(current_fh, stateid, | 631 | status = nfs4_preprocess_stateid_op(current_fh, stateid, |
630 | CHECK_FH | WR_STATE, &filp))) { | 632 | CHECK_FH | WR_STATE, &filp); |
631 | dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); | ||
632 | goto out; | ||
633 | } | ||
634 | if (filp) | 633 | if (filp) |
635 | get_file(filp); | 634 | get_file(filp); |
636 | nfs4_unlock_state(); | 635 | nfs4_unlock_state(); |
637 | 636 | ||
637 | if (status) { | ||
638 | dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); | ||
639 | return status; | ||
640 | } | ||
641 | |||
638 | write->wr_bytes_written = write->wr_buflen; | 642 | write->wr_bytes_written = write->wr_buflen; |
639 | write->wr_how_written = write->wr_stable_how; | 643 | write->wr_how_written = write->wr_stable_how; |
640 | p = (u32 *)write->wr_verifier.data; | 644 | p = (u32 *)write->wr_verifier.data; |
@@ -650,9 +654,6 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ | |||
650 | if (status == nfserr_symlink) | 654 | if (status == nfserr_symlink) |
651 | status = nfserr_inval; | 655 | status = nfserr_inval; |
652 | return status; | 656 | return status; |
653 | out: | ||
654 | nfs4_unlock_state(); | ||
655 | return status; | ||
656 | } | 657 | } |
657 | 658 | ||
658 | /* This routine never returns NFS_OK! If there are no other errors, it | 659 | /* This routine never returns NFS_OK! If there are no other errors, it |
@@ -768,6 +769,8 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
768 | while (!status && resp->opcnt < args->opcnt) { | 769 | while (!status && resp->opcnt < args->opcnt) { |
769 | op = &args->ops[resp->opcnt++]; | 770 | op = &args->ops[resp->opcnt++]; |
770 | 771 | ||
772 | dprintk("nfsv4 compound op #%d: %d\n", resp->opcnt, op->opnum); | ||
773 | |||
771 | /* | 774 | /* |
772 | * The XDR decode routines may have pre-set op->status; | 775 | * The XDR decode routines may have pre-set op->status; |
773 | * for example, if there is a miscellaneous XDR error | 776 | * for example, if there is a miscellaneous XDR error |
@@ -792,17 +795,13 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, | |||
792 | /* All operations except RENEW, SETCLIENTID, RESTOREFH | 795 | /* All operations except RENEW, SETCLIENTID, RESTOREFH |
793 | * SETCLIENTID_CONFIRM, PUTFH and PUTROOTFH | 796 | * SETCLIENTID_CONFIRM, PUTFH and PUTROOTFH |
794 | * require a valid current filehandle | 797 | * require a valid current filehandle |
795 | * | ||
796 | * SETATTR NOFILEHANDLE error handled in nfsd4_setattr | ||
797 | * due to required returned bitmap argument | ||
798 | */ | 798 | */ |
799 | if ((!current_fh->fh_dentry) && | 799 | if ((!current_fh->fh_dentry) && |
800 | !((op->opnum == OP_PUTFH) || (op->opnum == OP_PUTROOTFH) || | 800 | !((op->opnum == OP_PUTFH) || (op->opnum == OP_PUTROOTFH) || |
801 | (op->opnum == OP_SETCLIENTID) || | 801 | (op->opnum == OP_SETCLIENTID) || |
802 | (op->opnum == OP_SETCLIENTID_CONFIRM) || | 802 | (op->opnum == OP_SETCLIENTID_CONFIRM) || |
803 | (op->opnum == OP_RENEW) || (op->opnum == OP_RESTOREFH) || | 803 | (op->opnum == OP_RENEW) || (op->opnum == OP_RESTOREFH) || |
804 | (op->opnum == OP_RELEASE_LOCKOWNER) || | 804 | (op->opnum == OP_RELEASE_LOCKOWNER))) { |
805 | (op->opnum == OP_SETATTR))) { | ||
806 | op->status = nfserr_nofilehandle; | 805 | op->status = nfserr_nofilehandle; |
807 | goto encode_op; | 806 | goto encode_op; |
808 | } | 807 | } |
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index be963a133aaa..06da7506363c 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c | |||
@@ -222,8 +222,7 @@ nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f) | |||
222 | 222 | ||
223 | nfs4_save_user(&uid, &gid); | 223 | nfs4_save_user(&uid, &gid); |
224 | 224 | ||
225 | filp = dentry_open(dget(dir), mntget(rec_dir.mnt), | 225 | filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY); |
226 | O_RDWR); | ||
227 | status = PTR_ERR(filp); | 226 | status = PTR_ERR(filp); |
228 | if (IS_ERR(filp)) | 227 | if (IS_ERR(filp)) |
229 | goto out; | 228 | goto out; |
@@ -400,9 +399,10 @@ nfsd4_init_recdir(char *rec_dirname) | |||
400 | 399 | ||
401 | nfs4_save_user(&uid, &gid); | 400 | nfs4_save_user(&uid, &gid); |
402 | 401 | ||
403 | status = path_lookup(rec_dirname, LOOKUP_FOLLOW, &rec_dir); | 402 | status = path_lookup(rec_dirname, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, |
404 | if (status == -ENOENT) | 403 | &rec_dir); |
405 | printk("NFSD: recovery directory %s doesn't exist\n", | 404 | if (status) |
405 | printk("NFSD: unable to find recovery directory %s\n", | ||
406 | rec_dirname); | 406 | rec_dirname); |
407 | 407 | ||
408 | if (!status) | 408 | if (!status) |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 6bbefd06f10d..1143cfb64549 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -1088,7 +1088,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str | |||
1088 | sop->so_seqid = open->op_seqid; | 1088 | sop->so_seqid = open->op_seqid; |
1089 | sop->so_confirmed = 0; | 1089 | sop->so_confirmed = 0; |
1090 | rp = &sop->so_replay; | 1090 | rp = &sop->so_replay; |
1091 | rp->rp_status = NFSERR_SERVERFAULT; | 1091 | rp->rp_status = nfserr_serverfault; |
1092 | rp->rp_buflen = 0; | 1092 | rp->rp_buflen = 0; |
1093 | rp->rp_buf = rp->rp_ibuf; | 1093 | rp->rp_buf = rp->rp_ibuf; |
1094 | return sop; | 1094 | return sop; |
@@ -1178,7 +1178,6 @@ release_stateid(struct nfs4_stateid *stp, int flags) | |||
1178 | locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner); | 1178 | locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner); |
1179 | put_nfs4_file(stp->st_file); | 1179 | put_nfs4_file(stp->st_file); |
1180 | kmem_cache_free(stateid_slab, stp); | 1180 | kmem_cache_free(stateid_slab, stp); |
1181 | stp = NULL; | ||
1182 | } | 1181 | } |
1183 | 1182 | ||
1184 | static void | 1183 | static void |
@@ -1191,22 +1190,6 @@ move_to_close_lru(struct nfs4_stateowner *sop) | |||
1191 | sop->so_time = get_seconds(); | 1190 | sop->so_time = get_seconds(); |
1192 | } | 1191 | } |
1193 | 1192 | ||
1194 | static void | ||
1195 | release_state_owner(struct nfs4_stateid *stp, int flag) | ||
1196 | { | ||
1197 | struct nfs4_stateowner *sop = stp->st_stateowner; | ||
1198 | |||
1199 | dprintk("NFSD: release_state_owner\n"); | ||
1200 | release_stateid(stp, flag); | ||
1201 | |||
1202 | /* place unused nfs4_stateowners on so_close_lru list to be | ||
1203 | * released by the laundromat service after the lease period | ||
1204 | * to enable us to handle CLOSE replay | ||
1205 | */ | ||
1206 | if (sop->so_confirmed && list_empty(&sop->so_stateids)) | ||
1207 | move_to_close_lru(sop); | ||
1208 | } | ||
1209 | |||
1210 | static int | 1193 | static int |
1211 | cmp_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, clientid_t *clid) { | 1194 | cmp_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, clientid_t *clid) { |
1212 | return ((sop->so_owner.len == owner->len) && | 1195 | return ((sop->so_owner.len == owner->len) && |
@@ -1446,92 +1429,61 @@ static struct lock_manager_operations nfsd_lease_mng_ops = { | |||
1446 | }; | 1429 | }; |
1447 | 1430 | ||
1448 | 1431 | ||
1449 | /* | ||
1450 | * nfsd4_process_open1() | ||
1451 | * lookup stateowner. | ||
1452 | * found: | ||
1453 | * check confirmed | ||
1454 | * confirmed: | ||
1455 | * check seqid | ||
1456 | * not confirmed: | ||
1457 | * delete owner | ||
1458 | * create new owner | ||
1459 | * notfound: | ||
1460 | * verify clientid | ||
1461 | * create new owner | ||
1462 | * | ||
1463 | * called with nfs4_lock_state() held. | ||
1464 | */ | ||
1465 | int | 1432 | int |
1466 | nfsd4_process_open1(struct nfsd4_open *open) | 1433 | nfsd4_process_open1(struct nfsd4_open *open) |
1467 | { | 1434 | { |
1468 | int status; | ||
1469 | clientid_t *clientid = &open->op_clientid; | 1435 | clientid_t *clientid = &open->op_clientid; |
1470 | struct nfs4_client *clp = NULL; | 1436 | struct nfs4_client *clp = NULL; |
1471 | unsigned int strhashval; | 1437 | unsigned int strhashval; |
1472 | struct nfs4_stateowner *sop = NULL; | 1438 | struct nfs4_stateowner *sop = NULL; |
1473 | 1439 | ||
1474 | status = nfserr_inval; | ||
1475 | if (!check_name(open->op_owner)) | 1440 | if (!check_name(open->op_owner)) |
1476 | goto out; | 1441 | return nfserr_inval; |
1477 | 1442 | ||
1478 | if (STALE_CLIENTID(&open->op_clientid)) | 1443 | if (STALE_CLIENTID(&open->op_clientid)) |
1479 | return nfserr_stale_clientid; | 1444 | return nfserr_stale_clientid; |
1480 | 1445 | ||
1481 | strhashval = ownerstr_hashval(clientid->cl_id, open->op_owner); | 1446 | strhashval = ownerstr_hashval(clientid->cl_id, open->op_owner); |
1482 | sop = find_openstateowner_str(strhashval, open); | 1447 | sop = find_openstateowner_str(strhashval, open); |
1483 | if (sop) { | 1448 | open->op_stateowner = sop; |
1484 | open->op_stateowner = sop; | 1449 | if (!sop) { |
1485 | /* check for replay */ | 1450 | /* Make sure the client's lease hasn't expired. */ |
1486 | if (open->op_seqid == sop->so_seqid - 1){ | ||
1487 | if (sop->so_replay.rp_buflen) | ||
1488 | return NFSERR_REPLAY_ME; | ||
1489 | else { | ||
1490 | /* The original OPEN failed so spectacularly | ||
1491 | * that we don't even have replay data saved! | ||
1492 | * Therefore, we have no choice but to continue | ||
1493 | * processing this OPEN; presumably, we'll | ||
1494 | * fail again for the same reason. | ||
1495 | */ | ||
1496 | dprintk("nfsd4_process_open1:" | ||
1497 | " replay with no replay cache\n"); | ||
1498 | goto renew; | ||
1499 | } | ||
1500 | } else if (sop->so_confirmed) { | ||
1501 | if (open->op_seqid == sop->so_seqid) | ||
1502 | goto renew; | ||
1503 | status = nfserr_bad_seqid; | ||
1504 | goto out; | ||
1505 | } else { | ||
1506 | /* If we get here, we received an OPEN for an | ||
1507 | * unconfirmed nfs4_stateowner. Since the seqid's are | ||
1508 | * different, purge the existing nfs4_stateowner, and | ||
1509 | * instantiate a new one. | ||
1510 | */ | ||
1511 | clp = sop->so_client; | ||
1512 | release_stateowner(sop); | ||
1513 | } | ||
1514 | } else { | ||
1515 | /* nfs4_stateowner not found. | ||
1516 | * Verify clientid and instantiate new nfs4_stateowner. | ||
1517 | * If verify fails this is presumably the result of the | ||
1518 | * client's lease expiring. | ||
1519 | */ | ||
1520 | status = nfserr_expired; | ||
1521 | clp = find_confirmed_client(clientid); | 1451 | clp = find_confirmed_client(clientid); |
1522 | if (clp == NULL) | 1452 | if (clp == NULL) |
1523 | goto out; | 1453 | return nfserr_expired; |
1454 | goto renew; | ||
1524 | } | 1455 | } |
1525 | status = nfserr_resource; | 1456 | if (!sop->so_confirmed) { |
1526 | sop = alloc_init_open_stateowner(strhashval, clp, open); | 1457 | /* Replace unconfirmed owners without checking for replay. */ |
1527 | if (sop == NULL) | 1458 | clp = sop->so_client; |
1528 | goto out; | 1459 | release_stateowner(sop); |
1529 | open->op_stateowner = sop; | 1460 | open->op_stateowner = NULL; |
1461 | goto renew; | ||
1462 | } | ||
1463 | if (open->op_seqid == sop->so_seqid - 1) { | ||
1464 | if (sop->so_replay.rp_buflen) | ||
1465 | return NFSERR_REPLAY_ME; | ||
1466 | /* The original OPEN failed so spectacularly | ||
1467 | * that we don't even have replay data saved! | ||
1468 | * Therefore, we have no choice but to continue | ||
1469 | * processing this OPEN; presumably, we'll | ||
1470 | * fail again for the same reason. | ||
1471 | */ | ||
1472 | dprintk("nfsd4_process_open1: replay with no replay cache\n"); | ||
1473 | goto renew; | ||
1474 | } | ||
1475 | if (open->op_seqid != sop->so_seqid) | ||
1476 | return nfserr_bad_seqid; | ||
1530 | renew: | 1477 | renew: |
1531 | status = nfs_ok; | 1478 | if (open->op_stateowner == NULL) { |
1479 | sop = alloc_init_open_stateowner(strhashval, clp, open); | ||
1480 | if (sop == NULL) | ||
1481 | return nfserr_resource; | ||
1482 | open->op_stateowner = sop; | ||
1483 | } | ||
1484 | list_del_init(&sop->so_close_lru); | ||
1532 | renew_client(sop->so_client); | 1485 | renew_client(sop->so_client); |
1533 | out: | 1486 | return nfs_ok; |
1534 | return status; | ||
1535 | } | 1487 | } |
1536 | 1488 | ||
1537 | static inline int | 1489 | static inline int |
@@ -1648,7 +1600,7 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, | |||
1648 | if (!open->op_truncate) | 1600 | if (!open->op_truncate) |
1649 | return 0; | 1601 | return 0; |
1650 | if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) | 1602 | if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) |
1651 | return -EINVAL; | 1603 | return nfserr_inval; |
1652 | return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0); | 1604 | return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0); |
1653 | } | 1605 | } |
1654 | 1606 | ||
@@ -1657,26 +1609,26 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_sta | |||
1657 | { | 1609 | { |
1658 | struct file *filp = stp->st_vfs_file; | 1610 | struct file *filp = stp->st_vfs_file; |
1659 | struct inode *inode = filp->f_dentry->d_inode; | 1611 | struct inode *inode = filp->f_dentry->d_inode; |
1660 | unsigned int share_access; | 1612 | unsigned int share_access, new_writer; |
1661 | int status; | 1613 | int status; |
1662 | 1614 | ||
1663 | set_access(&share_access, stp->st_access_bmap); | 1615 | set_access(&share_access, stp->st_access_bmap); |
1664 | share_access = ~share_access; | 1616 | new_writer = (~share_access) & open->op_share_access |
1665 | share_access &= open->op_share_access; | 1617 | & NFS4_SHARE_ACCESS_WRITE; |
1666 | |||
1667 | if (!(share_access & NFS4_SHARE_ACCESS_WRITE)) | ||
1668 | return nfsd4_truncate(rqstp, cur_fh, open); | ||
1669 | 1618 | ||
1670 | status = get_write_access(inode); | 1619 | if (new_writer) { |
1671 | if (status) | 1620 | status = get_write_access(inode); |
1672 | return nfserrno(status); | 1621 | if (status) |
1622 | return nfserrno(status); | ||
1623 | } | ||
1673 | status = nfsd4_truncate(rqstp, cur_fh, open); | 1624 | status = nfsd4_truncate(rqstp, cur_fh, open); |
1674 | if (status) { | 1625 | if (status) { |
1675 | put_write_access(inode); | 1626 | if (new_writer) |
1627 | put_write_access(inode); | ||
1676 | return status; | 1628 | return status; |
1677 | } | 1629 | } |
1678 | /* remember the open */ | 1630 | /* remember the open */ |
1679 | filp->f_mode = (filp->f_mode | FMODE_WRITE) & ~FMODE_READ; | 1631 | filp->f_mode |= open->op_share_access; |
1680 | set_bit(open->op_share_access, &stp->st_access_bmap); | 1632 | set_bit(open->op_share_access, &stp->st_access_bmap); |
1681 | set_bit(open->op_share_deny, &stp->st_deny_bmap); | 1633 | set_bit(open->op_share_deny, &stp->st_deny_bmap); |
1682 | 1634 | ||
@@ -1780,12 +1732,6 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
1780 | struct nfs4_delegation *dp = NULL; | 1732 | struct nfs4_delegation *dp = NULL; |
1781 | int status; | 1733 | int status; |
1782 | 1734 | ||
1783 | if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) | ||
1784 | return nfserr_grace; | ||
1785 | |||
1786 | if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) | ||
1787 | return nfserr_no_grace; | ||
1788 | |||
1789 | status = nfserr_inval; | 1735 | status = nfserr_inval; |
1790 | if (!TEST_ACCESS(open->op_share_access) || !TEST_DENY(open->op_share_deny)) | 1736 | if (!TEST_ACCESS(open->op_share_access) || !TEST_DENY(open->op_share_deny)) |
1791 | goto out; | 1737 | goto out; |
@@ -2423,15 +2369,19 @@ nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_clos | |||
2423 | CHECK_FH | OPEN_STATE | CLOSE_STATE, | 2369 | CHECK_FH | OPEN_STATE | CLOSE_STATE, |
2424 | &close->cl_stateowner, &stp, NULL))) | 2370 | &close->cl_stateowner, &stp, NULL))) |
2425 | goto out; | 2371 | goto out; |
2426 | /* | ||
2427 | * Return success, but first update the stateid. | ||
2428 | */ | ||
2429 | status = nfs_ok; | 2372 | status = nfs_ok; |
2430 | update_stateid(&stp->st_stateid); | 2373 | update_stateid(&stp->st_stateid); |
2431 | memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t)); | 2374 | memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t)); |
2432 | 2375 | ||
2433 | /* release_state_owner() calls nfsd_close() if needed */ | 2376 | /* release_stateid() calls nfsd_close() if needed */ |
2434 | release_state_owner(stp, OPEN_STATE); | 2377 | release_stateid(stp, OPEN_STATE); |
2378 | |||
2379 | /* place unused nfs4_stateowners on so_close_lru list to be | ||
2380 | * released by the laundromat service after the lease period | ||
2381 | * to enable us to handle CLOSE replay | ||
2382 | */ | ||
2383 | if (list_empty(&close->cl_stateowner->so_stateids)) | ||
2384 | move_to_close_lru(close->cl_stateowner); | ||
2435 | out: | 2385 | out: |
2436 | if (close->cl_stateowner) { | 2386 | if (close->cl_stateowner) { |
2437 | nfs4_get_stateowner(close->cl_stateowner); | 2387 | nfs4_get_stateowner(close->cl_stateowner); |
@@ -2633,7 +2583,7 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str | |||
2633 | sop->so_seqid = lock->lk_new_lock_seqid + 1; | 2583 | sop->so_seqid = lock->lk_new_lock_seqid + 1; |
2634 | sop->so_confirmed = 1; | 2584 | sop->so_confirmed = 1; |
2635 | rp = &sop->so_replay; | 2585 | rp = &sop->so_replay; |
2636 | rp->rp_status = NFSERR_SERVERFAULT; | 2586 | rp->rp_status = nfserr_serverfault; |
2637 | rp->rp_buflen = 0; | 2587 | rp->rp_buflen = 0; |
2638 | rp->rp_buf = rp->rp_ibuf; | 2588 | rp->rp_buf = rp->rp_ibuf; |
2639 | return sop; | 2589 | return sop; |
@@ -2700,6 +2650,11 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
2700 | if (check_lock_length(lock->lk_offset, lock->lk_length)) | 2650 | if (check_lock_length(lock->lk_offset, lock->lk_length)) |
2701 | return nfserr_inval; | 2651 | return nfserr_inval; |
2702 | 2652 | ||
2653 | if ((status = fh_verify(rqstp, current_fh, S_IFREG, MAY_LOCK))) { | ||
2654 | dprintk("NFSD: nfsd4_lock: permission denied!\n"); | ||
2655 | return status; | ||
2656 | } | ||
2657 | |||
2703 | nfs4_lock_state(); | 2658 | nfs4_lock_state(); |
2704 | 2659 | ||
2705 | if (lock->lk_is_new) { | 2660 | if (lock->lk_is_new) { |
@@ -2720,11 +2675,11 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
2720 | lock->lk_new_open_seqid, | 2675 | lock->lk_new_open_seqid, |
2721 | &lock->lk_new_open_stateid, | 2676 | &lock->lk_new_open_stateid, |
2722 | CHECK_FH | OPEN_STATE, | 2677 | CHECK_FH | OPEN_STATE, |
2723 | &lock->lk_stateowner, &open_stp, | 2678 | &lock->lk_replay_owner, &open_stp, |
2724 | lock); | 2679 | lock); |
2725 | if (status) | 2680 | if (status) |
2726 | goto out; | 2681 | goto out; |
2727 | open_sop = lock->lk_stateowner; | 2682 | open_sop = lock->lk_replay_owner; |
2728 | /* create lockowner and lock stateid */ | 2683 | /* create lockowner and lock stateid */ |
2729 | fp = open_stp->st_file; | 2684 | fp = open_stp->st_file; |
2730 | strhashval = lock_ownerstr_hashval(fp->fi_inode, | 2685 | strhashval = lock_ownerstr_hashval(fp->fi_inode, |
@@ -2739,29 +2694,22 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
2739 | if (lock_sop == NULL) | 2694 | if (lock_sop == NULL) |
2740 | goto out; | 2695 | goto out; |
2741 | lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp); | 2696 | lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp); |
2742 | if (lock_stp == NULL) { | 2697 | if (lock_stp == NULL) |
2743 | release_stateowner(lock_sop); | ||
2744 | goto out; | 2698 | goto out; |
2745 | } | ||
2746 | } else { | 2699 | } else { |
2747 | /* lock (lock owner + lock stateid) already exists */ | 2700 | /* lock (lock owner + lock stateid) already exists */ |
2748 | status = nfs4_preprocess_seqid_op(current_fh, | 2701 | status = nfs4_preprocess_seqid_op(current_fh, |
2749 | lock->lk_old_lock_seqid, | 2702 | lock->lk_old_lock_seqid, |
2750 | &lock->lk_old_lock_stateid, | 2703 | &lock->lk_old_lock_stateid, |
2751 | CHECK_FH | LOCK_STATE, | 2704 | CHECK_FH | LOCK_STATE, |
2752 | &lock->lk_stateowner, &lock_stp, lock); | 2705 | &lock->lk_replay_owner, &lock_stp, lock); |
2753 | if (status) | 2706 | if (status) |
2754 | goto out; | 2707 | goto out; |
2755 | lock_sop = lock->lk_stateowner; | 2708 | lock_sop = lock->lk_replay_owner; |
2756 | } | 2709 | } |
2757 | /* lock->lk_stateowner and lock_stp have been created or found */ | 2710 | /* lock->lk_replay_owner and lock_stp have been created or found */ |
2758 | filp = lock_stp->st_vfs_file; | 2711 | filp = lock_stp->st_vfs_file; |
2759 | 2712 | ||
2760 | if ((status = fh_verify(rqstp, current_fh, S_IFREG, MAY_LOCK))) { | ||
2761 | dprintk("NFSD: nfsd4_lock: permission denied!\n"); | ||
2762 | goto out; | ||
2763 | } | ||
2764 | |||
2765 | status = nfserr_grace; | 2713 | status = nfserr_grace; |
2766 | if (nfs4_in_grace() && !lock->lk_reclaim) | 2714 | if (nfs4_in_grace() && !lock->lk_reclaim) |
2767 | goto out; | 2715 | goto out; |
@@ -2802,8 +2750,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
2802 | */ | 2750 | */ |
2803 | 2751 | ||
2804 | status = posix_lock_file(filp, &file_lock); | 2752 | status = posix_lock_file(filp, &file_lock); |
2805 | if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private) | ||
2806 | file_lock.fl_ops->fl_release_private(&file_lock); | ||
2807 | dprintk("NFSD: nfsd4_lock: posix_lock_file status %d\n",status); | 2753 | dprintk("NFSD: nfsd4_lock: posix_lock_file status %d\n",status); |
2808 | switch (-status) { | 2754 | switch (-status) { |
2809 | case 0: /* success! */ | 2755 | case 0: /* success! */ |
@@ -2815,9 +2761,12 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
2815 | goto conflicting_lock; | 2761 | goto conflicting_lock; |
2816 | case (EDEADLK): | 2762 | case (EDEADLK): |
2817 | status = nfserr_deadlock; | 2763 | status = nfserr_deadlock; |
2764 | dprintk("NFSD: nfsd4_lock: posix_lock_file() failed! status %d\n",status); | ||
2765 | goto out; | ||
2818 | default: | 2766 | default: |
2767 | status = nfserrno(status); | ||
2819 | dprintk("NFSD: nfsd4_lock: posix_lock_file() failed! status %d\n",status); | 2768 | dprintk("NFSD: nfsd4_lock: posix_lock_file() failed! status %d\n",status); |
2820 | goto out_destroy_new_stateid; | 2769 | goto out; |
2821 | } | 2770 | } |
2822 | 2771 | ||
2823 | conflicting_lock: | 2772 | conflicting_lock: |
@@ -2831,20 +2780,12 @@ conflicting_lock: | |||
2831 | goto out; | 2780 | goto out; |
2832 | } | 2781 | } |
2833 | nfs4_set_lock_denied(conflock, &lock->lk_denied); | 2782 | nfs4_set_lock_denied(conflock, &lock->lk_denied); |
2834 | |||
2835 | out_destroy_new_stateid: | ||
2836 | if (lock->lk_is_new) { | ||
2837 | dprintk("NFSD: nfsd4_lock: destroy new stateid!\n"); | ||
2838 | /* | ||
2839 | * An error encountered after instantiation of the new | ||
2840 | * stateid has forced us to destroy it. | ||
2841 | */ | ||
2842 | release_state_owner(lock_stp, LOCK_STATE); | ||
2843 | } | ||
2844 | out: | 2783 | out: |
2845 | if (lock->lk_stateowner) { | 2784 | if (status && lock->lk_is_new && lock_sop) |
2846 | nfs4_get_stateowner(lock->lk_stateowner); | 2785 | release_stateowner(lock_sop); |
2847 | *replay_owner = lock->lk_stateowner; | 2786 | if (lock->lk_replay_owner) { |
2787 | nfs4_get_stateowner(lock->lk_replay_owner); | ||
2788 | *replay_owner = lock->lk_replay_owner; | ||
2848 | } | 2789 | } |
2849 | nfs4_unlock_state(); | 2790 | nfs4_unlock_state(); |
2850 | return status; | 2791 | return status; |
@@ -2977,8 +2918,6 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
2977 | * Try to unlock the file in the VFS. | 2918 | * Try to unlock the file in the VFS. |
2978 | */ | 2919 | */ |
2979 | status = posix_lock_file(filp, &file_lock); | 2920 | status = posix_lock_file(filp, &file_lock); |
2980 | if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private) | ||
2981 | file_lock.fl_ops->fl_release_private(&file_lock); | ||
2982 | if (status) { | 2921 | if (status) { |
2983 | dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n"); | 2922 | dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n"); |
2984 | goto out_nfserr; | 2923 | goto out_nfserr; |
@@ -3016,9 +2955,10 @@ check_for_locks(struct file *filp, struct nfs4_stateowner *lowner) | |||
3016 | 2955 | ||
3017 | lock_kernel(); | 2956 | lock_kernel(); |
3018 | for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) { | 2957 | for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) { |
3019 | if ((*flpp)->fl_owner == (fl_owner_t)lowner) | 2958 | if ((*flpp)->fl_owner == (fl_owner_t)lowner) { |
3020 | status = 1; | 2959 | status = 1; |
3021 | goto out; | 2960 | goto out; |
2961 | } | ||
3022 | } | 2962 | } |
3023 | out: | 2963 | out: |
3024 | unlock_kernel(); | 2964 | unlock_kernel(); |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index dcd673186944..69d3501173a8 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -528,7 +528,7 @@ nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) | |||
528 | { | 528 | { |
529 | DECODE_HEAD; | 529 | DECODE_HEAD; |
530 | 530 | ||
531 | lock->lk_stateowner = NULL; | 531 | lock->lk_replay_owner = NULL; |
532 | /* | 532 | /* |
533 | * type, reclaim(boolean), offset, length, new_lock_owner(boolean) | 533 | * type, reclaim(boolean), offset, length, new_lock_owner(boolean) |
534 | */ | 534 | */ |
@@ -1764,10 +1764,11 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen, | |||
1764 | */ | 1764 | */ |
1765 | if (!(cd->rd_bmval[0] & FATTR4_WORD0_RDATTR_ERROR)) | 1765 | if (!(cd->rd_bmval[0] & FATTR4_WORD0_RDATTR_ERROR)) |
1766 | goto fail; | 1766 | goto fail; |
1767 | nfserr = nfserr_toosmall; | ||
1768 | p = nfsd4_encode_rdattr_error(p, buflen, nfserr); | 1767 | p = nfsd4_encode_rdattr_error(p, buflen, nfserr); |
1769 | if (p == NULL) | 1768 | if (p == NULL) { |
1769 | nfserr = nfserr_toosmall; | ||
1770 | goto fail; | 1770 | goto fail; |
1771 | } | ||
1771 | } | 1772 | } |
1772 | cd->buflen -= (p - cd->buffer); | 1773 | cd->buflen -= (p - cd->buffer); |
1773 | cd->buffer = p; | 1774 | cd->buffer = p; |
@@ -1895,7 +1896,6 @@ nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denie | |||
1895 | static void | 1896 | static void |
1896 | nfsd4_encode_lock(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lock *lock) | 1897 | nfsd4_encode_lock(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lock *lock) |
1897 | { | 1898 | { |
1898 | |||
1899 | ENCODE_SEQID_OP_HEAD; | 1899 | ENCODE_SEQID_OP_HEAD; |
1900 | 1900 | ||
1901 | if (!nfserr) { | 1901 | if (!nfserr) { |
@@ -1906,7 +1906,7 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lock | |||
1906 | } else if (nfserr == nfserr_denied) | 1906 | } else if (nfserr == nfserr_denied) |
1907 | nfsd4_encode_lock_denied(resp, &lock->lk_denied); | 1907 | nfsd4_encode_lock_denied(resp, &lock->lk_denied); |
1908 | 1908 | ||
1909 | ENCODE_SEQID_OP_TAIL(lock->lk_stateowner); | 1909 | ENCODE_SEQID_OP_TAIL(lock->lk_replay_owner); |
1910 | } | 1910 | } |
1911 | 1911 | ||
1912 | static void | 1912 | static void |
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 0aa1b9603d7f..3e6b75cd90fd 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c | |||
@@ -36,6 +36,22 @@ nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp) | |||
36 | return nfs_ok; | 36 | return nfs_ok; |
37 | } | 37 | } |
38 | 38 | ||
39 | static int | ||
40 | nfsd_return_attrs(int err, struct nfsd_attrstat *resp) | ||
41 | { | ||
42 | if (err) return err; | ||
43 | return nfserrno(vfs_getattr(resp->fh.fh_export->ex_mnt, | ||
44 | resp->fh.fh_dentry, | ||
45 | &resp->stat)); | ||
46 | } | ||
47 | static int | ||
48 | nfsd_return_dirop(int err, struct nfsd_diropres *resp) | ||
49 | { | ||
50 | if (err) return err; | ||
51 | return nfserrno(vfs_getattr(resp->fh.fh_export->ex_mnt, | ||
52 | resp->fh.fh_dentry, | ||
53 | &resp->stat)); | ||
54 | } | ||
39 | /* | 55 | /* |
40 | * Get a file's attributes | 56 | * Get a file's attributes |
41 | * N.B. After this call resp->fh needs an fh_put | 57 | * N.B. After this call resp->fh needs an fh_put |
@@ -44,10 +60,12 @@ static int | |||
44 | nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, | 60 | nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, |
45 | struct nfsd_attrstat *resp) | 61 | struct nfsd_attrstat *resp) |
46 | { | 62 | { |
63 | int nfserr; | ||
47 | dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); | 64 | dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); |
48 | 65 | ||
49 | fh_copy(&resp->fh, &argp->fh); | 66 | fh_copy(&resp->fh, &argp->fh); |
50 | return fh_verify(rqstp, &resp->fh, 0, MAY_NOP); | 67 | nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP); |
68 | return nfsd_return_attrs(nfserr, resp); | ||
51 | } | 69 | } |
52 | 70 | ||
53 | /* | 71 | /* |
@@ -58,12 +76,14 @@ static int | |||
58 | nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp, | 76 | nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp, |
59 | struct nfsd_attrstat *resp) | 77 | struct nfsd_attrstat *resp) |
60 | { | 78 | { |
79 | int nfserr; | ||
61 | dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n", | 80 | dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n", |
62 | SVCFH_fmt(&argp->fh), | 81 | SVCFH_fmt(&argp->fh), |
63 | argp->attrs.ia_valid, (long) argp->attrs.ia_size); | 82 | argp->attrs.ia_valid, (long) argp->attrs.ia_size); |
64 | 83 | ||
65 | fh_copy(&resp->fh, &argp->fh); | 84 | fh_copy(&resp->fh, &argp->fh); |
66 | return nfsd_setattr(rqstp, &resp->fh, &argp->attrs,0, (time_t)0); | 85 | nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs,0, (time_t)0); |
86 | return nfsd_return_attrs(nfserr, resp); | ||
67 | } | 87 | } |
68 | 88 | ||
69 | /* | 89 | /* |
@@ -86,7 +106,7 @@ nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp, | |||
86 | &resp->fh); | 106 | &resp->fh); |
87 | 107 | ||
88 | fh_put(&argp->fh); | 108 | fh_put(&argp->fh); |
89 | return nfserr; | 109 | return nfsd_return_dirop(nfserr, resp); |
90 | } | 110 | } |
91 | 111 | ||
92 | /* | 112 | /* |
@@ -142,7 +162,10 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp, | |||
142 | argp->vec, argp->vlen, | 162 | argp->vec, argp->vlen, |
143 | &resp->count); | 163 | &resp->count); |
144 | 164 | ||
145 | return nfserr; | 165 | if (nfserr) return nfserr; |
166 | return nfserrno(vfs_getattr(resp->fh.fh_export->ex_mnt, | ||
167 | resp->fh.fh_dentry, | ||
168 | &resp->stat)); | ||
146 | } | 169 | } |
147 | 170 | ||
148 | /* | 171 | /* |
@@ -165,7 +188,7 @@ nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp, | |||
165 | argp->vec, argp->vlen, | 188 | argp->vec, argp->vlen, |
166 | argp->len, | 189 | argp->len, |
167 | &stable); | 190 | &stable); |
168 | return nfserr; | 191 | return nfsd_return_attrs(nfserr, resp); |
169 | } | 192 | } |
170 | 193 | ||
171 | /* | 194 | /* |
@@ -322,7 +345,7 @@ out_unlock: | |||
322 | 345 | ||
323 | done: | 346 | done: |
324 | fh_put(dirfhp); | 347 | fh_put(dirfhp); |
325 | return nfserr; | 348 | return nfsd_return_dirop(nfserr, resp); |
326 | } | 349 | } |
327 | 350 | ||
328 | static int | 351 | static int |
@@ -425,7 +448,7 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp, | |||
425 | nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len, | 448 | nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len, |
426 | &argp->attrs, S_IFDIR, 0, &resp->fh); | 449 | &argp->attrs, S_IFDIR, 0, &resp->fh); |
427 | fh_put(&argp->fh); | 450 | fh_put(&argp->fh); |
428 | return nfserr; | 451 | return nfsd_return_dirop(nfserr, resp); |
429 | } | 452 | } |
430 | 453 | ||
431 | /* | 454 | /* |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index eef0576a7785..5320e5afaddb 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -710,14 +710,15 @@ static inline int nfsd_dosync(struct file *filp, struct dentry *dp, | |||
710 | { | 710 | { |
711 | struct inode *inode = dp->d_inode; | 711 | struct inode *inode = dp->d_inode; |
712 | int (*fsync) (struct file *, struct dentry *, int); | 712 | int (*fsync) (struct file *, struct dentry *, int); |
713 | int err = nfs_ok; | 713 | int err; |
714 | 714 | ||
715 | filemap_fdatawrite(inode->i_mapping); | 715 | err = filemap_fdatawrite(inode->i_mapping); |
716 | if (fop && (fsync = fop->fsync)) | 716 | if (err == 0 && fop && (fsync = fop->fsync)) |
717 | err=fsync(filp, dp, 0); | 717 | err = fsync(filp, dp, 0); |
718 | filemap_fdatawait(inode->i_mapping); | 718 | if (err == 0) |
719 | err = filemap_fdatawait(inode->i_mapping); | ||
719 | 720 | ||
720 | return nfserrno(err); | 721 | return err; |
721 | } | 722 | } |
722 | 723 | ||
723 | 724 | ||
@@ -734,10 +735,10 @@ nfsd_sync(struct file *filp) | |||
734 | return err; | 735 | return err; |
735 | } | 736 | } |
736 | 737 | ||
737 | void | 738 | int |
738 | nfsd_sync_dir(struct dentry *dp) | 739 | nfsd_sync_dir(struct dentry *dp) |
739 | { | 740 | { |
740 | nfsd_dosync(NULL, dp, dp->d_inode->i_fop); | 741 | return nfsd_dosync(NULL, dp, dp->d_inode->i_fop); |
741 | } | 742 | } |
742 | 743 | ||
743 | /* | 744 | /* |
@@ -814,7 +815,7 @@ nfsd_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset | |||
814 | return size; | 815 | return size; |
815 | } | 816 | } |
816 | 817 | ||
817 | static inline int | 818 | static int |
818 | nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | 819 | nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, |
819 | loff_t offset, struct kvec *vec, int vlen, unsigned long *count) | 820 | loff_t offset, struct kvec *vec, int vlen, unsigned long *count) |
820 | { | 821 | { |
@@ -878,7 +879,7 @@ static void kill_suid(struct dentry *dentry) | |||
878 | mutex_unlock(&dentry->d_inode->i_mutex); | 879 | mutex_unlock(&dentry->d_inode->i_mutex); |
879 | } | 880 | } |
880 | 881 | ||
881 | static inline int | 882 | static int |
882 | nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | 883 | nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, |
883 | loff_t offset, struct kvec *vec, int vlen, | 884 | loff_t offset, struct kvec *vec, int vlen, |
884 | unsigned long cnt, int *stablep) | 885 | unsigned long cnt, int *stablep) |
@@ -890,9 +891,9 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
890 | int err = 0; | 891 | int err = 0; |
891 | int stable = *stablep; | 892 | int stable = *stablep; |
892 | 893 | ||
894 | #ifdef MSNFS | ||
893 | err = nfserr_perm; | 895 | err = nfserr_perm; |
894 | 896 | ||
895 | #ifdef MSNFS | ||
896 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && | 897 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && |
897 | (!lock_may_write(file->f_dentry->d_inode, offset, cnt))) | 898 | (!lock_may_write(file->f_dentry->d_inode, offset, cnt))) |
898 | goto out; | 899 | goto out; |
@@ -1064,7 +1065,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1064 | return err; | 1065 | return err; |
1065 | if (EX_ISSYNC(fhp->fh_export)) { | 1066 | if (EX_ISSYNC(fhp->fh_export)) { |
1066 | if (file->f_op && file->f_op->fsync) { | 1067 | if (file->f_op && file->f_op->fsync) { |
1067 | err = nfsd_sync(file); | 1068 | err = nfserrno(nfsd_sync(file)); |
1068 | } else { | 1069 | } else { |
1069 | err = nfserr_notsupp; | 1070 | err = nfserr_notsupp; |
1070 | } | 1071 | } |
@@ -1132,7 +1133,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1132 | "nfsd_create: parent %s/%s not locked!\n", | 1133 | "nfsd_create: parent %s/%s not locked!\n", |
1133 | dentry->d_parent->d_name.name, | 1134 | dentry->d_parent->d_name.name, |
1134 | dentry->d_name.name); | 1135 | dentry->d_name.name); |
1135 | err = -EIO; | 1136 | err = nfserr_io; |
1136 | goto out; | 1137 | goto out; |
1137 | } | 1138 | } |
1138 | } | 1139 | } |
@@ -1175,7 +1176,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1175 | goto out_nfserr; | 1176 | goto out_nfserr; |
1176 | 1177 | ||
1177 | if (EX_ISSYNC(fhp->fh_export)) { | 1178 | if (EX_ISSYNC(fhp->fh_export)) { |
1178 | nfsd_sync_dir(dentry); | 1179 | err = nfserrno(nfsd_sync_dir(dentry)); |
1179 | write_inode_now(dchild->d_inode, 1); | 1180 | write_inode_now(dchild->d_inode, 1); |
1180 | } | 1181 | } |
1181 | 1182 | ||
@@ -1185,9 +1186,11 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1185 | * send along the gid when it tries to implement setgid | 1186 | * send along the gid when it tries to implement setgid |
1186 | * directories via NFS. | 1187 | * directories via NFS. |
1187 | */ | 1188 | */ |
1188 | err = 0; | 1189 | if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) { |
1189 | if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) | 1190 | int err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); |
1190 | err = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); | 1191 | if (err2) |
1192 | err = err2; | ||
1193 | } | ||
1191 | /* | 1194 | /* |
1192 | * Update the file handle to get the new inode info. | 1195 | * Update the file handle to get the new inode info. |
1193 | */ | 1196 | */ |
@@ -1306,17 +1309,10 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1306 | goto out_nfserr; | 1309 | goto out_nfserr; |
1307 | 1310 | ||
1308 | if (EX_ISSYNC(fhp->fh_export)) { | 1311 | if (EX_ISSYNC(fhp->fh_export)) { |
1309 | nfsd_sync_dir(dentry); | 1312 | err = nfserrno(nfsd_sync_dir(dentry)); |
1310 | /* setattr will sync the child (or not) */ | 1313 | /* setattr will sync the child (or not) */ |
1311 | } | 1314 | } |
1312 | 1315 | ||
1313 | /* | ||
1314 | * Update the filehandle to get the new inode info. | ||
1315 | */ | ||
1316 | err = fh_update(resfhp); | ||
1317 | if (err) | ||
1318 | goto out; | ||
1319 | |||
1320 | if (createmode == NFS3_CREATE_EXCLUSIVE) { | 1316 | if (createmode == NFS3_CREATE_EXCLUSIVE) { |
1321 | /* Cram the verifier into atime/mtime/mode */ | 1317 | /* Cram the verifier into atime/mtime/mode */ |
1322 | iap->ia_valid = ATTR_MTIME|ATTR_ATIME | 1318 | iap->ia_valid = ATTR_MTIME|ATTR_ATIME |
@@ -1337,8 +1333,17 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1337 | * implement setgid directories via NFS. Clear out all that cruft. | 1333 | * implement setgid directories via NFS. Clear out all that cruft. |
1338 | */ | 1334 | */ |
1339 | set_attr: | 1335 | set_attr: |
1340 | if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0) | 1336 | if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0) { |
1341 | err = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); | 1337 | int err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0); |
1338 | if (err2) | ||
1339 | err = err2; | ||
1340 | } | ||
1341 | |||
1342 | /* | ||
1343 | * Update the filehandle to get the new inode info. | ||
1344 | */ | ||
1345 | if (!err) | ||
1346 | err = fh_update(resfhp); | ||
1342 | 1347 | ||
1343 | out: | 1348 | out: |
1344 | fh_unlock(fhp); | 1349 | fh_unlock(fhp); |
@@ -1447,10 +1452,10 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1447 | } else | 1452 | } else |
1448 | err = vfs_symlink(dentry->d_inode, dnew, path, mode); | 1453 | err = vfs_symlink(dentry->d_inode, dnew, path, mode); |
1449 | 1454 | ||
1450 | if (!err) { | 1455 | if (!err) |
1451 | if (EX_ISSYNC(fhp->fh_export)) | 1456 | if (EX_ISSYNC(fhp->fh_export)) |
1452 | nfsd_sync_dir(dentry); | 1457 | err = nfsd_sync_dir(dentry); |
1453 | } else | 1458 | if (err) |
1454 | err = nfserrno(err); | 1459 | err = nfserrno(err); |
1455 | fh_unlock(fhp); | 1460 | fh_unlock(fhp); |
1456 | 1461 | ||
@@ -1506,7 +1511,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | |||
1506 | err = vfs_link(dold, dirp, dnew); | 1511 | err = vfs_link(dold, dirp, dnew); |
1507 | if (!err) { | 1512 | if (!err) { |
1508 | if (EX_ISSYNC(ffhp->fh_export)) { | 1513 | if (EX_ISSYNC(ffhp->fh_export)) { |
1509 | nfsd_sync_dir(ddir); | 1514 | err = nfserrno(nfsd_sync_dir(ddir)); |
1510 | write_inode_now(dest, 1); | 1515 | write_inode_now(dest, 1); |
1511 | } | 1516 | } |
1512 | } else { | 1517 | } else { |
@@ -1590,13 +1595,14 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
1590 | if ((ffhp->fh_export->ex_flags & NFSEXP_MSNFS) && | 1595 | if ((ffhp->fh_export->ex_flags & NFSEXP_MSNFS) && |
1591 | ((atomic_read(&odentry->d_count) > 1) | 1596 | ((atomic_read(&odentry->d_count) > 1) |
1592 | || (atomic_read(&ndentry->d_count) > 1))) { | 1597 | || (atomic_read(&ndentry->d_count) > 1))) { |
1593 | err = nfserr_perm; | 1598 | err = -EPERM; |
1594 | } else | 1599 | } else |
1595 | #endif | 1600 | #endif |
1596 | err = vfs_rename(fdir, odentry, tdir, ndentry); | 1601 | err = vfs_rename(fdir, odentry, tdir, ndentry); |
1597 | if (!err && EX_ISSYNC(tfhp->fh_export)) { | 1602 | if (!err && EX_ISSYNC(tfhp->fh_export)) { |
1598 | nfsd_sync_dir(tdentry); | 1603 | err = nfsd_sync_dir(tdentry); |
1599 | nfsd_sync_dir(fdentry); | 1604 | if (!err) |
1605 | err = nfsd_sync_dir(fdentry); | ||
1600 | } | 1606 | } |
1601 | 1607 | ||
1602 | out_dput_new: | 1608 | out_dput_new: |
@@ -1661,7 +1667,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
1661 | #ifdef MSNFS | 1667 | #ifdef MSNFS |
1662 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && | 1668 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && |
1663 | (atomic_read(&rdentry->d_count) > 1)) { | 1669 | (atomic_read(&rdentry->d_count) > 1)) { |
1664 | err = nfserr_perm; | 1670 | err = -EPERM; |
1665 | } else | 1671 | } else |
1666 | #endif | 1672 | #endif |
1667 | err = vfs_unlink(dirp, rdentry); | 1673 | err = vfs_unlink(dirp, rdentry); |
@@ -1671,17 +1677,14 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
1671 | 1677 | ||
1672 | dput(rdentry); | 1678 | dput(rdentry); |
1673 | 1679 | ||
1674 | if (err) | 1680 | if (err == 0 && |
1675 | goto out_nfserr; | 1681 | EX_ISSYNC(fhp->fh_export)) |
1676 | if (EX_ISSYNC(fhp->fh_export)) | 1682 | err = nfsd_sync_dir(dentry); |
1677 | nfsd_sync_dir(dentry); | ||
1678 | |||
1679 | out: | ||
1680 | return err; | ||
1681 | 1683 | ||
1682 | out_nfserr: | 1684 | out_nfserr: |
1683 | err = nfserrno(err); | 1685 | err = nfserrno(err); |
1684 | goto out; | 1686 | out: |
1687 | return err; | ||
1685 | } | 1688 | } |
1686 | 1689 | ||
1687 | /* | 1690 | /* |
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/security.h> | 20 | #include <linux/security.h> |
21 | #include <linux/mount.h> | 21 | #include <linux/mount.h> |
22 | #include <linux/vfs.h> | 22 | #include <linux/vfs.h> |
23 | #include <linux/fcntl.h> | ||
23 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
24 | #include <linux/fs.h> | 25 | #include <linux/fs.h> |
25 | #include <linux/personality.h> | 26 | #include <linux/personality.h> |
@@ -383,7 +384,7 @@ asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times) | |||
383 | 384 | ||
384 | error = get_user(newattrs.ia_atime.tv_sec, ×->actime); | 385 | error = get_user(newattrs.ia_atime.tv_sec, ×->actime); |
385 | newattrs.ia_atime.tv_nsec = 0; | 386 | newattrs.ia_atime.tv_nsec = 0; |
386 | if (!error) | 387 | if (!error) |
387 | error = get_user(newattrs.ia_mtime.tv_sec, ×->modtime); | 388 | error = get_user(newattrs.ia_mtime.tv_sec, ×->modtime); |
388 | newattrs.ia_mtime.tv_nsec = 0; | 389 | newattrs.ia_mtime.tv_nsec = 0; |
389 | if (error) | 390 | if (error) |
@@ -414,14 +415,14 @@ out: | |||
414 | * must be owner or have write permission. | 415 | * must be owner or have write permission. |
415 | * Else, update from *times, must be owner or super user. | 416 | * Else, update from *times, must be owner or super user. |
416 | */ | 417 | */ |
417 | long do_utimes(char __user * filename, struct timeval * times) | 418 | long do_utimes(int dfd, char __user *filename, struct timeval *times) |
418 | { | 419 | { |
419 | int error; | 420 | int error; |
420 | struct nameidata nd; | 421 | struct nameidata nd; |
421 | struct inode * inode; | 422 | struct inode * inode; |
422 | struct iattr newattrs; | 423 | struct iattr newattrs; |
423 | 424 | ||
424 | error = user_path_walk(filename, &nd); | 425 | error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd); |
425 | 426 | ||
426 | if (error) | 427 | if (error) |
427 | goto out; | 428 | goto out; |
@@ -461,13 +462,18 @@ out: | |||
461 | return error; | 462 | return error; |
462 | } | 463 | } |
463 | 464 | ||
464 | asmlinkage long sys_utimes(char __user * filename, struct timeval __user * utimes) | 465 | asmlinkage long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes) |
465 | { | 466 | { |
466 | struct timeval times[2]; | 467 | struct timeval times[2]; |
467 | 468 | ||
468 | if (utimes && copy_from_user(×, utimes, sizeof(times))) | 469 | if (utimes && copy_from_user(×, utimes, sizeof(times))) |
469 | return -EFAULT; | 470 | return -EFAULT; |
470 | return do_utimes(filename, utimes ? times : NULL); | 471 | return do_utimes(dfd, filename, utimes ? times : NULL); |
472 | } | ||
473 | |||
474 | asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes) | ||
475 | { | ||
476 | return sys_futimesat(AT_FDCWD, filename, utimes); | ||
471 | } | 477 | } |
472 | 478 | ||
473 | 479 | ||
@@ -476,7 +482,7 @@ asmlinkage long sys_utimes(char __user * filename, struct timeval __user * utime | |||
476 | * We do this by temporarily clearing all FS-related capabilities and | 482 | * We do this by temporarily clearing all FS-related capabilities and |
477 | * switching the fsuid/fsgid around to the real ones. | 483 | * switching the fsuid/fsgid around to the real ones. |
478 | */ | 484 | */ |
479 | asmlinkage long sys_access(const char __user * filename, int mode) | 485 | asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode) |
480 | { | 486 | { |
481 | struct nameidata nd; | 487 | struct nameidata nd; |
482 | int old_fsuid, old_fsgid; | 488 | int old_fsuid, old_fsgid; |
@@ -506,7 +512,7 @@ asmlinkage long sys_access(const char __user * filename, int mode) | |||
506 | else | 512 | else |
507 | current->cap_effective = current->cap_permitted; | 513 | current->cap_effective = current->cap_permitted; |
508 | 514 | ||
509 | res = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd); | 515 | res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd); |
510 | if (!res) { | 516 | if (!res) { |
511 | res = vfs_permission(&nd, mode); | 517 | res = vfs_permission(&nd, mode); |
512 | /* SuS v2 requires we report a read only fs too */ | 518 | /* SuS v2 requires we report a read only fs too */ |
@@ -523,6 +529,11 @@ asmlinkage long sys_access(const char __user * filename, int mode) | |||
523 | return res; | 529 | return res; |
524 | } | 530 | } |
525 | 531 | ||
532 | asmlinkage long sys_access(const char __user *filename, int mode) | ||
533 | { | ||
534 | return sys_faccessat(AT_FDCWD, filename, mode); | ||
535 | } | ||
536 | |||
526 | asmlinkage long sys_chdir(const char __user * filename) | 537 | asmlinkage long sys_chdir(const char __user * filename) |
527 | { | 538 | { |
528 | struct nameidata nd; | 539 | struct nameidata nd; |
@@ -635,14 +646,15 @@ out: | |||
635 | return err; | 646 | return err; |
636 | } | 647 | } |
637 | 648 | ||
638 | asmlinkage long sys_chmod(const char __user * filename, mode_t mode) | 649 | asmlinkage long sys_fchmodat(int dfd, const char __user *filename, |
650 | mode_t mode) | ||
639 | { | 651 | { |
640 | struct nameidata nd; | 652 | struct nameidata nd; |
641 | struct inode * inode; | 653 | struct inode * inode; |
642 | int error; | 654 | int error; |
643 | struct iattr newattrs; | 655 | struct iattr newattrs; |
644 | 656 | ||
645 | error = user_path_walk(filename, &nd); | 657 | error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd); |
646 | if (error) | 658 | if (error) |
647 | goto out; | 659 | goto out; |
648 | inode = nd.dentry->d_inode; | 660 | inode = nd.dentry->d_inode; |
@@ -669,6 +681,11 @@ out: | |||
669 | return error; | 681 | return error; |
670 | } | 682 | } |
671 | 683 | ||
684 | asmlinkage long sys_chmod(const char __user *filename, mode_t mode) | ||
685 | { | ||
686 | return sys_fchmodat(AT_FDCWD, filename, mode); | ||
687 | } | ||
688 | |||
672 | static int chown_common(struct dentry * dentry, uid_t user, gid_t group) | 689 | static int chown_common(struct dentry * dentry, uid_t user, gid_t group) |
673 | { | 690 | { |
674 | struct inode * inode; | 691 | struct inode * inode; |
@@ -717,6 +734,26 @@ asmlinkage long sys_chown(const char __user * filename, uid_t user, gid_t group) | |||
717 | return error; | 734 | return error; |
718 | } | 735 | } |
719 | 736 | ||
737 | asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user, | ||
738 | gid_t group, int flag) | ||
739 | { | ||
740 | struct nameidata nd; | ||
741 | int error = -EINVAL; | ||
742 | int follow; | ||
743 | |||
744 | if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0) | ||
745 | goto out; | ||
746 | |||
747 | follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; | ||
748 | error = __user_walk_fd(dfd, filename, follow, &nd); | ||
749 | if (!error) { | ||
750 | error = chown_common(nd.dentry, user, group); | ||
751 | path_release(&nd); | ||
752 | } | ||
753 | out: | ||
754 | return error; | ||
755 | } | ||
756 | |||
720 | asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group) | 757 | asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group) |
721 | { | 758 | { |
722 | struct nameidata nd; | 759 | struct nameidata nd; |
@@ -820,7 +857,8 @@ cleanup_file: | |||
820 | * for the internal routines (ie open_namei()/follow_link() etc). 00 is | 857 | * for the internal routines (ie open_namei()/follow_link() etc). 00 is |
821 | * used by symlinks. | 858 | * used by symlinks. |
822 | */ | 859 | */ |
823 | struct file *filp_open(const char * filename, int flags, int mode) | 860 | static struct file *do_filp_open(int dfd, const char *filename, int flags, |
861 | int mode) | ||
824 | { | 862 | { |
825 | int namei_flags, error; | 863 | int namei_flags, error; |
826 | struct nameidata nd; | 864 | struct nameidata nd; |
@@ -829,12 +867,17 @@ struct file *filp_open(const char * filename, int flags, int mode) | |||
829 | if ((namei_flags+1) & O_ACCMODE) | 867 | if ((namei_flags+1) & O_ACCMODE) |
830 | namei_flags++; | 868 | namei_flags++; |
831 | 869 | ||
832 | error = open_namei(filename, namei_flags, mode, &nd); | 870 | error = open_namei(dfd, filename, namei_flags, mode, &nd); |
833 | if (!error) | 871 | if (!error) |
834 | return nameidata_to_filp(&nd, flags); | 872 | return nameidata_to_filp(&nd, flags); |
835 | 873 | ||
836 | return ERR_PTR(error); | 874 | return ERR_PTR(error); |
837 | } | 875 | } |
876 | |||
877 | struct file *filp_open(const char *filename, int flags, int mode) | ||
878 | { | ||
879 | return do_filp_open(AT_FDCWD, filename, flags, mode); | ||
880 | } | ||
838 | EXPORT_SYMBOL(filp_open); | 881 | EXPORT_SYMBOL(filp_open); |
839 | 882 | ||
840 | /** | 883 | /** |
@@ -991,7 +1034,7 @@ void fastcall put_unused_fd(unsigned int fd) | |||
991 | EXPORT_SYMBOL(put_unused_fd); | 1034 | EXPORT_SYMBOL(put_unused_fd); |
992 | 1035 | ||
993 | /* | 1036 | /* |
994 | * Install a file pointer in the fd array. | 1037 | * Install a file pointer in the fd array. |
995 | * | 1038 | * |
996 | * The VFS is full of places where we drop the files lock between | 1039 | * The VFS is full of places where we drop the files lock between |
997 | * setting the open_fds bitmap and installing the file in the file | 1040 | * setting the open_fds bitmap and installing the file in the file |
@@ -1016,7 +1059,7 @@ void fastcall fd_install(unsigned int fd, struct file * file) | |||
1016 | 1059 | ||
1017 | EXPORT_SYMBOL(fd_install); | 1060 | EXPORT_SYMBOL(fd_install); |
1018 | 1061 | ||
1019 | long do_sys_open(const char __user *filename, int flags, int mode) | 1062 | long do_sys_open(int dfd, const char __user *filename, int flags, int mode) |
1020 | { | 1063 | { |
1021 | char *tmp = getname(filename); | 1064 | char *tmp = getname(filename); |
1022 | int fd = PTR_ERR(tmp); | 1065 | int fd = PTR_ERR(tmp); |
@@ -1024,7 +1067,7 @@ long do_sys_open(const char __user *filename, int flags, int mode) | |||
1024 | if (!IS_ERR(tmp)) { | 1067 | if (!IS_ERR(tmp)) { |
1025 | fd = get_unused_fd(); | 1068 | fd = get_unused_fd(); |
1026 | if (fd >= 0) { | 1069 | if (fd >= 0) { |
1027 | struct file *f = filp_open(tmp, flags, mode); | 1070 | struct file *f = do_filp_open(dfd, tmp, flags, mode); |
1028 | if (IS_ERR(f)) { | 1071 | if (IS_ERR(f)) { |
1029 | put_unused_fd(fd); | 1072 | put_unused_fd(fd); |
1030 | fd = PTR_ERR(f); | 1073 | fd = PTR_ERR(f); |
@@ -1043,10 +1086,20 @@ asmlinkage long sys_open(const char __user *filename, int flags, int mode) | |||
1043 | if (force_o_largefile()) | 1086 | if (force_o_largefile()) |
1044 | flags |= O_LARGEFILE; | 1087 | flags |= O_LARGEFILE; |
1045 | 1088 | ||
1046 | return do_sys_open(filename, flags, mode); | 1089 | return do_sys_open(AT_FDCWD, filename, flags, mode); |
1047 | } | 1090 | } |
1048 | EXPORT_SYMBOL_GPL(sys_open); | 1091 | EXPORT_SYMBOL_GPL(sys_open); |
1049 | 1092 | ||
1093 | asmlinkage long sys_openat(int dfd, const char __user *filename, int flags, | ||
1094 | int mode) | ||
1095 | { | ||
1096 | if (force_o_largefile()) | ||
1097 | flags |= O_LARGEFILE; | ||
1098 | |||
1099 | return do_sys_open(dfd, filename, flags, mode); | ||
1100 | } | ||
1101 | EXPORT_SYMBOL_GPL(sys_openat); | ||
1102 | |||
1050 | #ifndef __alpha__ | 1103 | #ifndef __alpha__ |
1051 | 1104 | ||
1052 | /* | 1105 | /* |
diff --git a/fs/select.c b/fs/select.c index f10a10317d54..c0f02d36c60e 100644 --- a/fs/select.c +++ b/fs/select.c | |||
@@ -179,12 +179,11 @@ get_max: | |||
179 | #define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR) | 179 | #define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR) |
180 | #define POLLEX_SET (POLLPRI) | 180 | #define POLLEX_SET (POLLPRI) |
181 | 181 | ||
182 | int do_select(int n, fd_set_bits *fds, long *timeout) | 182 | int do_select(int n, fd_set_bits *fds, s64 *timeout) |
183 | { | 183 | { |
184 | struct poll_wqueues table; | 184 | struct poll_wqueues table; |
185 | poll_table *wait; | 185 | poll_table *wait; |
186 | int retval, i; | 186 | int retval, i; |
187 | long __timeout = *timeout; | ||
188 | 187 | ||
189 | rcu_read_lock(); | 188 | rcu_read_lock(); |
190 | retval = max_select_fd(n, fds); | 189 | retval = max_select_fd(n, fds); |
@@ -196,11 +195,12 @@ int do_select(int n, fd_set_bits *fds, long *timeout) | |||
196 | 195 | ||
197 | poll_initwait(&table); | 196 | poll_initwait(&table); |
198 | wait = &table.pt; | 197 | wait = &table.pt; |
199 | if (!__timeout) | 198 | if (!*timeout) |
200 | wait = NULL; | 199 | wait = NULL; |
201 | retval = 0; | 200 | retval = 0; |
202 | for (;;) { | 201 | for (;;) { |
203 | unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp; | 202 | unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp; |
203 | long __timeout; | ||
204 | 204 | ||
205 | set_current_state(TASK_INTERRUPTIBLE); | 205 | set_current_state(TASK_INTERRUPTIBLE); |
206 | 206 | ||
@@ -255,22 +255,32 @@ int do_select(int n, fd_set_bits *fds, long *timeout) | |||
255 | *rexp = res_ex; | 255 | *rexp = res_ex; |
256 | } | 256 | } |
257 | wait = NULL; | 257 | wait = NULL; |
258 | if (retval || !__timeout || signal_pending(current)) | 258 | if (retval || !*timeout || signal_pending(current)) |
259 | break; | 259 | break; |
260 | if(table.error) { | 260 | if(table.error) { |
261 | retval = table.error; | 261 | retval = table.error; |
262 | break; | 262 | break; |
263 | } | 263 | } |
264 | |||
265 | if (*timeout < 0) { | ||
266 | /* Wait indefinitely */ | ||
267 | __timeout = MAX_SCHEDULE_TIMEOUT; | ||
268 | } else if (unlikely(*timeout >= (s64)MAX_SCHEDULE_TIMEOUT - 1)) { | ||
269 | /* Wait for longer than MAX_SCHEDULE_TIMEOUT. Do it in a loop */ | ||
270 | __timeout = MAX_SCHEDULE_TIMEOUT - 1; | ||
271 | *timeout -= __timeout; | ||
272 | } else { | ||
273 | __timeout = *timeout; | ||
274 | *timeout = 0; | ||
275 | } | ||
264 | __timeout = schedule_timeout(__timeout); | 276 | __timeout = schedule_timeout(__timeout); |
277 | if (*timeout >= 0) | ||
278 | *timeout += __timeout; | ||
265 | } | 279 | } |
266 | __set_current_state(TASK_RUNNING); | 280 | __set_current_state(TASK_RUNNING); |
267 | 281 | ||
268 | poll_freewait(&table); | 282 | poll_freewait(&table); |
269 | 283 | ||
270 | /* | ||
271 | * Up-to-date the caller timeout. | ||
272 | */ | ||
273 | *timeout = __timeout; | ||
274 | return retval; | 284 | return retval; |
275 | } | 285 | } |
276 | 286 | ||
@@ -295,36 +305,14 @@ static void select_bits_free(void *bits, int size) | |||
295 | #define MAX_SELECT_SECONDS \ | 305 | #define MAX_SELECT_SECONDS \ |
296 | ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) | 306 | ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) |
297 | 307 | ||
298 | asmlinkage long | 308 | static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp, |
299 | sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, struct timeval __user *tvp) | 309 | fd_set __user *exp, s64 *timeout) |
300 | { | 310 | { |
301 | fd_set_bits fds; | 311 | fd_set_bits fds; |
302 | char *bits; | 312 | char *bits; |
303 | long timeout; | ||
304 | int ret, size, max_fdset; | 313 | int ret, size, max_fdset; |
305 | struct fdtable *fdt; | 314 | struct fdtable *fdt; |
306 | 315 | ||
307 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
308 | if (tvp) { | ||
309 | time_t sec, usec; | ||
310 | |||
311 | if (!access_ok(VERIFY_READ, tvp, sizeof(*tvp)) | ||
312 | || __get_user(sec, &tvp->tv_sec) | ||
313 | || __get_user(usec, &tvp->tv_usec)) { | ||
314 | ret = -EFAULT; | ||
315 | goto out_nofds; | ||
316 | } | ||
317 | |||
318 | ret = -EINVAL; | ||
319 | if (sec < 0 || usec < 0) | ||
320 | goto out_nofds; | ||
321 | |||
322 | if ((unsigned long) sec < MAX_SELECT_SECONDS) { | ||
323 | timeout = ROUND_UP(usec, 1000000/HZ); | ||
324 | timeout += sec * (unsigned long) HZ; | ||
325 | } | ||
326 | } | ||
327 | |||
328 | ret = -EINVAL; | 316 | ret = -EINVAL; |
329 | if (n < 0) | 317 | if (n < 0) |
330 | goto out_nofds; | 318 | goto out_nofds; |
@@ -362,18 +350,7 @@ sys_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, s | |||
362 | zero_fd_set(n, fds.res_out); | 350 | zero_fd_set(n, fds.res_out); |
363 | zero_fd_set(n, fds.res_ex); | 351 | zero_fd_set(n, fds.res_ex); |
364 | 352 | ||
365 | ret = do_select(n, &fds, &timeout); | 353 | ret = do_select(n, &fds, timeout); |
366 | |||
367 | if (tvp && !(current->personality & STICKY_TIMEOUTS)) { | ||
368 | time_t sec = 0, usec = 0; | ||
369 | if (timeout) { | ||
370 | sec = timeout / HZ; | ||
371 | usec = timeout % HZ; | ||
372 | usec *= (1000000/HZ); | ||
373 | } | ||
374 | put_user(sec, &tvp->tv_sec); | ||
375 | put_user(usec, &tvp->tv_usec); | ||
376 | } | ||
377 | 354 | ||
378 | if (ret < 0) | 355 | if (ret < 0) |
379 | goto out; | 356 | goto out; |
@@ -395,6 +372,154 @@ out_nofds: | |||
395 | return ret; | 372 | return ret; |
396 | } | 373 | } |
397 | 374 | ||
375 | asmlinkage long sys_select(int n, fd_set __user *inp, fd_set __user *outp, | ||
376 | fd_set __user *exp, struct timeval __user *tvp) | ||
377 | { | ||
378 | s64 timeout = -1; | ||
379 | struct timeval tv; | ||
380 | int ret; | ||
381 | |||
382 | if (tvp) { | ||
383 | if (copy_from_user(&tv, tvp, sizeof(tv))) | ||
384 | return -EFAULT; | ||
385 | |||
386 | if (tv.tv_sec < 0 || tv.tv_usec < 0) | ||
387 | return -EINVAL; | ||
388 | |||
389 | /* Cast to u64 to make GCC stop complaining */ | ||
390 | if ((u64)tv.tv_sec >= (u64)MAX_INT64_SECONDS) | ||
391 | timeout = -1; /* infinite */ | ||
392 | else { | ||
393 | timeout = ROUND_UP(tv.tv_usec, USEC_PER_SEC/HZ); | ||
394 | timeout += tv.tv_sec * HZ; | ||
395 | } | ||
396 | } | ||
397 | |||
398 | ret = core_sys_select(n, inp, outp, exp, &timeout); | ||
399 | |||
400 | if (tvp) { | ||
401 | if (current->personality & STICKY_TIMEOUTS) | ||
402 | goto sticky; | ||
403 | tv.tv_usec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ)); | ||
404 | tv.tv_sec = timeout; | ||
405 | if (copy_to_user(tvp, &tv, sizeof(tv))) { | ||
406 | sticky: | ||
407 | /* | ||
408 | * If an application puts its timeval in read-only | ||
409 | * memory, we don't want the Linux-specific update to | ||
410 | * the timeval to cause a fault after the select has | ||
411 | * completed successfully. However, because we're not | ||
412 | * updating the timeval, we can't restart the system | ||
413 | * call. | ||
414 | */ | ||
415 | if (ret == -ERESTARTNOHAND) | ||
416 | ret = -EINTR; | ||
417 | } | ||
418 | } | ||
419 | |||
420 | return ret; | ||
421 | } | ||
422 | |||
423 | #ifdef TIF_RESTORE_SIGMASK | ||
424 | asmlinkage long sys_pselect7(int n, fd_set __user *inp, fd_set __user *outp, | ||
425 | fd_set __user *exp, struct timespec __user *tsp, | ||
426 | const sigset_t __user *sigmask, size_t sigsetsize) | ||
427 | { | ||
428 | s64 timeout = MAX_SCHEDULE_TIMEOUT; | ||
429 | sigset_t ksigmask, sigsaved; | ||
430 | struct timespec ts; | ||
431 | int ret; | ||
432 | |||
433 | if (tsp) { | ||
434 | if (copy_from_user(&ts, tsp, sizeof(ts))) | ||
435 | return -EFAULT; | ||
436 | |||
437 | if (ts.tv_sec < 0 || ts.tv_nsec < 0) | ||
438 | return -EINVAL; | ||
439 | |||
440 | /* Cast to u64 to make GCC stop complaining */ | ||
441 | if ((u64)ts.tv_sec >= (u64)MAX_INT64_SECONDS) | ||
442 | timeout = -1; /* infinite */ | ||
443 | else { | ||
444 | timeout = ROUND_UP(ts.tv_nsec, NSEC_PER_SEC/HZ); | ||
445 | timeout += ts.tv_sec * HZ; | ||
446 | } | ||
447 | } | ||
448 | |||
449 | if (sigmask) { | ||
450 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
451 | if (sigsetsize != sizeof(sigset_t)) | ||
452 | return -EINVAL; | ||
453 | if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask))) | ||
454 | return -EFAULT; | ||
455 | |||
456 | sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); | ||
457 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | ||
458 | } | ||
459 | |||
460 | ret = core_sys_select(n, inp, outp, exp, &timeout); | ||
461 | |||
462 | if (tsp) { | ||
463 | if (current->personality & STICKY_TIMEOUTS) | ||
464 | goto sticky; | ||
465 | ts.tv_nsec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ)) * 1000; | ||
466 | ts.tv_sec = timeout; | ||
467 | if (copy_to_user(tsp, &ts, sizeof(ts))) { | ||
468 | sticky: | ||
469 | /* | ||
470 | * If an application puts its timeval in read-only | ||
471 | * memory, we don't want the Linux-specific update to | ||
472 | * the timeval to cause a fault after the select has | ||
473 | * completed successfully. However, because we're not | ||
474 | * updating the timeval, we can't restart the system | ||
475 | * call. | ||
476 | */ | ||
477 | if (ret == -ERESTARTNOHAND) | ||
478 | ret = -EINTR; | ||
479 | } | ||
480 | } | ||
481 | |||
482 | if (ret == -ERESTARTNOHAND) { | ||
483 | /* | ||
484 | * Don't restore the signal mask yet. Let do_signal() deliver | ||
485 | * the signal on the way back to userspace, before the signal | ||
486 | * mask is restored. | ||
487 | */ | ||
488 | if (sigmask) { | ||
489 | memcpy(¤t->saved_sigmask, &sigsaved, | ||
490 | sizeof(sigsaved)); | ||
491 | set_thread_flag(TIF_RESTORE_SIGMASK); | ||
492 | } | ||
493 | } else if (sigmask) | ||
494 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
495 | |||
496 | return ret; | ||
497 | } | ||
498 | |||
499 | /* | ||
500 | * Most architectures can't handle 7-argument syscalls. So we provide a | ||
501 | * 6-argument version where the sixth argument is a pointer to a structure | ||
502 | * which has a pointer to the sigset_t itself followed by a size_t containing | ||
503 | * the sigset size. | ||
504 | */ | ||
505 | asmlinkage long sys_pselect6(int n, fd_set __user *inp, fd_set __user *outp, | ||
506 | fd_set __user *exp, struct timespec __user *tsp, void __user *sig) | ||
507 | { | ||
508 | size_t sigsetsize = 0; | ||
509 | sigset_t __user *up = NULL; | ||
510 | |||
511 | if (sig) { | ||
512 | if (!access_ok(VERIFY_READ, sig, sizeof(void *)+sizeof(size_t)) | ||
513 | || __get_user(up, (sigset_t * __user *)sig) | ||
514 | || __get_user(sigsetsize, | ||
515 | (size_t * __user)(sig+sizeof(void *)))) | ||
516 | return -EFAULT; | ||
517 | } | ||
518 | |||
519 | return sys_pselect7(n, inp, outp, exp, tsp, up, sigsetsize); | ||
520 | } | ||
521 | #endif /* TIF_RESTORE_SIGMASK */ | ||
522 | |||
398 | struct poll_list { | 523 | struct poll_list { |
399 | struct poll_list *next; | 524 | struct poll_list *next; |
400 | int len; | 525 | int len; |
@@ -436,16 +561,19 @@ static void do_pollfd(unsigned int num, struct pollfd * fdpage, | |||
436 | } | 561 | } |
437 | 562 | ||
438 | static int do_poll(unsigned int nfds, struct poll_list *list, | 563 | static int do_poll(unsigned int nfds, struct poll_list *list, |
439 | struct poll_wqueues *wait, long timeout) | 564 | struct poll_wqueues *wait, s64 *timeout) |
440 | { | 565 | { |
441 | int count = 0; | 566 | int count = 0; |
442 | poll_table* pt = &wait->pt; | 567 | poll_table* pt = &wait->pt; |
443 | 568 | ||
444 | if (!timeout) | 569 | /* Optimise the no-wait case */ |
570 | if (!(*timeout)) | ||
445 | pt = NULL; | 571 | pt = NULL; |
446 | 572 | ||
447 | for (;;) { | 573 | for (;;) { |
448 | struct poll_list *walk; | 574 | struct poll_list *walk; |
575 | long __timeout; | ||
576 | |||
449 | set_current_state(TASK_INTERRUPTIBLE); | 577 | set_current_state(TASK_INTERRUPTIBLE); |
450 | walk = list; | 578 | walk = list; |
451 | while(walk != NULL) { | 579 | while(walk != NULL) { |
@@ -453,18 +581,36 @@ static int do_poll(unsigned int nfds, struct poll_list *list, | |||
453 | walk = walk->next; | 581 | walk = walk->next; |
454 | } | 582 | } |
455 | pt = NULL; | 583 | pt = NULL; |
456 | if (count || !timeout || signal_pending(current)) | 584 | if (count || !*timeout || signal_pending(current)) |
457 | break; | 585 | break; |
458 | count = wait->error; | 586 | count = wait->error; |
459 | if (count) | 587 | if (count) |
460 | break; | 588 | break; |
461 | timeout = schedule_timeout(timeout); | 589 | |
590 | if (*timeout < 0) { | ||
591 | /* Wait indefinitely */ | ||
592 | __timeout = MAX_SCHEDULE_TIMEOUT; | ||
593 | } else if (unlikely(*timeout >= (s64)MAX_SCHEDULE_TIMEOUT-1)) { | ||
594 | /* | ||
595 | * Wait for longer than MAX_SCHEDULE_TIMEOUT. Do it in | ||
596 | * a loop | ||
597 | */ | ||
598 | __timeout = MAX_SCHEDULE_TIMEOUT - 1; | ||
599 | *timeout -= __timeout; | ||
600 | } else { | ||
601 | __timeout = *timeout; | ||
602 | *timeout = 0; | ||
603 | } | ||
604 | |||
605 | __timeout = schedule_timeout(__timeout); | ||
606 | if (*timeout >= 0) | ||
607 | *timeout += __timeout; | ||
462 | } | 608 | } |
463 | __set_current_state(TASK_RUNNING); | 609 | __set_current_state(TASK_RUNNING); |
464 | return count; | 610 | return count; |
465 | } | 611 | } |
466 | 612 | ||
467 | asmlinkage long sys_poll(struct pollfd __user * ufds, unsigned int nfds, long timeout) | 613 | int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout) |
468 | { | 614 | { |
469 | struct poll_wqueues table; | 615 | struct poll_wqueues table; |
470 | int fdcount, err; | 616 | int fdcount, err; |
@@ -482,14 +628,6 @@ asmlinkage long sys_poll(struct pollfd __user * ufds, unsigned int nfds, long ti | |||
482 | if (nfds > max_fdset && nfds > OPEN_MAX) | 628 | if (nfds > max_fdset && nfds > OPEN_MAX) |
483 | return -EINVAL; | 629 | return -EINVAL; |
484 | 630 | ||
485 | if (timeout) { | ||
486 | /* Careful about overflow in the intermediate values */ | ||
487 | if ((unsigned long) timeout < MAX_SCHEDULE_TIMEOUT / HZ) | ||
488 | timeout = (unsigned long)(timeout*HZ+999)/1000+1; | ||
489 | else /* Negative or overflow */ | ||
490 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
491 | } | ||
492 | |||
493 | poll_initwait(&table); | 631 | poll_initwait(&table); |
494 | 632 | ||
495 | head = NULL; | 633 | head = NULL; |
@@ -519,6 +657,7 @@ asmlinkage long sys_poll(struct pollfd __user * ufds, unsigned int nfds, long ti | |||
519 | } | 657 | } |
520 | i -= pp->len; | 658 | i -= pp->len; |
521 | } | 659 | } |
660 | |||
522 | fdcount = do_poll(nfds, head, &table, timeout); | 661 | fdcount = do_poll(nfds, head, &table, timeout); |
523 | 662 | ||
524 | /* OK, now copy the revents fields back to user space. */ | 663 | /* OK, now copy the revents fields back to user space. */ |
@@ -547,3 +686,98 @@ out_fds: | |||
547 | poll_freewait(&table); | 686 | poll_freewait(&table); |
548 | return err; | 687 | return err; |
549 | } | 688 | } |
689 | |||
690 | asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds, | ||
691 | long timeout_msecs) | ||
692 | { | ||
693 | s64 timeout_jiffies = 0; | ||
694 | |||
695 | if (timeout_msecs) { | ||
696 | #if HZ > 1000 | ||
697 | /* We can only overflow if HZ > 1000 */ | ||
698 | if (timeout_msecs / 1000 > (s64)0x7fffffffffffffffULL / (s64)HZ) | ||
699 | timeout_jiffies = -1; | ||
700 | else | ||
701 | #endif | ||
702 | timeout_jiffies = msecs_to_jiffies(timeout_msecs); | ||
703 | } | ||
704 | |||
705 | return do_sys_poll(ufds, nfds, &timeout_jiffies); | ||
706 | } | ||
707 | |||
708 | #ifdef TIF_RESTORE_SIGMASK | ||
709 | asmlinkage long sys_ppoll(struct pollfd __user *ufds, unsigned int nfds, | ||
710 | struct timespec __user *tsp, const sigset_t __user *sigmask, | ||
711 | size_t sigsetsize) | ||
712 | { | ||
713 | sigset_t ksigmask, sigsaved; | ||
714 | struct timespec ts; | ||
715 | s64 timeout = -1; | ||
716 | int ret; | ||
717 | |||
718 | if (tsp) { | ||
719 | if (copy_from_user(&ts, tsp, sizeof(ts))) | ||
720 | return -EFAULT; | ||
721 | |||
722 | /* Cast to u64 to make GCC stop complaining */ | ||
723 | if ((u64)ts.tv_sec >= (u64)MAX_INT64_SECONDS) | ||
724 | timeout = -1; /* infinite */ | ||
725 | else { | ||
726 | timeout = ROUND_UP(ts.tv_nsec, NSEC_PER_SEC/HZ); | ||
727 | timeout += ts.tv_sec * HZ; | ||
728 | } | ||
729 | } | ||
730 | |||
731 | if (sigmask) { | ||
732 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
733 | if (sigsetsize != sizeof(sigset_t)) | ||
734 | return -EINVAL; | ||
735 | if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask))) | ||
736 | return -EFAULT; | ||
737 | |||
738 | sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); | ||
739 | sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); | ||
740 | } | ||
741 | |||
742 | ret = do_sys_poll(ufds, nfds, &timeout); | ||
743 | |||
744 | /* We can restart this syscall, usually */ | ||
745 | if (ret == -EINTR) { | ||
746 | /* | ||
747 | * Don't restore the signal mask yet. Let do_signal() deliver | ||
748 | * the signal on the way back to userspace, before the signal | ||
749 | * mask is restored. | ||
750 | */ | ||
751 | if (sigmask) { | ||
752 | memcpy(¤t->saved_sigmask, &sigsaved, | ||
753 | sizeof(sigsaved)); | ||
754 | set_thread_flag(TIF_RESTORE_SIGMASK); | ||
755 | } | ||
756 | ret = -ERESTARTNOHAND; | ||
757 | } else if (sigmask) | ||
758 | sigprocmask(SIG_SETMASK, &sigsaved, NULL); | ||
759 | |||
760 | if (tsp && timeout >= 0) { | ||
761 | if (current->personality & STICKY_TIMEOUTS) | ||
762 | goto sticky; | ||
763 | /* Yes, we know it's actually an s64, but it's also positive. */ | ||
764 | ts.tv_nsec = jiffies_to_usecs(do_div((*(u64*)&timeout), HZ)) * 1000; | ||
765 | ts.tv_sec = timeout; | ||
766 | if (copy_to_user(tsp, &ts, sizeof(ts))) { | ||
767 | sticky: | ||
768 | /* | ||
769 | * If an application puts its timeval in read-only | ||
770 | * memory, we don't want the Linux-specific update to | ||
771 | * the timeval to cause a fault after the select has | ||
772 | * completed successfully. However, because we're not | ||
773 | * updating the timeval, we can't restart the system | ||
774 | * call. | ||
775 | */ | ||
776 | if (ret == -ERESTARTNOHAND && timeout >= 0) | ||
777 | ret = -EINTR; | ||
778 | } | ||
779 | } | ||
780 | |||
781 | return ret; | ||
782 | } | ||
783 | #endif /* TIF_RESTORE_SIGMASK */ | ||
@@ -63,12 +63,12 @@ int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
63 | 63 | ||
64 | EXPORT_SYMBOL(vfs_getattr); | 64 | EXPORT_SYMBOL(vfs_getattr); |
65 | 65 | ||
66 | int vfs_stat(char __user *name, struct kstat *stat) | 66 | int vfs_stat_fd(int dfd, char __user *name, struct kstat *stat) |
67 | { | 67 | { |
68 | struct nameidata nd; | 68 | struct nameidata nd; |
69 | int error; | 69 | int error; |
70 | 70 | ||
71 | error = user_path_walk(name, &nd); | 71 | error = __user_walk_fd(dfd, name, LOOKUP_FOLLOW, &nd); |
72 | if (!error) { | 72 | if (!error) { |
73 | error = vfs_getattr(nd.mnt, nd.dentry, stat); | 73 | error = vfs_getattr(nd.mnt, nd.dentry, stat); |
74 | path_release(&nd); | 74 | path_release(&nd); |
@@ -76,14 +76,19 @@ int vfs_stat(char __user *name, struct kstat *stat) | |||
76 | return error; | 76 | return error; |
77 | } | 77 | } |
78 | 78 | ||
79 | int vfs_stat(char __user *name, struct kstat *stat) | ||
80 | { | ||
81 | return vfs_stat_fd(AT_FDCWD, name, stat); | ||
82 | } | ||
83 | |||
79 | EXPORT_SYMBOL(vfs_stat); | 84 | EXPORT_SYMBOL(vfs_stat); |
80 | 85 | ||
81 | int vfs_lstat(char __user *name, struct kstat *stat) | 86 | int vfs_lstat_fd(int dfd, char __user *name, struct kstat *stat) |
82 | { | 87 | { |
83 | struct nameidata nd; | 88 | struct nameidata nd; |
84 | int error; | 89 | int error; |
85 | 90 | ||
86 | error = user_path_walk_link(name, &nd); | 91 | error = __user_walk_fd(dfd, name, 0, &nd); |
87 | if (!error) { | 92 | if (!error) { |
88 | error = vfs_getattr(nd.mnt, nd.dentry, stat); | 93 | error = vfs_getattr(nd.mnt, nd.dentry, stat); |
89 | path_release(&nd); | 94 | path_release(&nd); |
@@ -91,6 +96,11 @@ int vfs_lstat(char __user *name, struct kstat *stat) | |||
91 | return error; | 96 | return error; |
92 | } | 97 | } |
93 | 98 | ||
99 | int vfs_lstat(char __user *name, struct kstat *stat) | ||
100 | { | ||
101 | return vfs_lstat_fd(AT_FDCWD, name, stat); | ||
102 | } | ||
103 | |||
94 | EXPORT_SYMBOL(vfs_lstat); | 104 | EXPORT_SYMBOL(vfs_lstat); |
95 | 105 | ||
96 | int vfs_fstat(unsigned int fd, struct kstat *stat) | 106 | int vfs_fstat(unsigned int fd, struct kstat *stat) |
@@ -151,7 +161,7 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta | |||
151 | asmlinkage long sys_stat(char __user * filename, struct __old_kernel_stat __user * statbuf) | 161 | asmlinkage long sys_stat(char __user * filename, struct __old_kernel_stat __user * statbuf) |
152 | { | 162 | { |
153 | struct kstat stat; | 163 | struct kstat stat; |
154 | int error = vfs_stat(filename, &stat); | 164 | int error = vfs_stat_fd(AT_FDCWD, filename, &stat); |
155 | 165 | ||
156 | if (!error) | 166 | if (!error) |
157 | error = cp_old_stat(&stat, statbuf); | 167 | error = cp_old_stat(&stat, statbuf); |
@@ -161,7 +171,7 @@ asmlinkage long sys_stat(char __user * filename, struct __old_kernel_stat __user | |||
161 | asmlinkage long sys_lstat(char __user * filename, struct __old_kernel_stat __user * statbuf) | 171 | asmlinkage long sys_lstat(char __user * filename, struct __old_kernel_stat __user * statbuf) |
162 | { | 172 | { |
163 | struct kstat stat; | 173 | struct kstat stat; |
164 | int error = vfs_lstat(filename, &stat); | 174 | int error = vfs_lstat_fd(AT_FDCWD, filename, &stat); |
165 | 175 | ||
166 | if (!error) | 176 | if (!error) |
167 | error = cp_old_stat(&stat, statbuf); | 177 | error = cp_old_stat(&stat, statbuf); |
@@ -229,27 +239,50 @@ static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf) | |||
229 | return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; | 239 | return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; |
230 | } | 240 | } |
231 | 241 | ||
232 | asmlinkage long sys_newstat(char __user * filename, struct stat __user * statbuf) | 242 | asmlinkage long sys_newstat(char __user *filename, struct stat __user *statbuf) |
233 | { | 243 | { |
234 | struct kstat stat; | 244 | struct kstat stat; |
235 | int error = vfs_stat(filename, &stat); | 245 | int error = vfs_stat_fd(AT_FDCWD, filename, &stat); |
236 | 246 | ||
237 | if (!error) | 247 | if (!error) |
238 | error = cp_new_stat(&stat, statbuf); | 248 | error = cp_new_stat(&stat, statbuf); |
239 | 249 | ||
240 | return error; | 250 | return error; |
241 | } | 251 | } |
242 | asmlinkage long sys_newlstat(char __user * filename, struct stat __user * statbuf) | 252 | |
253 | asmlinkage long sys_newlstat(char __user *filename, struct stat __user *statbuf) | ||
243 | { | 254 | { |
244 | struct kstat stat; | 255 | struct kstat stat; |
245 | int error = vfs_lstat(filename, &stat); | 256 | int error = vfs_lstat_fd(AT_FDCWD, filename, &stat); |
246 | 257 | ||
247 | if (!error) | 258 | if (!error) |
248 | error = cp_new_stat(&stat, statbuf); | 259 | error = cp_new_stat(&stat, statbuf); |
249 | 260 | ||
250 | return error; | 261 | return error; |
251 | } | 262 | } |
252 | asmlinkage long sys_newfstat(unsigned int fd, struct stat __user * statbuf) | 263 | |
264 | asmlinkage long sys_newfstatat(int dfd, char __user *filename, | ||
265 | struct stat __user *statbuf, int flag) | ||
266 | { | ||
267 | struct kstat stat; | ||
268 | int error = -EINVAL; | ||
269 | |||
270 | if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0) | ||
271 | goto out; | ||
272 | |||
273 | if (flag & AT_SYMLINK_NOFOLLOW) | ||
274 | error = vfs_lstat_fd(dfd, filename, &stat); | ||
275 | else | ||
276 | error = vfs_stat_fd(dfd, filename, &stat); | ||
277 | |||
278 | if (!error) | ||
279 | error = cp_new_stat(&stat, statbuf); | ||
280 | |||
281 | out: | ||
282 | return error; | ||
283 | } | ||
284 | |||
285 | asmlinkage long sys_newfstat(unsigned int fd, struct stat __user *statbuf) | ||
253 | { | 286 | { |
254 | struct kstat stat; | 287 | struct kstat stat; |
255 | int error = vfs_fstat(fd, &stat); | 288 | int error = vfs_fstat(fd, &stat); |
@@ -260,7 +293,8 @@ asmlinkage long sys_newfstat(unsigned int fd, struct stat __user * statbuf) | |||
260 | return error; | 293 | return error; |
261 | } | 294 | } |
262 | 295 | ||
263 | asmlinkage long sys_readlink(const char __user * path, char __user * buf, int bufsiz) | 296 | asmlinkage long sys_readlinkat(int dfd, const char __user *path, |
297 | char __user *buf, int bufsiz) | ||
264 | { | 298 | { |
265 | struct nameidata nd; | 299 | struct nameidata nd; |
266 | int error; | 300 | int error; |
@@ -268,7 +302,7 @@ asmlinkage long sys_readlink(const char __user * path, char __user * buf, int bu | |||
268 | if (bufsiz <= 0) | 302 | if (bufsiz <= 0) |
269 | return -EINVAL; | 303 | return -EINVAL; |
270 | 304 | ||
271 | error = user_path_walk_link(path, &nd); | 305 | error = __user_walk_fd(dfd, path, 0, &nd); |
272 | if (!error) { | 306 | if (!error) { |
273 | struct inode * inode = nd.dentry->d_inode; | 307 | struct inode * inode = nd.dentry->d_inode; |
274 | 308 | ||
@@ -285,6 +319,12 @@ asmlinkage long sys_readlink(const char __user * path, char __user * buf, int bu | |||
285 | return error; | 319 | return error; |
286 | } | 320 | } |
287 | 321 | ||
322 | asmlinkage long sys_readlink(const char __user *path, char __user *buf, | ||
323 | int bufsiz) | ||
324 | { | ||
325 | return sys_readlinkat(AT_FDCWD, path, buf, bufsiz); | ||
326 | } | ||
327 | |||
288 | 328 | ||
289 | /* ---------- LFS-64 ----------- */ | 329 | /* ---------- LFS-64 ----------- */ |
290 | #ifdef __ARCH_WANT_STAT64 | 330 | #ifdef __ARCH_WANT_STAT64 |