diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/Makefile | 2 | ||||
-rw-r--r-- | fs/autofs4/dev-ioctl.c | 5 | ||||
-rw-r--r-- | fs/autofs4/expire.c | 19 | ||||
-rw-r--r-- | fs/block_dev.c | 23 | ||||
-rw-r--r-- | fs/cifs/CHANGES | 6 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 2 | ||||
-rw-r--r-- | fs/cifs/connect.c | 50 | ||||
-rw-r--r-- | fs/cifs/file.c | 2 | ||||
-rw-r--r-- | fs/cifs/inode.c | 4 | ||||
-rw-r--r-- | fs/cifs/transport.c | 48 | ||||
-rw-r--r-- | fs/ext3/super.c | 11 | ||||
-rw-r--r-- | fs/fat/Makefile | 6 | ||||
-rw-r--r-- | fs/fat/cache.c | 25 | ||||
-rw-r--r-- | fs/fat/dir.c | 20 | ||||
-rw-r--r-- | fs/fat/fat.h | 329 | ||||
-rw-r--r-- | fs/fat/fatent.c | 24 | ||||
-rw-r--r-- | fs/fat/file.c | 49 | ||||
-rw-r--r-- | fs/fat/inode.c | 131 | ||||
-rw-r--r-- | fs/fat/misc.c | 155 | ||||
-rw-r--r-- | fs/fat/namei_msdos.c (renamed from fs/msdos/namei.c) | 42 | ||||
-rw-r--r-- | fs/fat/namei_vfat.c (renamed from fs/vfat/namei.c) | 161 | ||||
-rw-r--r-- | fs/jffs2/background.c | 10 | ||||
-rw-r--r-- | fs/jffs2/compr_lzo.c | 15 | ||||
-rw-r--r-- | fs/jffs2/nodemgmt.c | 2 | ||||
-rw-r--r-- | fs/msdos/Makefile | 7 | ||||
-rw-r--r-- | fs/proc/uptime.c | 38 | ||||
-rw-r--r-- | fs/vfat/Makefile | 7 |
29 files changed, 872 insertions, 325 deletions
diff --git a/fs/Makefile b/fs/Makefile index 2168c902d5ca..d9f8afe6f0c4 100644 --- a/fs/Makefile +++ b/fs/Makefile | |||
@@ -81,8 +81,6 @@ obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ | |||
81 | obj-$(CONFIG_CODA_FS) += coda/ | 81 | obj-$(CONFIG_CODA_FS) += coda/ |
82 | obj-$(CONFIG_MINIX_FS) += minix/ | 82 | obj-$(CONFIG_MINIX_FS) += minix/ |
83 | obj-$(CONFIG_FAT_FS) += fat/ | 83 | obj-$(CONFIG_FAT_FS) += fat/ |
84 | obj-$(CONFIG_MSDOS_FS) += msdos/ | ||
85 | obj-$(CONFIG_VFAT_FS) += vfat/ | ||
86 | obj-$(CONFIG_BFS_FS) += bfs/ | 84 | obj-$(CONFIG_BFS_FS) += bfs/ |
87 | obj-$(CONFIG_ISO9660_FS) += isofs/ | 85 | obj-$(CONFIG_ISO9660_FS) += isofs/ |
88 | obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+ | 86 | obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+ |
diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c index 625abf5422e2..33bf8cbfd051 100644 --- a/fs/autofs4/dev-ioctl.c +++ b/fs/autofs4/dev-ioctl.c | |||
@@ -128,9 +128,10 @@ static inline void free_dev_ioctl(struct autofs_dev_ioctl *param) | |||
128 | */ | 128 | */ |
129 | static int validate_dev_ioctl(int cmd, struct autofs_dev_ioctl *param) | 129 | static int validate_dev_ioctl(int cmd, struct autofs_dev_ioctl *param) |
130 | { | 130 | { |
131 | int err = -EINVAL; | 131 | int err; |
132 | 132 | ||
133 | if (check_dev_ioctl_version(cmd, param)) { | 133 | err = check_dev_ioctl_version(cmd, param); |
134 | if (err) { | ||
134 | AUTOFS_WARN("invalid device control module version " | 135 | AUTOFS_WARN("invalid device control module version " |
135 | "supplied for cmd(0x%08x)", cmd); | 136 | "supplied for cmd(0x%08x)", cmd); |
136 | goto out; | 137 | goto out; |
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index cde2f8e8935a..4b6fb3f628c0 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
@@ -56,12 +56,23 @@ static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry) | |||
56 | mntget(mnt); | 56 | mntget(mnt); |
57 | dget(dentry); | 57 | dget(dentry); |
58 | 58 | ||
59 | if (!autofs4_follow_mount(&mnt, &dentry)) | 59 | if (!follow_down(&mnt, &dentry)) |
60 | goto done; | 60 | goto done; |
61 | 61 | ||
62 | /* This is an autofs submount, we can't expire it */ | 62 | if (is_autofs4_dentry(dentry)) { |
63 | if (is_autofs4_dentry(dentry)) | 63 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); |
64 | goto done; | 64 | |
65 | /* This is an autofs submount, we can't expire it */ | ||
66 | if (sbi->type == AUTOFS_TYPE_INDIRECT) | ||
67 | goto done; | ||
68 | |||
69 | /* | ||
70 | * Otherwise it's an offset mount and we need to check | ||
71 | * if we can umount its mount, if there is one. | ||
72 | */ | ||
73 | if (!d_mountpoint(dentry)) | ||
74 | goto done; | ||
75 | } | ||
65 | 76 | ||
66 | /* Update the expiry counter if fs is busy */ | 77 | /* Update the expiry counter if fs is busy */ |
67 | if (!may_umount_tree(mnt)) { | 78 | if (!may_umount_tree(mnt)) { |
diff --git a/fs/block_dev.c b/fs/block_dev.c index 88a776fa0ef6..db831efbdbbd 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -986,7 +986,6 @@ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part); | |||
986 | static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) | 986 | static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) |
987 | { | 987 | { |
988 | struct gendisk *disk; | 988 | struct gendisk *disk; |
989 | struct hd_struct *part = NULL; | ||
990 | int ret; | 989 | int ret; |
991 | int partno; | 990 | int partno; |
992 | int perm = 0; | 991 | int perm = 0; |
@@ -1004,24 +1003,25 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) | |||
1004 | return ret; | 1003 | return ret; |
1005 | } | 1004 | } |
1006 | 1005 | ||
1007 | ret = -ENXIO; | ||
1008 | |||
1009 | lock_kernel(); | 1006 | lock_kernel(); |
1010 | 1007 | ||
1008 | ret = -ENXIO; | ||
1011 | disk = get_gendisk(bdev->bd_dev, &partno); | 1009 | disk = get_gendisk(bdev->bd_dev, &partno); |
1012 | if (!disk) | 1010 | if (!disk) |
1013 | goto out_unlock_kernel; | 1011 | goto out_unlock_kernel; |
1014 | part = disk_get_part(disk, partno); | ||
1015 | if (!part) | ||
1016 | goto out_unlock_kernel; | ||
1017 | 1012 | ||
1018 | mutex_lock_nested(&bdev->bd_mutex, for_part); | 1013 | mutex_lock_nested(&bdev->bd_mutex, for_part); |
1019 | if (!bdev->bd_openers) { | 1014 | if (!bdev->bd_openers) { |
1020 | bdev->bd_disk = disk; | 1015 | bdev->bd_disk = disk; |
1021 | bdev->bd_part = part; | ||
1022 | bdev->bd_contains = bdev; | 1016 | bdev->bd_contains = bdev; |
1023 | if (!partno) { | 1017 | if (!partno) { |
1024 | struct backing_dev_info *bdi; | 1018 | struct backing_dev_info *bdi; |
1019 | |||
1020 | ret = -ENXIO; | ||
1021 | bdev->bd_part = disk_get_part(disk, partno); | ||
1022 | if (!bdev->bd_part) | ||
1023 | goto out_clear; | ||
1024 | |||
1025 | if (disk->fops->open) { | 1025 | if (disk->fops->open) { |
1026 | ret = disk->fops->open(bdev, mode); | 1026 | ret = disk->fops->open(bdev, mode); |
1027 | if (ret) | 1027 | if (ret) |
@@ -1049,18 +1049,17 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) | |||
1049 | bdev->bd_contains = whole; | 1049 | bdev->bd_contains = whole; |
1050 | bdev->bd_inode->i_data.backing_dev_info = | 1050 | bdev->bd_inode->i_data.backing_dev_info = |
1051 | whole->bd_inode->i_data.backing_dev_info; | 1051 | whole->bd_inode->i_data.backing_dev_info; |
1052 | bdev->bd_part = disk_get_part(disk, partno); | ||
1052 | if (!(disk->flags & GENHD_FL_UP) || | 1053 | if (!(disk->flags & GENHD_FL_UP) || |
1053 | !part || !part->nr_sects) { | 1054 | !bdev->bd_part || !bdev->bd_part->nr_sects) { |
1054 | ret = -ENXIO; | 1055 | ret = -ENXIO; |
1055 | goto out_clear; | 1056 | goto out_clear; |
1056 | } | 1057 | } |
1057 | bd_set_size(bdev, (loff_t)part->nr_sects << 9); | 1058 | bd_set_size(bdev, (loff_t)bdev->bd_part->nr_sects << 9); |
1058 | } | 1059 | } |
1059 | } else { | 1060 | } else { |
1060 | disk_put_part(part); | ||
1061 | put_disk(disk); | 1061 | put_disk(disk); |
1062 | module_put(disk->fops->owner); | 1062 | module_put(disk->fops->owner); |
1063 | part = NULL; | ||
1064 | disk = NULL; | 1063 | disk = NULL; |
1065 | if (bdev->bd_contains == bdev) { | 1064 | if (bdev->bd_contains == bdev) { |
1066 | if (bdev->bd_disk->fops->open) { | 1065 | if (bdev->bd_disk->fops->open) { |
@@ -1080,6 +1079,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) | |||
1080 | return 0; | 1079 | return 0; |
1081 | 1080 | ||
1082 | out_clear: | 1081 | out_clear: |
1082 | disk_put_part(bdev->bd_part); | ||
1083 | bdev->bd_disk = NULL; | 1083 | bdev->bd_disk = NULL; |
1084 | bdev->bd_part = NULL; | 1084 | bdev->bd_part = NULL; |
1085 | bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; | 1085 | bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; |
@@ -1091,7 +1091,6 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) | |||
1091 | out_unlock_kernel: | 1091 | out_unlock_kernel: |
1092 | unlock_kernel(); | 1092 | unlock_kernel(); |
1093 | 1093 | ||
1094 | disk_put_part(part); | ||
1095 | if (disk) | 1094 | if (disk) |
1096 | module_put(disk->fops->owner); | 1095 | module_put(disk->fops->owner); |
1097 | put_disk(disk); | 1096 | put_disk(disk); |
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 8f528ea24c48..8855331b2fba 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
@@ -4,7 +4,11 @@ Various fixes to make delete of open files behavior more predictable | |||
4 | (when delete of an open file fails we mark the file as "delete-on-close" | 4 | (when delete of an open file fails we mark the file as "delete-on-close" |
5 | in a way that more servers accept, but only if we can first rename the | 5 | in a way that more servers accept, but only if we can first rename the |
6 | file to a temporary name). Add experimental support for more safely | 6 | file to a temporary name). Add experimental support for more safely |
7 | handling fcntl(F_SETLEASE). | 7 | handling fcntl(F_SETLEASE). Convert cifs to using blocking tcp |
8 | sends, and also let tcp autotune the socket send and receive buffers. | ||
9 | This reduces the number of EAGAIN errors returned by TCP/IP in | ||
10 | high stress workloads (and the number of retries on socket writes | ||
11 | when sending large SMBWriteX requests). | ||
8 | 12 | ||
9 | Version 1.54 | 13 | Version 1.54 |
10 | ------------ | 14 | ------------ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index c791e5b5a914..1cb1189f24e0 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -141,6 +141,8 @@ struct TCP_Server_Info { | |||
141 | char versionMajor; | 141 | char versionMajor; |
142 | char versionMinor; | 142 | char versionMinor; |
143 | bool svlocal:1; /* local server or remote */ | 143 | bool svlocal:1; /* local server or remote */ |
144 | bool noblocksnd; /* use blocking sendmsg */ | ||
145 | bool noautotune; /* do not autotune send buf sizes */ | ||
144 | atomic_t socketUseCount; /* number of open cifs sessions on socket */ | 146 | atomic_t socketUseCount; /* number of open cifs sessions on socket */ |
145 | atomic_t inFlight; /* number of requests on the wire to server */ | 147 | atomic_t inFlight; /* number of requests on the wire to server */ |
146 | #ifdef CONFIG_CIFS_STATS2 | 148 | #ifdef CONFIG_CIFS_STATS2 |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 0cff7fe986e8..6f21ecb85ce5 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -36,7 +36,7 @@ extern void cifs_buf_release(void *); | |||
36 | extern struct smb_hdr *cifs_small_buf_get(void); | 36 | extern struct smb_hdr *cifs_small_buf_get(void); |
37 | extern void cifs_small_buf_release(void *); | 37 | extern void cifs_small_buf_release(void *); |
38 | extern int smb_send(struct socket *, struct smb_hdr *, | 38 | extern int smb_send(struct socket *, struct smb_hdr *, |
39 | unsigned int /* length */ , struct sockaddr *); | 39 | unsigned int /* length */ , struct sockaddr *, bool); |
40 | extern unsigned int _GetXid(void); | 40 | extern unsigned int _GetXid(void); |
41 | extern void _FreeXid(unsigned int); | 41 | extern void _FreeXid(unsigned int); |
42 | #define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current->fsuid)); | 42 | #define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current->fsuid)); |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 843a85fb8b9a..d5eac48fc415 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -1536,7 +1536,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
1536 | __u32 bytes_sent; | 1536 | __u32 bytes_sent; |
1537 | __u16 byte_count; | 1537 | __u16 byte_count; |
1538 | 1538 | ||
1539 | /* cFYI(1,("write at %lld %d bytes",offset,count));*/ | 1539 | /* cFYI(1, ("write at %lld %d bytes", offset, count));*/ |
1540 | if (tcon->ses == NULL) | 1540 | if (tcon->ses == NULL) |
1541 | return -ECONNABORTED; | 1541 | return -ECONNABORTED; |
1542 | 1542 | ||
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 71b7661e2260..e9f9248cb3fe 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -92,6 +92,8 @@ struct smb_vol { | |||
92 | bool seal:1; /* request transport encryption on share */ | 92 | bool seal:1; /* request transport encryption on share */ |
93 | bool nodfs:1; /* Do not request DFS, even if available */ | 93 | bool nodfs:1; /* Do not request DFS, even if available */ |
94 | bool local_lease:1; /* check leases only on local system, not remote */ | 94 | bool local_lease:1; /* check leases only on local system, not remote */ |
95 | bool noblocksnd:1; | ||
96 | bool noautotune:1; | ||
95 | unsigned int rsize; | 97 | unsigned int rsize; |
96 | unsigned int wsize; | 98 | unsigned int wsize; |
97 | unsigned int sockopt; | 99 | unsigned int sockopt; |
@@ -102,9 +104,11 @@ struct smb_vol { | |||
102 | static int ipv4_connect(struct sockaddr_in *psin_server, | 104 | static int ipv4_connect(struct sockaddr_in *psin_server, |
103 | struct socket **csocket, | 105 | struct socket **csocket, |
104 | char *netb_name, | 106 | char *netb_name, |
105 | char *server_netb_name); | 107 | char *server_netb_name, |
108 | bool noblocksnd, | ||
109 | bool nosndbuf); /* ipv6 never set sndbuf size */ | ||
106 | static int ipv6_connect(struct sockaddr_in6 *psin_server, | 110 | static int ipv6_connect(struct sockaddr_in6 *psin_server, |
107 | struct socket **csocket); | 111 | struct socket **csocket, bool noblocksnd); |
108 | 112 | ||
109 | 113 | ||
110 | /* | 114 | /* |
@@ -191,12 +195,13 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
191 | try_to_freeze(); | 195 | try_to_freeze(); |
192 | if (server->protocolType == IPV6) { | 196 | if (server->protocolType == IPV6) { |
193 | rc = ipv6_connect(&server->addr.sockAddr6, | 197 | rc = ipv6_connect(&server->addr.sockAddr6, |
194 | &server->ssocket); | 198 | &server->ssocket, server->noautotune); |
195 | } else { | 199 | } else { |
196 | rc = ipv4_connect(&server->addr.sockAddr, | 200 | rc = ipv4_connect(&server->addr.sockAddr, |
197 | &server->ssocket, | 201 | &server->ssocket, |
198 | server->workstation_RFC1001_name, | 202 | server->workstation_RFC1001_name, |
199 | server->server_RFC1001_name); | 203 | server->server_RFC1001_name, |
204 | server->noblocksnd, server->noautotune); | ||
200 | } | 205 | } |
201 | if (rc) { | 206 | if (rc) { |
202 | cFYI(1, ("reconnect error %d", rc)); | 207 | cFYI(1, ("reconnect error %d", rc)); |
@@ -1192,6 +1197,10 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1192 | /* ignore */ | 1197 | /* ignore */ |
1193 | } else if (strnicmp(data, "rw", 2) == 0) { | 1198 | } else if (strnicmp(data, "rw", 2) == 0) { |
1194 | vol->rw = true; | 1199 | vol->rw = true; |
1200 | } else if (strnicmp(data, "noblocksend", 11) == 0) { | ||
1201 | vol->noblocksnd = 1; | ||
1202 | } else if (strnicmp(data, "noautotune", 10) == 0) { | ||
1203 | vol->noautotune = 1; | ||
1195 | } else if ((strnicmp(data, "suid", 4) == 0) || | 1204 | } else if ((strnicmp(data, "suid", 4) == 0) || |
1196 | (strnicmp(data, "nosuid", 6) == 0) || | 1205 | (strnicmp(data, "nosuid", 6) == 0) || |
1197 | (strnicmp(data, "exec", 4) == 0) || | 1206 | (strnicmp(data, "exec", 4) == 0) || |
@@ -1518,7 +1527,8 @@ static void rfc1002mangle(char *target, char *source, unsigned int length) | |||
1518 | 1527 | ||
1519 | static int | 1528 | static int |
1520 | ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, | 1529 | ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, |
1521 | char *netbios_name, char *target_name) | 1530 | char *netbios_name, char *target_name, |
1531 | bool noblocksnd, bool noautotune) | ||
1522 | { | 1532 | { |
1523 | int rc = 0; | 1533 | int rc = 0; |
1524 | int connected = 0; | 1534 | int connected = 0; |
@@ -1590,11 +1600,16 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, | |||
1590 | (*csocket)->sk->sk_sndbuf, | 1600 | (*csocket)->sk->sk_sndbuf, |
1591 | (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo)); | 1601 | (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo)); |
1592 | (*csocket)->sk->sk_rcvtimeo = 7 * HZ; | 1602 | (*csocket)->sk->sk_rcvtimeo = 7 * HZ; |
1603 | if (!noblocksnd) | ||
1604 | (*csocket)->sk->sk_sndtimeo = 3 * HZ; | ||
1605 | |||
1593 | /* make the bufsizes depend on wsize/rsize and max requests */ | 1606 | /* make the bufsizes depend on wsize/rsize and max requests */ |
1594 | if ((*csocket)->sk->sk_sndbuf < (200 * 1024)) | 1607 | if (noautotune) { |
1595 | (*csocket)->sk->sk_sndbuf = 200 * 1024; | 1608 | if ((*csocket)->sk->sk_sndbuf < (200 * 1024)) |
1596 | if ((*csocket)->sk->sk_rcvbuf < (140 * 1024)) | 1609 | (*csocket)->sk->sk_sndbuf = 200 * 1024; |
1597 | (*csocket)->sk->sk_rcvbuf = 140 * 1024; | 1610 | if ((*csocket)->sk->sk_rcvbuf < (140 * 1024)) |
1611 | (*csocket)->sk->sk_rcvbuf = 140 * 1024; | ||
1612 | } | ||
1598 | 1613 | ||
1599 | /* send RFC1001 sessinit */ | 1614 | /* send RFC1001 sessinit */ |
1600 | if (psin_server->sin_port == htons(RFC1001_PORT)) { | 1615 | if (psin_server->sin_port == htons(RFC1001_PORT)) { |
@@ -1631,7 +1646,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, | |||
1631 | /* sizeof RFC1002_SESSION_REQUEST with no scope */ | 1646 | /* sizeof RFC1002_SESSION_REQUEST with no scope */ |
1632 | smb_buf->smb_buf_length = 0x81000044; | 1647 | smb_buf->smb_buf_length = 0x81000044; |
1633 | rc = smb_send(*csocket, smb_buf, 0x44, | 1648 | rc = smb_send(*csocket, smb_buf, 0x44, |
1634 | (struct sockaddr *)psin_server); | 1649 | (struct sockaddr *)psin_server, noblocksnd); |
1635 | kfree(ses_init_buf); | 1650 | kfree(ses_init_buf); |
1636 | msleep(1); /* RFC1001 layer in at least one server | 1651 | msleep(1); /* RFC1001 layer in at least one server |
1637 | requires very short break before negprot | 1652 | requires very short break before negprot |
@@ -1651,7 +1666,8 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, | |||
1651 | } | 1666 | } |
1652 | 1667 | ||
1653 | static int | 1668 | static int |
1654 | ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) | 1669 | ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket, |
1670 | bool noblocksnd) | ||
1655 | { | 1671 | { |
1656 | int rc = 0; | 1672 | int rc = 0; |
1657 | int connected = 0; | 1673 | int connected = 0; |
@@ -1720,6 +1736,9 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) | |||
1720 | the default. sock_setsockopt not used because it expects | 1736 | the default. sock_setsockopt not used because it expects |
1721 | user space buffer */ | 1737 | user space buffer */ |
1722 | (*csocket)->sk->sk_rcvtimeo = 7 * HZ; | 1738 | (*csocket)->sk->sk_rcvtimeo = 7 * HZ; |
1739 | if (!noblocksnd) | ||
1740 | (*csocket)->sk->sk_sndtimeo = 3 * HZ; | ||
1741 | |||
1723 | 1742 | ||
1724 | return rc; | 1743 | return rc; |
1725 | } | 1744 | } |
@@ -1983,11 +2002,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
1983 | cFYI(1, ("attempting ipv6 connect")); | 2002 | cFYI(1, ("attempting ipv6 connect")); |
1984 | /* BB should we allow ipv6 on port 139? */ | 2003 | /* BB should we allow ipv6 on port 139? */ |
1985 | /* other OS never observed in Wild doing 139 with v6 */ | 2004 | /* other OS never observed in Wild doing 139 with v6 */ |
1986 | rc = ipv6_connect(&sin_server6, &csocket); | 2005 | rc = ipv6_connect(&sin_server6, &csocket, |
2006 | volume_info.noblocksnd); | ||
1987 | } else | 2007 | } else |
1988 | rc = ipv4_connect(&sin_server, &csocket, | 2008 | rc = ipv4_connect(&sin_server, &csocket, |
1989 | volume_info.source_rfc1001_name, | 2009 | volume_info.source_rfc1001_name, |
1990 | volume_info.target_rfc1001_name); | 2010 | volume_info.target_rfc1001_name, |
2011 | volume_info.noblocksnd, | ||
2012 | volume_info.noautotune); | ||
1991 | if (rc < 0) { | 2013 | if (rc < 0) { |
1992 | cERROR(1, ("Error connecting to IPv4 socket. " | 2014 | cERROR(1, ("Error connecting to IPv4 socket. " |
1993 | "Aborting operation")); | 2015 | "Aborting operation")); |
@@ -2002,6 +2024,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2002 | sock_release(csocket); | 2024 | sock_release(csocket); |
2003 | goto out; | 2025 | goto out; |
2004 | } else { | 2026 | } else { |
2027 | srvTcp->noblocksnd = volume_info.noblocksnd; | ||
2028 | srvTcp->noautotune = volume_info.noautotune; | ||
2005 | memcpy(&srvTcp->addr.sockAddr, &sin_server, | 2029 | memcpy(&srvTcp->addr.sockAddr, &sin_server, |
2006 | sizeof(struct sockaddr_in)); | 2030 | sizeof(struct sockaddr_in)); |
2007 | atomic_set(&srvTcp->inFlight, 0); | 2031 | atomic_set(&srvTcp->inFlight, 0); |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 62d8bd8f14c0..ead1a3bb0256 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -1824,7 +1824,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
1824 | pTcon = cifs_sb->tcon; | 1824 | pTcon = cifs_sb->tcon; |
1825 | 1825 | ||
1826 | pagevec_init(&lru_pvec, 0); | 1826 | pagevec_init(&lru_pvec, 0); |
1827 | cFYI(DBG2, ("rpages: num pages %d", num_pages)); | 1827 | cFYI(DBG2, ("rpages: num pages %d", num_pages)); |
1828 | for (i = 0; i < num_pages; ) { | 1828 | for (i = 0; i < num_pages; ) { |
1829 | unsigned contig_pages; | 1829 | unsigned contig_pages; |
1830 | struct page *tmp_page; | 1830 | struct page *tmp_page; |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index d54fa8aeaea9..ff8c68de4a92 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -1361,9 +1361,11 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry, | |||
1361 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1361 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
1362 | 1362 | ||
1363 | if (tmprc == 0 && (info_buf_source->UniqueId == | 1363 | if (tmprc == 0 && (info_buf_source->UniqueId == |
1364 | info_buf_target->UniqueId)) | 1364 | info_buf_target->UniqueId)) { |
1365 | /* same file, POSIX says that this is a noop */ | 1365 | /* same file, POSIX says that this is a noop */ |
1366 | rc = 0; | ||
1366 | goto cifs_rename_exit; | 1367 | goto cifs_rename_exit; |
1368 | } | ||
1367 | } /* else ... BB we could add the same check for Windows by | 1369 | } /* else ... BB we could add the same check for Windows by |
1368 | checking the UniqueId via FILE_INTERNAL_INFO */ | 1370 | checking the UniqueId via FILE_INTERNAL_INFO */ |
1369 | 1371 | ||
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index bf0e6d8e382a..ff8243a8fe3e 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -161,7 +161,7 @@ void DeleteTconOplockQEntries(struct cifsTconInfo *tcon) | |||
161 | 161 | ||
162 | int | 162 | int |
163 | smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, | 163 | smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, |
164 | unsigned int smb_buf_length, struct sockaddr *sin) | 164 | unsigned int smb_buf_length, struct sockaddr *sin, bool noblocksnd) |
165 | { | 165 | { |
166 | int rc = 0; | 166 | int rc = 0; |
167 | int i = 0; | 167 | int i = 0; |
@@ -178,7 +178,10 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
178 | smb_msg.msg_namelen = sizeof(struct sockaddr); | 178 | smb_msg.msg_namelen = sizeof(struct sockaddr); |
179 | smb_msg.msg_control = NULL; | 179 | smb_msg.msg_control = NULL; |
180 | smb_msg.msg_controllen = 0; | 180 | smb_msg.msg_controllen = 0; |
181 | smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/ | 181 | if (noblocksnd) |
182 | smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; | ||
183 | else | ||
184 | smb_msg.msg_flags = MSG_NOSIGNAL; | ||
182 | 185 | ||
183 | /* smb header is converted in header_assemble. bcc and rest of SMB word | 186 | /* smb header is converted in header_assemble. bcc and rest of SMB word |
184 | area, and byte area if necessary, is converted to littleendian in | 187 | area, and byte area if necessary, is converted to littleendian in |
@@ -229,8 +232,8 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
229 | } | 232 | } |
230 | 233 | ||
231 | static int | 234 | static int |
232 | smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, | 235 | smb_send2(struct TCP_Server_Info *server, struct kvec *iov, int n_vec, |
233 | struct sockaddr *sin) | 236 | struct sockaddr *sin, bool noblocksnd) |
234 | { | 237 | { |
235 | int rc = 0; | 238 | int rc = 0; |
236 | int i = 0; | 239 | int i = 0; |
@@ -240,6 +243,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, | |||
240 | unsigned int total_len; | 243 | unsigned int total_len; |
241 | int first_vec = 0; | 244 | int first_vec = 0; |
242 | unsigned int smb_buf_length = smb_buffer->smb_buf_length; | 245 | unsigned int smb_buf_length = smb_buffer->smb_buf_length; |
246 | struct socket *ssocket = server->ssocket; | ||
243 | 247 | ||
244 | if (ssocket == NULL) | 248 | if (ssocket == NULL) |
245 | return -ENOTSOCK; /* BB eventually add reconnect code here */ | 249 | return -ENOTSOCK; /* BB eventually add reconnect code here */ |
@@ -248,7 +252,10 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, | |||
248 | smb_msg.msg_namelen = sizeof(struct sockaddr); | 252 | smb_msg.msg_namelen = sizeof(struct sockaddr); |
249 | smb_msg.msg_control = NULL; | 253 | smb_msg.msg_control = NULL; |
250 | smb_msg.msg_controllen = 0; | 254 | smb_msg.msg_controllen = 0; |
251 | smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/ | 255 | if (noblocksnd) |
256 | smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; | ||
257 | else | ||
258 | smb_msg.msg_flags = MSG_NOSIGNAL; | ||
252 | 259 | ||
253 | /* smb header is converted in header_assemble. bcc and rest of SMB word | 260 | /* smb header is converted in header_assemble. bcc and rest of SMB word |
254 | area, and byte area if necessary, is converted to littleendian in | 261 | area, and byte area if necessary, is converted to littleendian in |
@@ -283,8 +290,11 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, | |||
283 | if (rc < 0) | 290 | if (rc < 0) |
284 | break; | 291 | break; |
285 | 292 | ||
286 | if (rc >= total_len) { | 293 | if (rc == total_len) { |
287 | WARN_ON(rc > total_len); | 294 | total_len = 0; |
295 | break; | ||
296 | } else if (rc > total_len) { | ||
297 | cERROR(1, ("sent %d requested %d", rc, total_len)); | ||
288 | break; | 298 | break; |
289 | } | 299 | } |
290 | if (rc == 0) { | 300 | if (rc == 0) { |
@@ -312,6 +322,16 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, | |||
312 | i = 0; /* in case we get ENOSPC on the next send */ | 322 | i = 0; /* in case we get ENOSPC on the next send */ |
313 | } | 323 | } |
314 | 324 | ||
325 | if ((total_len > 0) && (total_len != smb_buf_length + 4)) { | ||
326 | cFYI(1, ("partial send (%d remaining), terminating session", | ||
327 | total_len)); | ||
328 | /* If we have only sent part of an SMB then the next SMB | ||
329 | could be taken as the remainder of this one. We need | ||
330 | to kill the socket so the server throws away the partial | ||
331 | SMB */ | ||
332 | server->tcpStatus = CifsNeedReconnect; | ||
333 | } | ||
334 | |||
315 | if (rc < 0) { | 335 | if (rc < 0) { |
316 | cERROR(1, ("Error %d sending data on socket to server", rc)); | 336 | cERROR(1, ("Error %d sending data on socket to server", rc)); |
317 | } else | 337 | } else |
@@ -518,8 +538,9 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
518 | #ifdef CONFIG_CIFS_STATS2 | 538 | #ifdef CONFIG_CIFS_STATS2 |
519 | atomic_inc(&ses->server->inSend); | 539 | atomic_inc(&ses->server->inSend); |
520 | #endif | 540 | #endif |
521 | rc = smb_send2(ses->server->ssocket, iov, n_vec, | 541 | rc = smb_send2(ses->server, iov, n_vec, |
522 | (struct sockaddr *) &(ses->server->addr.sockAddr)); | 542 | (struct sockaddr *) &(ses->server->addr.sockAddr), |
543 | ses->server->noblocksnd); | ||
523 | #ifdef CONFIG_CIFS_STATS2 | 544 | #ifdef CONFIG_CIFS_STATS2 |
524 | atomic_dec(&ses->server->inSend); | 545 | atomic_dec(&ses->server->inSend); |
525 | midQ->when_sent = jiffies; | 546 | midQ->when_sent = jiffies; |
@@ -711,7 +732,8 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
711 | atomic_inc(&ses->server->inSend); | 732 | atomic_inc(&ses->server->inSend); |
712 | #endif | 733 | #endif |
713 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, | 734 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, |
714 | (struct sockaddr *) &(ses->server->addr.sockAddr)); | 735 | (struct sockaddr *) &(ses->server->addr.sockAddr), |
736 | ses->server->noblocksnd); | ||
715 | #ifdef CONFIG_CIFS_STATS2 | 737 | #ifdef CONFIG_CIFS_STATS2 |
716 | atomic_dec(&ses->server->inSend); | 738 | atomic_dec(&ses->server->inSend); |
717 | midQ->when_sent = jiffies; | 739 | midQ->when_sent = jiffies; |
@@ -851,7 +873,8 @@ send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf, | |||
851 | return rc; | 873 | return rc; |
852 | } | 874 | } |
853 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, | 875 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, |
854 | (struct sockaddr *) &(ses->server->addr.sockAddr)); | 876 | (struct sockaddr *) &(ses->server->addr.sockAddr), |
877 | ses->server->noblocksnd); | ||
855 | up(&ses->server->tcpSem); | 878 | up(&ses->server->tcpSem); |
856 | return rc; | 879 | return rc; |
857 | } | 880 | } |
@@ -941,7 +964,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
941 | atomic_inc(&ses->server->inSend); | 964 | atomic_inc(&ses->server->inSend); |
942 | #endif | 965 | #endif |
943 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, | 966 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, |
944 | (struct sockaddr *) &(ses->server->addr.sockAddr)); | 967 | (struct sockaddr *) &(ses->server->addr.sockAddr), |
968 | ses->server->noblocksnd); | ||
945 | #ifdef CONFIG_CIFS_STATS2 | 969 | #ifdef CONFIG_CIFS_STATS2 |
946 | atomic_dec(&ses->server->inSend); | 970 | atomic_dec(&ses->server->inSend); |
947 | midQ->when_sent = jiffies; | 971 | midQ->when_sent = jiffies; |
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index e5717a4fae67..5dec6d1356c4 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c | |||
@@ -2390,13 +2390,12 @@ static void ext3_write_super (struct super_block * sb) | |||
2390 | 2390 | ||
2391 | static int ext3_sync_fs(struct super_block *sb, int wait) | 2391 | static int ext3_sync_fs(struct super_block *sb, int wait) |
2392 | { | 2392 | { |
2393 | tid_t target; | ||
2394 | |||
2395 | sb->s_dirt = 0; | 2393 | sb->s_dirt = 0; |
2396 | if (journal_start_commit(EXT3_SB(sb)->s_journal, &target)) { | 2394 | if (wait) |
2397 | if (wait) | 2395 | ext3_force_commit(sb); |
2398 | log_wait_commit(EXT3_SB(sb)->s_journal, target); | 2396 | else |
2399 | } | 2397 | journal_start_commit(EXT3_SB(sb)->s_journal, NULL); |
2398 | |||
2400 | return 0; | 2399 | return 0; |
2401 | } | 2400 | } |
2402 | 2401 | ||
diff --git a/fs/fat/Makefile b/fs/fat/Makefile index bfb5f06cf2c8..e06190322c1c 100644 --- a/fs/fat/Makefile +++ b/fs/fat/Makefile | |||
@@ -3,5 +3,9 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_FAT_FS) += fat.o | 5 | obj-$(CONFIG_FAT_FS) += fat.o |
6 | obj-$(CONFIG_VFAT_FS) += vfat.o | ||
7 | obj-$(CONFIG_MSDOS_FS) += msdos.o | ||
6 | 8 | ||
7 | fat-objs := cache.o dir.o fatent.o file.o inode.o misc.o | 9 | fat-y := cache.o dir.o fatent.o file.o inode.o misc.o |
10 | vfat-y := namei_vfat.o | ||
11 | msdos-y := namei_msdos.o | ||
diff --git a/fs/fat/cache.c b/fs/fat/cache.c index 3222f51c41cf..b42602298087 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c | |||
@@ -9,8 +9,8 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/fs.h> | 11 | #include <linux/fs.h> |
12 | #include <linux/msdos_fs.h> | ||
13 | #include <linux/buffer_head.h> | 12 | #include <linux/buffer_head.h> |
13 | #include "fat.h" | ||
14 | 14 | ||
15 | /* this must be > 0. */ | 15 | /* this must be > 0. */ |
16 | #define FAT_MAX_CACHE 8 | 16 | #define FAT_MAX_CACHE 8 |
@@ -293,10 +293,12 @@ static int fat_bmap_cluster(struct inode *inode, int cluster) | |||
293 | } | 293 | } |
294 | 294 | ||
295 | int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys, | 295 | int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys, |
296 | unsigned long *mapped_blocks) | 296 | unsigned long *mapped_blocks, int create) |
297 | { | 297 | { |
298 | struct super_block *sb = inode->i_sb; | 298 | struct super_block *sb = inode->i_sb; |
299 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | 299 | struct msdos_sb_info *sbi = MSDOS_SB(sb); |
300 | const unsigned long blocksize = sb->s_blocksize; | ||
301 | const unsigned char blocksize_bits = sb->s_blocksize_bits; | ||
300 | sector_t last_block; | 302 | sector_t last_block; |
301 | int cluster, offset; | 303 | int cluster, offset; |
302 | 304 | ||
@@ -309,10 +311,21 @@ int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys, | |||
309 | } | 311 | } |
310 | return 0; | 312 | return 0; |
311 | } | 313 | } |
312 | last_block = (MSDOS_I(inode)->mmu_private + (sb->s_blocksize - 1)) | 314 | |
313 | >> sb->s_blocksize_bits; | 315 | last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits; |
314 | if (sector >= last_block) | 316 | if (sector >= last_block) { |
315 | return 0; | 317 | if (!create) |
318 | return 0; | ||
319 | |||
320 | /* | ||
321 | * ->mmu_private can access on only allocation path. | ||
322 | * (caller must hold ->i_mutex) | ||
323 | */ | ||
324 | last_block = (MSDOS_I(inode)->mmu_private + (blocksize - 1)) | ||
325 | >> blocksize_bits; | ||
326 | if (sector >= last_block) | ||
327 | return 0; | ||
328 | } | ||
316 | 329 | ||
317 | cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits); | 330 | cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits); |
318 | offset = sector & (sbi->sec_per_clus - 1); | 331 | offset = sector & (sbi->sec_per_clus - 1); |
diff --git a/fs/fat/dir.c b/fs/fat/dir.c index bae1c3292522..67e058357098 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c | |||
@@ -16,11 +16,11 @@ | |||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/time.h> | 18 | #include <linux/time.h> |
19 | #include <linux/msdos_fs.h> | ||
20 | #include <linux/smp_lock.h> | 19 | #include <linux/smp_lock.h> |
21 | #include <linux/buffer_head.h> | 20 | #include <linux/buffer_head.h> |
22 | #include <linux/compat.h> | 21 | #include <linux/compat.h> |
23 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
23 | #include "fat.h" | ||
24 | 24 | ||
25 | static inline loff_t fat_make_i_pos(struct super_block *sb, | 25 | static inline loff_t fat_make_i_pos(struct super_block *sb, |
26 | struct buffer_head *bh, | 26 | struct buffer_head *bh, |
@@ -77,7 +77,7 @@ next: | |||
77 | 77 | ||
78 | *bh = NULL; | 78 | *bh = NULL; |
79 | iblock = *pos >> sb->s_blocksize_bits; | 79 | iblock = *pos >> sb->s_blocksize_bits; |
80 | err = fat_bmap(dir, iblock, &phys, &mapped_blocks); | 80 | err = fat_bmap(dir, iblock, &phys, &mapped_blocks, 0); |
81 | if (err || !phys) | 81 | if (err || !phys) |
82 | return -1; /* beyond EOF or error */ | 82 | return -1; /* beyond EOF or error */ |
83 | 83 | ||
@@ -86,7 +86,7 @@ next: | |||
86 | *bh = sb_bread(sb, phys); | 86 | *bh = sb_bread(sb, phys); |
87 | if (*bh == NULL) { | 87 | if (*bh == NULL) { |
88 | printk(KERN_ERR "FAT: Directory bread(block %llu) failed\n", | 88 | printk(KERN_ERR "FAT: Directory bread(block %llu) failed\n", |
89 | (unsigned long long)phys); | 89 | (llu)phys); |
90 | /* skip this block */ | 90 | /* skip this block */ |
91 | *pos = (iblock + 1) << sb->s_blocksize_bits; | 91 | *pos = (iblock + 1) << sb->s_blocksize_bits; |
92 | goto next; | 92 | goto next; |
@@ -373,9 +373,10 @@ parse_record: | |||
373 | if (de->attr == ATTR_EXT) { | 373 | if (de->attr == ATTR_EXT) { |
374 | int status = fat_parse_long(inode, &cpos, &bh, &de, | 374 | int status = fat_parse_long(inode, &cpos, &bh, &de, |
375 | &unicode, &nr_slots); | 375 | &unicode, &nr_slots); |
376 | if (status < 0) | 376 | if (status < 0) { |
377 | return status; | 377 | err = status; |
378 | else if (status == PARSE_INVALID) | 378 | goto end_of_dir; |
379 | } else if (status == PARSE_INVALID) | ||
379 | continue; | 380 | continue; |
380 | else if (status == PARSE_NOT_LONGNAME) | 381 | else if (status == PARSE_NOT_LONGNAME) |
381 | goto parse_record; | 382 | goto parse_record; |
@@ -832,6 +833,7 @@ static long fat_compat_dir_ioctl(struct file *filp, unsigned cmd, | |||
832 | #endif /* CONFIG_COMPAT */ | 833 | #endif /* CONFIG_COMPAT */ |
833 | 834 | ||
834 | const struct file_operations fat_dir_operations = { | 835 | const struct file_operations fat_dir_operations = { |
836 | .llseek = generic_file_llseek, | ||
835 | .read = generic_read_dir, | 837 | .read = generic_read_dir, |
836 | .readdir = fat_readdir, | 838 | .readdir = fat_readdir, |
837 | .ioctl = fat_dir_ioctl, | 839 | .ioctl = fat_dir_ioctl, |
@@ -1089,6 +1091,7 @@ int fat_alloc_new_dir(struct inode *dir, struct timespec *ts) | |||
1089 | struct msdos_dir_entry *de; | 1091 | struct msdos_dir_entry *de; |
1090 | sector_t blknr; | 1092 | sector_t blknr; |
1091 | __le16 date, time; | 1093 | __le16 date, time; |
1094 | u8 time_cs; | ||
1092 | int err, cluster; | 1095 | int err, cluster; |
1093 | 1096 | ||
1094 | err = fat_alloc_clusters(dir, &cluster, 1); | 1097 | err = fat_alloc_clusters(dir, &cluster, 1); |
@@ -1102,7 +1105,7 @@ int fat_alloc_new_dir(struct inode *dir, struct timespec *ts) | |||
1102 | goto error_free; | 1105 | goto error_free; |
1103 | } | 1106 | } |
1104 | 1107 | ||
1105 | fat_date_unix2dos(ts->tv_sec, &time, &date, sbi->options.tz_utc); | 1108 | fat_time_unix2fat(sbi, ts, &time, &date, &time_cs); |
1106 | 1109 | ||
1107 | de = (struct msdos_dir_entry *)bhs[0]->b_data; | 1110 | de = (struct msdos_dir_entry *)bhs[0]->b_data; |
1108 | /* filling the new directory slots ("." and ".." entries) */ | 1111 | /* filling the new directory slots ("." and ".." entries) */ |
@@ -1112,13 +1115,14 @@ int fat_alloc_new_dir(struct inode *dir, struct timespec *ts) | |||
1112 | de[0].lcase = de[1].lcase = 0; | 1115 | de[0].lcase = de[1].lcase = 0; |
1113 | de[0].time = de[1].time = time; | 1116 | de[0].time = de[1].time = time; |
1114 | de[0].date = de[1].date = date; | 1117 | de[0].date = de[1].date = date; |
1115 | de[0].ctime_cs = de[1].ctime_cs = 0; | ||
1116 | if (sbi->options.isvfat) { | 1118 | if (sbi->options.isvfat) { |
1117 | /* extra timestamps */ | 1119 | /* extra timestamps */ |
1118 | de[0].ctime = de[1].ctime = time; | 1120 | de[0].ctime = de[1].ctime = time; |
1121 | de[0].ctime_cs = de[1].ctime_cs = time_cs; | ||
1119 | de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = date; | 1122 | de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = date; |
1120 | } else { | 1123 | } else { |
1121 | de[0].ctime = de[1].ctime = 0; | 1124 | de[0].ctime = de[1].ctime = 0; |
1125 | de[0].ctime_cs = de[1].ctime_cs = 0; | ||
1122 | de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = 0; | 1126 | de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = 0; |
1123 | } | 1127 | } |
1124 | de[0].start = cpu_to_le16(cluster); | 1128 | de[0].start = cpu_to_le16(cluster); |
diff --git a/fs/fat/fat.h b/fs/fat/fat.h new file mode 100644 index 000000000000..ea440d65819c --- /dev/null +++ b/fs/fat/fat.h | |||
@@ -0,0 +1,329 @@ | |||
1 | #ifndef _FAT_H | ||
2 | #define _FAT_H | ||
3 | |||
4 | #include <linux/buffer_head.h> | ||
5 | #include <linux/string.h> | ||
6 | #include <linux/nls.h> | ||
7 | #include <linux/fs.h> | ||
8 | #include <linux/mutex.h> | ||
9 | #include <linux/msdos_fs.h> | ||
10 | |||
11 | /* | ||
12 | * vfat shortname flags | ||
13 | */ | ||
14 | #define VFAT_SFN_DISPLAY_LOWER 0x0001 /* convert to lowercase for display */ | ||
15 | #define VFAT_SFN_DISPLAY_WIN95 0x0002 /* emulate win95 rule for display */ | ||
16 | #define VFAT_SFN_DISPLAY_WINNT 0x0004 /* emulate winnt rule for display */ | ||
17 | #define VFAT_SFN_CREATE_WIN95 0x0100 /* emulate win95 rule for create */ | ||
18 | #define VFAT_SFN_CREATE_WINNT 0x0200 /* emulate winnt rule for create */ | ||
19 | |||
20 | struct fat_mount_options { | ||
21 | uid_t fs_uid; | ||
22 | gid_t fs_gid; | ||
23 | unsigned short fs_fmask; | ||
24 | unsigned short fs_dmask; | ||
25 | unsigned short codepage; /* Codepage for shortname conversions */ | ||
26 | char *iocharset; /* Charset used for filename input/display */ | ||
27 | unsigned short shortname; /* flags for shortname display/create rule */ | ||
28 | unsigned char name_check; /* r = relaxed, n = normal, s = strict */ | ||
29 | unsigned short allow_utime;/* permission for setting the [am]time */ | ||
30 | unsigned quiet:1, /* set = fake successful chmods and chowns */ | ||
31 | showexec:1, /* set = only set x bit for com/exe/bat */ | ||
32 | sys_immutable:1, /* set = system files are immutable */ | ||
33 | dotsOK:1, /* set = hidden and system files are named '.filename' */ | ||
34 | isvfat:1, /* 0=no vfat long filename support, 1=vfat support */ | ||
35 | utf8:1, /* Use of UTF-8 character set (Default) */ | ||
36 | unicode_xlate:1, /* create escape sequences for unhandled Unicode */ | ||
37 | numtail:1, /* Does first alias have a numeric '~1' type tail? */ | ||
38 | flush:1, /* write things quickly */ | ||
39 | nocase:1, /* Does this need case conversion? 0=need case conversion*/ | ||
40 | usefree:1, /* Use free_clusters for FAT32 */ | ||
41 | tz_utc:1, /* Filesystem timestamps are in UTC */ | ||
42 | rodir:1; /* allow ATTR_RO for directory */ | ||
43 | }; | ||
44 | |||
45 | #define FAT_HASH_BITS 8 | ||
46 | #define FAT_HASH_SIZE (1UL << FAT_HASH_BITS) | ||
47 | |||
48 | /* | ||
49 | * MS-DOS file system in-core superblock data | ||
50 | */ | ||
51 | struct msdos_sb_info { | ||
52 | unsigned short sec_per_clus; /* sectors/cluster */ | ||
53 | unsigned short cluster_bits; /* log2(cluster_size) */ | ||
54 | unsigned int cluster_size; /* cluster size */ | ||
55 | unsigned char fats,fat_bits; /* number of FATs, FAT bits (12 or 16) */ | ||
56 | unsigned short fat_start; | ||
57 | unsigned long fat_length; /* FAT start & length (sec.) */ | ||
58 | unsigned long dir_start; | ||
59 | unsigned short dir_entries; /* root dir start & entries */ | ||
60 | unsigned long data_start; /* first data sector */ | ||
61 | unsigned long max_cluster; /* maximum cluster number */ | ||
62 | unsigned long root_cluster; /* first cluster of the root directory */ | ||
63 | unsigned long fsinfo_sector; /* sector number of FAT32 fsinfo */ | ||
64 | struct mutex fat_lock; | ||
65 | unsigned int prev_free; /* previously allocated cluster number */ | ||
66 | unsigned int free_clusters; /* -1 if undefined */ | ||
67 | unsigned int free_clus_valid; /* is free_clusters valid? */ | ||
68 | struct fat_mount_options options; | ||
69 | struct nls_table *nls_disk; /* Codepage used on disk */ | ||
70 | struct nls_table *nls_io; /* Charset used for input and display */ | ||
71 | const void *dir_ops; /* Opaque; default directory operations */ | ||
72 | int dir_per_block; /* dir entries per block */ | ||
73 | int dir_per_block_bits; /* log2(dir_per_block) */ | ||
74 | |||
75 | int fatent_shift; | ||
76 | struct fatent_operations *fatent_ops; | ||
77 | |||
78 | spinlock_t inode_hash_lock; | ||
79 | struct hlist_head inode_hashtable[FAT_HASH_SIZE]; | ||
80 | }; | ||
81 | |||
82 | #define FAT_CACHE_VALID 0 /* special case for valid cache */ | ||
83 | |||
84 | /* | ||
85 | * MS-DOS file system inode data in memory | ||
86 | */ | ||
87 | struct msdos_inode_info { | ||
88 | spinlock_t cache_lru_lock; | ||
89 | struct list_head cache_lru; | ||
90 | int nr_caches; | ||
91 | /* for avoiding the race between fat_free() and fat_get_cluster() */ | ||
92 | unsigned int cache_valid_id; | ||
93 | |||
94 | /* NOTE: mmu_private is 64bits, so must hold ->i_mutex to access */ | ||
95 | loff_t mmu_private; /* physically allocated size */ | ||
96 | |||
97 | int i_start; /* first cluster or 0 */ | ||
98 | int i_logstart; /* logical first cluster */ | ||
99 | int i_attrs; /* unused attribute bits */ | ||
100 | loff_t i_pos; /* on-disk position of directory entry or 0 */ | ||
101 | struct hlist_node i_fat_hash; /* hash by i_location */ | ||
102 | struct inode vfs_inode; | ||
103 | }; | ||
104 | |||
105 | struct fat_slot_info { | ||
106 | loff_t i_pos; /* on-disk position of directory entry */ | ||
107 | loff_t slot_off; /* offset for slot or de start */ | ||
108 | int nr_slots; /* number of slots + 1(de) in filename */ | ||
109 | struct msdos_dir_entry *de; | ||
110 | struct buffer_head *bh; | ||
111 | }; | ||
112 | |||
113 | static inline struct msdos_sb_info *MSDOS_SB(struct super_block *sb) | ||
114 | { | ||
115 | return sb->s_fs_info; | ||
116 | } | ||
117 | |||
118 | static inline struct msdos_inode_info *MSDOS_I(struct inode *inode) | ||
119 | { | ||
120 | return container_of(inode, struct msdos_inode_info, vfs_inode); | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * If ->i_mode can't hold S_IWUGO (i.e. ATTR_RO), we use ->i_attrs to | ||
125 | * save ATTR_RO instead of ->i_mode. | ||
126 | * | ||
127 | * If it's directory and !sbi->options.rodir, ATTR_RO isn't read-only | ||
128 | * bit, it's just used as flag for app. | ||
129 | */ | ||
130 | static inline int fat_mode_can_hold_ro(struct inode *inode) | ||
131 | { | ||
132 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | ||
133 | mode_t mask; | ||
134 | |||
135 | if (S_ISDIR(inode->i_mode)) { | ||
136 | if (!sbi->options.rodir) | ||
137 | return 0; | ||
138 | mask = ~sbi->options.fs_dmask; | ||
139 | } else | ||
140 | mask = ~sbi->options.fs_fmask; | ||
141 | |||
142 | if (!(mask & S_IWUGO)) | ||
143 | return 0; | ||
144 | return 1; | ||
145 | } | ||
146 | |||
147 | /* Convert attribute bits and a mask to the UNIX mode. */ | ||
148 | static inline mode_t fat_make_mode(struct msdos_sb_info *sbi, | ||
149 | u8 attrs, mode_t mode) | ||
150 | { | ||
151 | if (attrs & ATTR_RO && !((attrs & ATTR_DIR) && !sbi->options.rodir)) | ||
152 | mode &= ~S_IWUGO; | ||
153 | |||
154 | if (attrs & ATTR_DIR) | ||
155 | return (mode & ~sbi->options.fs_dmask) | S_IFDIR; | ||
156 | else | ||
157 | return (mode & ~sbi->options.fs_fmask) | S_IFREG; | ||
158 | } | ||
159 | |||
160 | /* Return the FAT attribute byte for this inode */ | ||
161 | static inline u8 fat_make_attrs(struct inode *inode) | ||
162 | { | ||
163 | u8 attrs = MSDOS_I(inode)->i_attrs; | ||
164 | if (S_ISDIR(inode->i_mode)) | ||
165 | attrs |= ATTR_DIR; | ||
166 | if (fat_mode_can_hold_ro(inode) && !(inode->i_mode & S_IWUGO)) | ||
167 | attrs |= ATTR_RO; | ||
168 | return attrs; | ||
169 | } | ||
170 | |||
171 | static inline void fat_save_attrs(struct inode *inode, u8 attrs) | ||
172 | { | ||
173 | if (fat_mode_can_hold_ro(inode)) | ||
174 | MSDOS_I(inode)->i_attrs = attrs & ATTR_UNUSED; | ||
175 | else | ||
176 | MSDOS_I(inode)->i_attrs = attrs & (ATTR_UNUSED | ATTR_RO); | ||
177 | } | ||
178 | |||
179 | static inline unsigned char fat_checksum(const __u8 *name) | ||
180 | { | ||
181 | unsigned char s = name[0]; | ||
182 | s = (s<<7) + (s>>1) + name[1]; s = (s<<7) + (s>>1) + name[2]; | ||
183 | s = (s<<7) + (s>>1) + name[3]; s = (s<<7) + (s>>1) + name[4]; | ||
184 | s = (s<<7) + (s>>1) + name[5]; s = (s<<7) + (s>>1) + name[6]; | ||
185 | s = (s<<7) + (s>>1) + name[7]; s = (s<<7) + (s>>1) + name[8]; | ||
186 | s = (s<<7) + (s>>1) + name[9]; s = (s<<7) + (s>>1) + name[10]; | ||
187 | return s; | ||
188 | } | ||
189 | |||
190 | static inline sector_t fat_clus_to_blknr(struct msdos_sb_info *sbi, int clus) | ||
191 | { | ||
192 | return ((sector_t)clus - FAT_START_ENT) * sbi->sec_per_clus | ||
193 | + sbi->data_start; | ||
194 | } | ||
195 | |||
196 | static inline void fat16_towchar(wchar_t *dst, const __u8 *src, size_t len) | ||
197 | { | ||
198 | #ifdef __BIG_ENDIAN | ||
199 | while (len--) { | ||
200 | *dst++ = src[0] | (src[1] << 8); | ||
201 | src += 2; | ||
202 | } | ||
203 | #else | ||
204 | memcpy(dst, src, len * 2); | ||
205 | #endif | ||
206 | } | ||
207 | |||
208 | static inline void fatwchar_to16(__u8 *dst, const wchar_t *src, size_t len) | ||
209 | { | ||
210 | #ifdef __BIG_ENDIAN | ||
211 | while (len--) { | ||
212 | dst[0] = *src & 0x00FF; | ||
213 | dst[1] = (*src & 0xFF00) >> 8; | ||
214 | dst += 2; | ||
215 | src++; | ||
216 | } | ||
217 | #else | ||
218 | memcpy(dst, src, len * 2); | ||
219 | #endif | ||
220 | } | ||
221 | |||
222 | /* fat/cache.c */ | ||
223 | extern void fat_cache_inval_inode(struct inode *inode); | ||
224 | extern int fat_get_cluster(struct inode *inode, int cluster, | ||
225 | int *fclus, int *dclus); | ||
226 | extern int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys, | ||
227 | unsigned long *mapped_blocks, int create); | ||
228 | |||
229 | /* fat/dir.c */ | ||
230 | extern const struct file_operations fat_dir_operations; | ||
231 | extern int fat_search_long(struct inode *inode, const unsigned char *name, | ||
232 | int name_len, struct fat_slot_info *sinfo); | ||
233 | extern int fat_dir_empty(struct inode *dir); | ||
234 | extern int fat_subdirs(struct inode *dir); | ||
235 | extern int fat_scan(struct inode *dir, const unsigned char *name, | ||
236 | struct fat_slot_info *sinfo); | ||
237 | extern int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh, | ||
238 | struct msdos_dir_entry **de, loff_t *i_pos); | ||
239 | extern int fat_alloc_new_dir(struct inode *dir, struct timespec *ts); | ||
240 | extern int fat_add_entries(struct inode *dir, void *slots, int nr_slots, | ||
241 | struct fat_slot_info *sinfo); | ||
242 | extern int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo); | ||
243 | |||
244 | /* fat/fatent.c */ | ||
245 | struct fat_entry { | ||
246 | int entry; | ||
247 | union { | ||
248 | u8 *ent12_p[2]; | ||
249 | __le16 *ent16_p; | ||
250 | __le32 *ent32_p; | ||
251 | } u; | ||
252 | int nr_bhs; | ||
253 | struct buffer_head *bhs[2]; | ||
254 | }; | ||
255 | |||
256 | static inline void fatent_init(struct fat_entry *fatent) | ||
257 | { | ||
258 | fatent->nr_bhs = 0; | ||
259 | fatent->entry = 0; | ||
260 | fatent->u.ent32_p = NULL; | ||
261 | fatent->bhs[0] = fatent->bhs[1] = NULL; | ||
262 | } | ||
263 | |||
264 | static inline void fatent_set_entry(struct fat_entry *fatent, int entry) | ||
265 | { | ||
266 | fatent->entry = entry; | ||
267 | fatent->u.ent32_p = NULL; | ||
268 | } | ||
269 | |||
270 | static inline void fatent_brelse(struct fat_entry *fatent) | ||
271 | { | ||
272 | int i; | ||
273 | fatent->u.ent32_p = NULL; | ||
274 | for (i = 0; i < fatent->nr_bhs; i++) | ||
275 | brelse(fatent->bhs[i]); | ||
276 | fatent->nr_bhs = 0; | ||
277 | fatent->bhs[0] = fatent->bhs[1] = NULL; | ||
278 | } | ||
279 | |||
280 | extern void fat_ent_access_init(struct super_block *sb); | ||
281 | extern int fat_ent_read(struct inode *inode, struct fat_entry *fatent, | ||
282 | int entry); | ||
283 | extern int fat_ent_write(struct inode *inode, struct fat_entry *fatent, | ||
284 | int new, int wait); | ||
285 | extern int fat_alloc_clusters(struct inode *inode, int *cluster, | ||
286 | int nr_cluster); | ||
287 | extern int fat_free_clusters(struct inode *inode, int cluster); | ||
288 | extern int fat_count_free_clusters(struct super_block *sb); | ||
289 | |||
290 | /* fat/file.c */ | ||
291 | extern int fat_generic_ioctl(struct inode *inode, struct file *filp, | ||
292 | unsigned int cmd, unsigned long arg); | ||
293 | extern const struct file_operations fat_file_operations; | ||
294 | extern const struct inode_operations fat_file_inode_operations; | ||
295 | extern int fat_setattr(struct dentry * dentry, struct iattr * attr); | ||
296 | extern void fat_truncate(struct inode *inode); | ||
297 | extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, | ||
298 | struct kstat *stat); | ||
299 | |||
300 | /* fat/inode.c */ | ||
301 | extern void fat_attach(struct inode *inode, loff_t i_pos); | ||
302 | extern void fat_detach(struct inode *inode); | ||
303 | extern struct inode *fat_iget(struct super_block *sb, loff_t i_pos); | ||
304 | extern struct inode *fat_build_inode(struct super_block *sb, | ||
305 | struct msdos_dir_entry *de, loff_t i_pos); | ||
306 | extern int fat_sync_inode(struct inode *inode); | ||
307 | extern int fat_fill_super(struct super_block *sb, void *data, int silent, | ||
308 | const struct inode_operations *fs_dir_inode_ops, int isvfat); | ||
309 | |||
310 | extern int fat_flush_inodes(struct super_block *sb, struct inode *i1, | ||
311 | struct inode *i2); | ||
312 | /* fat/misc.c */ | ||
313 | extern void fat_fs_panic(struct super_block *s, const char *fmt, ...) | ||
314 | __attribute__ ((format (printf, 2, 3))) __cold; | ||
315 | extern void fat_clusters_flush(struct super_block *sb); | ||
316 | extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster); | ||
317 | extern void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec *ts, | ||
318 | __le16 __time, __le16 __date, u8 time_cs); | ||
319 | extern void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec *ts, | ||
320 | __le16 *time, __le16 *date, u8 *time_cs); | ||
321 | extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs); | ||
322 | |||
323 | int fat_cache_init(void); | ||
324 | void fat_cache_destroy(void); | ||
325 | |||
326 | /* helper for printk */ | ||
327 | typedef unsigned long long llu; | ||
328 | |||
329 | #endif /* !_FAT_H */ | ||
diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index fb98b3d847ed..da6eea47872f 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <linux/fs.h> | 7 | #include <linux/fs.h> |
8 | #include <linux/msdos_fs.h> | 8 | #include <linux/msdos_fs.h> |
9 | #include <linux/blkdev.h> | 9 | #include <linux/blkdev.h> |
10 | #include "fat.h" | ||
10 | 11 | ||
11 | struct fatent_operations { | 12 | struct fatent_operations { |
12 | void (*ent_blocknr)(struct super_block *, int, int *, sector_t *); | 13 | void (*ent_blocknr)(struct super_block *, int, int *, sector_t *); |
@@ -92,8 +93,7 @@ static int fat12_ent_bread(struct super_block *sb, struct fat_entry *fatent, | |||
92 | err_brelse: | 93 | err_brelse: |
93 | brelse(bhs[0]); | 94 | brelse(bhs[0]); |
94 | err: | 95 | err: |
95 | printk(KERN_ERR "FAT: FAT read failed (blocknr %llu)\n", | 96 | printk(KERN_ERR "FAT: FAT read failed (blocknr %llu)\n", (llu)blocknr); |
96 | (unsigned long long)blocknr); | ||
97 | return -EIO; | 97 | return -EIO; |
98 | } | 98 | } |
99 | 99 | ||
@@ -106,7 +106,7 @@ static int fat_ent_bread(struct super_block *sb, struct fat_entry *fatent, | |||
106 | fatent->bhs[0] = sb_bread(sb, blocknr); | 106 | fatent->bhs[0] = sb_bread(sb, blocknr); |
107 | if (!fatent->bhs[0]) { | 107 | if (!fatent->bhs[0]) { |
108 | printk(KERN_ERR "FAT: FAT read failed (blocknr %llu)\n", | 108 | printk(KERN_ERR "FAT: FAT read failed (blocknr %llu)\n", |
109 | (unsigned long long)blocknr); | 109 | (llu)blocknr); |
110 | return -EIO; | 110 | return -EIO; |
111 | } | 111 | } |
112 | fatent->nr_bhs = 1; | 112 | fatent->nr_bhs = 1; |
@@ -316,10 +316,20 @@ static inline int fat_ent_update_ptr(struct super_block *sb, | |||
316 | /* Is this fatent's blocks including this entry? */ | 316 | /* Is this fatent's blocks including this entry? */ |
317 | if (!fatent->nr_bhs || bhs[0]->b_blocknr != blocknr) | 317 | if (!fatent->nr_bhs || bhs[0]->b_blocknr != blocknr) |
318 | return 0; | 318 | return 0; |
319 | /* Does this entry need the next block? */ | 319 | if (sbi->fat_bits == 12) { |
320 | if (sbi->fat_bits == 12 && (offset + 1) >= sb->s_blocksize) { | 320 | if ((offset + 1) < sb->s_blocksize) { |
321 | if (fatent->nr_bhs != 2 || bhs[1]->b_blocknr != (blocknr + 1)) | 321 | /* This entry is on bhs[0]. */ |
322 | return 0; | 322 | if (fatent->nr_bhs == 2) { |
323 | brelse(bhs[1]); | ||
324 | fatent->nr_bhs = 1; | ||
325 | } | ||
326 | } else { | ||
327 | /* This entry needs the next block. */ | ||
328 | if (fatent->nr_bhs != 2) | ||
329 | return 0; | ||
330 | if (bhs[1]->b_blocknr != (blocknr + 1)) | ||
331 | return 0; | ||
332 | } | ||
323 | } | 333 | } |
324 | ops->ent_set_ptr(fatent, offset); | 334 | ops->ent_set_ptr(fatent, offset); |
325 | return 1; | 335 | return 1; |
diff --git a/fs/fat/file.c b/fs/fat/file.c index ddde37025ca6..f06a4e525ece 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c | |||
@@ -10,13 +10,13 @@ | |||
10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <linux/mount.h> | 11 | #include <linux/mount.h> |
12 | #include <linux/time.h> | 12 | #include <linux/time.h> |
13 | #include <linux/msdos_fs.h> | ||
14 | #include <linux/buffer_head.h> | 13 | #include <linux/buffer_head.h> |
15 | #include <linux/writeback.h> | 14 | #include <linux/writeback.h> |
16 | #include <linux/backing-dev.h> | 15 | #include <linux/backing-dev.h> |
17 | #include <linux/blkdev.h> | 16 | #include <linux/blkdev.h> |
18 | #include <linux/fsnotify.h> | 17 | #include <linux/fsnotify.h> |
19 | #include <linux/security.h> | 18 | #include <linux/security.h> |
19 | #include "fat.h" | ||
20 | 20 | ||
21 | int fat_generic_ioctl(struct inode *inode, struct file *filp, | 21 | int fat_generic_ioctl(struct inode *inode, struct file *filp, |
22 | unsigned int cmd, unsigned long arg) | 22 | unsigned int cmd, unsigned long arg) |
@@ -29,10 +29,9 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp, | |||
29 | { | 29 | { |
30 | u32 attr; | 30 | u32 attr; |
31 | 31 | ||
32 | if (inode->i_ino == MSDOS_ROOT_INO) | 32 | mutex_lock(&inode->i_mutex); |
33 | attr = ATTR_DIR; | 33 | attr = fat_make_attrs(inode); |
34 | else | 34 | mutex_unlock(&inode->i_mutex); |
35 | attr = fat_attr(inode); | ||
36 | 35 | ||
37 | return put_user(attr, user_attr); | 36 | return put_user(attr, user_attr); |
38 | } | 37 | } |
@@ -62,20 +61,16 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp, | |||
62 | /* Merge in ATTR_VOLUME and ATTR_DIR */ | 61 | /* Merge in ATTR_VOLUME and ATTR_DIR */ |
63 | attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) | | 62 | attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) | |
64 | (is_dir ? ATTR_DIR : 0); | 63 | (is_dir ? ATTR_DIR : 0); |
65 | oldattr = fat_attr(inode); | 64 | oldattr = fat_make_attrs(inode); |
66 | 65 | ||
67 | /* Equivalent to a chmod() */ | 66 | /* Equivalent to a chmod() */ |
68 | ia.ia_valid = ATTR_MODE | ATTR_CTIME; | 67 | ia.ia_valid = ATTR_MODE | ATTR_CTIME; |
69 | ia.ia_ctime = current_fs_time(inode->i_sb); | 68 | ia.ia_ctime = current_fs_time(inode->i_sb); |
70 | if (is_dir) { | 69 | if (is_dir) |
71 | ia.ia_mode = MSDOS_MKMODE(attr, | 70 | ia.ia_mode = fat_make_mode(sbi, attr, S_IRWXUGO); |
72 | S_IRWXUGO & ~sbi->options.fs_dmask) | 71 | else { |
73 | | S_IFDIR; | 72 | ia.ia_mode = fat_make_mode(sbi, attr, |
74 | } else { | 73 | S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO)); |
75 | ia.ia_mode = MSDOS_MKMODE(attr, | ||
76 | (S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO)) | ||
77 | & ~sbi->options.fs_fmask) | ||
78 | | S_IFREG; | ||
79 | } | 74 | } |
80 | 75 | ||
81 | /* The root directory has no attributes */ | 76 | /* The root directory has no attributes */ |
@@ -115,7 +110,7 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp, | |||
115 | inode->i_flags &= S_IMMUTABLE; | 110 | inode->i_flags &= S_IMMUTABLE; |
116 | } | 111 | } |
117 | 112 | ||
118 | MSDOS_I(inode)->i_attrs = attr & ATTR_UNUSED; | 113 | fat_save_attrs(inode, attr); |
119 | mark_inode_dirty(inode); | 114 | mark_inode_dirty(inode); |
120 | up: | 115 | up: |
121 | mnt_drop_write(filp->f_path.mnt); | 116 | mnt_drop_write(filp->f_path.mnt); |
@@ -274,7 +269,7 @@ static int fat_sanitize_mode(const struct msdos_sb_info *sbi, | |||
274 | 269 | ||
275 | /* | 270 | /* |
276 | * Note, the basic check is already done by a caller of | 271 | * Note, the basic check is already done by a caller of |
277 | * (attr->ia_mode & ~MSDOS_VALID_MODE) | 272 | * (attr->ia_mode & ~FAT_VALID_MODE) |
278 | */ | 273 | */ |
279 | 274 | ||
280 | if (S_ISREG(inode->i_mode)) | 275 | if (S_ISREG(inode->i_mode)) |
@@ -287,11 +282,18 @@ static int fat_sanitize_mode(const struct msdos_sb_info *sbi, | |||
287 | /* | 282 | /* |
288 | * Of the r and x bits, all (subject to umask) must be present. Of the | 283 | * Of the r and x bits, all (subject to umask) must be present. Of the |
289 | * w bits, either all (subject to umask) or none must be present. | 284 | * w bits, either all (subject to umask) or none must be present. |
285 | * | ||
286 | * If fat_mode_can_hold_ro(inode) is false, can't change w bits. | ||
290 | */ | 287 | */ |
291 | if ((perm & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO))) | 288 | if ((perm & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO))) |
292 | return -EPERM; | 289 | return -EPERM; |
293 | if ((perm & S_IWUGO) && ((perm & S_IWUGO) != (S_IWUGO & ~mask))) | 290 | if (fat_mode_can_hold_ro(inode)) { |
294 | return -EPERM; | 291 | if ((perm & S_IWUGO) && ((perm & S_IWUGO) != (S_IWUGO & ~mask))) |
292 | return -EPERM; | ||
293 | } else { | ||
294 | if ((perm & S_IWUGO) != (S_IWUGO & ~mask)) | ||
295 | return -EPERM; | ||
296 | } | ||
295 | 297 | ||
296 | *mode_ptr &= S_IFMT | perm; | 298 | *mode_ptr &= S_IFMT | perm; |
297 | 299 | ||
@@ -314,13 +316,15 @@ static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode) | |||
314 | } | 316 | } |
315 | 317 | ||
316 | #define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET) | 318 | #define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET) |
319 | /* valid file mode bits */ | ||
320 | #define FAT_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXUGO) | ||
317 | 321 | ||
318 | int fat_setattr(struct dentry *dentry, struct iattr *attr) | 322 | int fat_setattr(struct dentry *dentry, struct iattr *attr) |
319 | { | 323 | { |
320 | struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); | 324 | struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); |
321 | struct inode *inode = dentry->d_inode; | 325 | struct inode *inode = dentry->d_inode; |
322 | int error = 0; | ||
323 | unsigned int ia_valid; | 326 | unsigned int ia_valid; |
327 | int error; | ||
324 | 328 | ||
325 | /* | 329 | /* |
326 | * Expand the file. Since inode_setattr() updates ->i_size | 330 | * Expand the file. Since inode_setattr() updates ->i_size |
@@ -356,7 +360,7 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) | |||
356 | ((attr->ia_valid & ATTR_GID) && | 360 | ((attr->ia_valid & ATTR_GID) && |
357 | (attr->ia_gid != sbi->options.fs_gid)) || | 361 | (attr->ia_gid != sbi->options.fs_gid)) || |
358 | ((attr->ia_valid & ATTR_MODE) && | 362 | ((attr->ia_valid & ATTR_MODE) && |
359 | (attr->ia_mode & ~MSDOS_VALID_MODE))) | 363 | (attr->ia_mode & ~FAT_VALID_MODE))) |
360 | error = -EPERM; | 364 | error = -EPERM; |
361 | 365 | ||
362 | if (error) { | 366 | if (error) { |
@@ -374,7 +378,8 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) | |||
374 | attr->ia_valid &= ~ATTR_MODE; | 378 | attr->ia_valid &= ~ATTR_MODE; |
375 | } | 379 | } |
376 | 380 | ||
377 | error = inode_setattr(inode, attr); | 381 | if (attr->ia_valid) |
382 | error = inode_setattr(inode, attr); | ||
378 | out: | 383 | out: |
379 | return error; | 384 | return error; |
380 | } | 385 | } |
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 2b2eec1283bf..bdd8fb7be2ca 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
@@ -16,7 +16,6 @@ | |||
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/smp_lock.h> | 17 | #include <linux/smp_lock.h> |
18 | #include <linux/seq_file.h> | 18 | #include <linux/seq_file.h> |
19 | #include <linux/msdos_fs.h> | ||
20 | #include <linux/pagemap.h> | 19 | #include <linux/pagemap.h> |
21 | #include <linux/mpage.h> | 20 | #include <linux/mpage.h> |
22 | #include <linux/buffer_head.h> | 21 | #include <linux/buffer_head.h> |
@@ -27,7 +26,9 @@ | |||
27 | #include <linux/uio.h> | 26 | #include <linux/uio.h> |
28 | #include <linux/writeback.h> | 27 | #include <linux/writeback.h> |
29 | #include <linux/log2.h> | 28 | #include <linux/log2.h> |
29 | #include <linux/hash.h> | ||
30 | #include <asm/unaligned.h> | 30 | #include <asm/unaligned.h> |
31 | #include "fat.h" | ||
31 | 32 | ||
32 | #ifndef CONFIG_FAT_DEFAULT_IOCHARSET | 33 | #ifndef CONFIG_FAT_DEFAULT_IOCHARSET |
33 | /* if user don't select VFAT, this is undefined. */ | 34 | /* if user don't select VFAT, this is undefined. */ |
@@ -63,7 +64,7 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock, | |||
63 | sector_t phys; | 64 | sector_t phys; |
64 | int err, offset; | 65 | int err, offset; |
65 | 66 | ||
66 | err = fat_bmap(inode, iblock, &phys, &mapped_blocks); | 67 | err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create); |
67 | if (err) | 68 | if (err) |
68 | return err; | 69 | return err; |
69 | if (phys) { | 70 | if (phys) { |
@@ -93,7 +94,7 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock, | |||
93 | *max_blocks = min(mapped_blocks, *max_blocks); | 94 | *max_blocks = min(mapped_blocks, *max_blocks); |
94 | MSDOS_I(inode)->mmu_private += *max_blocks << sb->s_blocksize_bits; | 95 | MSDOS_I(inode)->mmu_private += *max_blocks << sb->s_blocksize_bits; |
95 | 96 | ||
96 | err = fat_bmap(inode, iblock, &phys, &mapped_blocks); | 97 | err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create); |
97 | if (err) | 98 | if (err) |
98 | return err; | 99 | return err; |
99 | 100 | ||
@@ -198,7 +199,14 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, | |||
198 | 199 | ||
199 | static sector_t _fat_bmap(struct address_space *mapping, sector_t block) | 200 | static sector_t _fat_bmap(struct address_space *mapping, sector_t block) |
200 | { | 201 | { |
201 | return generic_block_bmap(mapping, block, fat_get_block); | 202 | sector_t blocknr; |
203 | |||
204 | /* fat_get_cluster() assumes the requested blocknr isn't truncated. */ | ||
205 | mutex_lock(&mapping->host->i_mutex); | ||
206 | blocknr = generic_block_bmap(mapping, block, fat_get_block); | ||
207 | mutex_unlock(&mapping->host->i_mutex); | ||
208 | |||
209 | return blocknr; | ||
202 | } | 210 | } |
203 | 211 | ||
204 | static const struct address_space_operations fat_aops = { | 212 | static const struct address_space_operations fat_aops = { |
@@ -247,25 +255,21 @@ static void fat_hash_init(struct super_block *sb) | |||
247 | INIT_HLIST_HEAD(&sbi->inode_hashtable[i]); | 255 | INIT_HLIST_HEAD(&sbi->inode_hashtable[i]); |
248 | } | 256 | } |
249 | 257 | ||
250 | static inline unsigned long fat_hash(struct super_block *sb, loff_t i_pos) | 258 | static inline unsigned long fat_hash(loff_t i_pos) |
251 | { | 259 | { |
252 | unsigned long tmp = (unsigned long)i_pos | (unsigned long) sb; | 260 | return hash_32(i_pos, FAT_HASH_BITS); |
253 | tmp = tmp + (tmp >> FAT_HASH_BITS) + (tmp >> FAT_HASH_BITS * 2); | ||
254 | return tmp & FAT_HASH_MASK; | ||
255 | } | 261 | } |
256 | 262 | ||
257 | void fat_attach(struct inode *inode, loff_t i_pos) | 263 | void fat_attach(struct inode *inode, loff_t i_pos) |
258 | { | 264 | { |
259 | struct super_block *sb = inode->i_sb; | 265 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); |
260 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | 266 | struct hlist_head *head = sbi->inode_hashtable + fat_hash(i_pos); |
261 | 267 | ||
262 | spin_lock(&sbi->inode_hash_lock); | 268 | spin_lock(&sbi->inode_hash_lock); |
263 | MSDOS_I(inode)->i_pos = i_pos; | 269 | MSDOS_I(inode)->i_pos = i_pos; |
264 | hlist_add_head(&MSDOS_I(inode)->i_fat_hash, | 270 | hlist_add_head(&MSDOS_I(inode)->i_fat_hash, head); |
265 | sbi->inode_hashtable + fat_hash(sb, i_pos)); | ||
266 | spin_unlock(&sbi->inode_hash_lock); | 271 | spin_unlock(&sbi->inode_hash_lock); |
267 | } | 272 | } |
268 | |||
269 | EXPORT_SYMBOL_GPL(fat_attach); | 273 | EXPORT_SYMBOL_GPL(fat_attach); |
270 | 274 | ||
271 | void fat_detach(struct inode *inode) | 275 | void fat_detach(struct inode *inode) |
@@ -276,13 +280,12 @@ void fat_detach(struct inode *inode) | |||
276 | hlist_del_init(&MSDOS_I(inode)->i_fat_hash); | 280 | hlist_del_init(&MSDOS_I(inode)->i_fat_hash); |
277 | spin_unlock(&sbi->inode_hash_lock); | 281 | spin_unlock(&sbi->inode_hash_lock); |
278 | } | 282 | } |
279 | |||
280 | EXPORT_SYMBOL_GPL(fat_detach); | 283 | EXPORT_SYMBOL_GPL(fat_detach); |
281 | 284 | ||
282 | struct inode *fat_iget(struct super_block *sb, loff_t i_pos) | 285 | struct inode *fat_iget(struct super_block *sb, loff_t i_pos) |
283 | { | 286 | { |
284 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | 287 | struct msdos_sb_info *sbi = MSDOS_SB(sb); |
285 | struct hlist_head *head = sbi->inode_hashtable + fat_hash(sb, i_pos); | 288 | struct hlist_head *head = sbi->inode_hashtable + fat_hash(i_pos); |
286 | struct hlist_node *_p; | 289 | struct hlist_node *_p; |
287 | struct msdos_inode_info *i; | 290 | struct msdos_inode_info *i; |
288 | struct inode *inode = NULL; | 291 | struct inode *inode = NULL; |
@@ -341,8 +344,7 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) | |||
341 | 344 | ||
342 | if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) { | 345 | if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) { |
343 | inode->i_generation &= ~1; | 346 | inode->i_generation &= ~1; |
344 | inode->i_mode = MSDOS_MKMODE(de->attr, | 347 | inode->i_mode = fat_make_mode(sbi, de->attr, S_IRWXUGO); |
345 | S_IRWXUGO & ~sbi->options.fs_dmask) | S_IFDIR; | ||
346 | inode->i_op = sbi->dir_ops; | 348 | inode->i_op = sbi->dir_ops; |
347 | inode->i_fop = &fat_dir_operations; | 349 | inode->i_fop = &fat_dir_operations; |
348 | 350 | ||
@@ -359,10 +361,9 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) | |||
359 | inode->i_nlink = fat_subdirs(inode); | 361 | inode->i_nlink = fat_subdirs(inode); |
360 | } else { /* not a directory */ | 362 | } else { /* not a directory */ |
361 | inode->i_generation |= 1; | 363 | inode->i_generation |= 1; |
362 | inode->i_mode = MSDOS_MKMODE(de->attr, | 364 | inode->i_mode = fat_make_mode(sbi, de->attr, |
363 | ((sbi->options.showexec && !is_exec(de->name + 8)) | 365 | ((sbi->options.showexec && !is_exec(de->name + 8)) |
364 | ? S_IRUGO|S_IWUGO : S_IRWXUGO) | 366 | ? S_IRUGO|S_IWUGO : S_IRWXUGO)); |
365 | & ~sbi->options.fs_fmask) | S_IFREG; | ||
366 | MSDOS_I(inode)->i_start = le16_to_cpu(de->start); | 367 | MSDOS_I(inode)->i_start = le16_to_cpu(de->start); |
367 | if (sbi->fat_bits == 32) | 368 | if (sbi->fat_bits == 32) |
368 | MSDOS_I(inode)->i_start |= (le16_to_cpu(de->starthi) << 16); | 369 | MSDOS_I(inode)->i_start |= (le16_to_cpu(de->starthi) << 16); |
@@ -378,25 +379,16 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) | |||
378 | if (sbi->options.sys_immutable) | 379 | if (sbi->options.sys_immutable) |
379 | inode->i_flags |= S_IMMUTABLE; | 380 | inode->i_flags |= S_IMMUTABLE; |
380 | } | 381 | } |
381 | MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED; | 382 | fat_save_attrs(inode, de->attr); |
383 | |||
382 | inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1)) | 384 | inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1)) |
383 | & ~((loff_t)sbi->cluster_size - 1)) >> 9; | 385 | & ~((loff_t)sbi->cluster_size - 1)) >> 9; |
384 | inode->i_mtime.tv_sec = | 386 | |
385 | date_dos2unix(le16_to_cpu(de->time), le16_to_cpu(de->date), | 387 | fat_time_fat2unix(sbi, &inode->i_mtime, de->time, de->date, 0); |
386 | sbi->options.tz_utc); | ||
387 | inode->i_mtime.tv_nsec = 0; | ||
388 | if (sbi->options.isvfat) { | 388 | if (sbi->options.isvfat) { |
389 | int secs = de->ctime_cs / 100; | 389 | fat_time_fat2unix(sbi, &inode->i_ctime, de->ctime, |
390 | int csecs = de->ctime_cs % 100; | 390 | de->cdate, de->ctime_cs); |
391 | inode->i_ctime.tv_sec = | 391 | fat_time_fat2unix(sbi, &inode->i_atime, 0, de->adate, 0); |
392 | date_dos2unix(le16_to_cpu(de->ctime), | ||
393 | le16_to_cpu(de->cdate), | ||
394 | sbi->options.tz_utc) + secs; | ||
395 | inode->i_ctime.tv_nsec = csecs * 10000000; | ||
396 | inode->i_atime.tv_sec = | ||
397 | date_dos2unix(0, le16_to_cpu(de->adate), | ||
398 | sbi->options.tz_utc); | ||
399 | inode->i_atime.tv_nsec = 0; | ||
400 | } else | 392 | } else |
401 | inode->i_ctime = inode->i_atime = inode->i_mtime; | 393 | inode->i_ctime = inode->i_atime = inode->i_mtime; |
402 | 394 | ||
@@ -443,13 +435,8 @@ static void fat_delete_inode(struct inode *inode) | |||
443 | 435 | ||
444 | static void fat_clear_inode(struct inode *inode) | 436 | static void fat_clear_inode(struct inode *inode) |
445 | { | 437 | { |
446 | struct super_block *sb = inode->i_sb; | ||
447 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||
448 | |||
449 | spin_lock(&sbi->inode_hash_lock); | ||
450 | fat_cache_inval_inode(inode); | 438 | fat_cache_inval_inode(inode); |
451 | hlist_del_init(&MSDOS_I(inode)->i_fat_hash); | 439 | fat_detach(inode); |
452 | spin_unlock(&sbi->inode_hash_lock); | ||
453 | } | 440 | } |
454 | 441 | ||
455 | static void fat_write_super(struct super_block *sb) | 442 | static void fat_write_super(struct super_block *sb) |
@@ -555,6 +542,20 @@ static int fat_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
555 | return 0; | 542 | return 0; |
556 | } | 543 | } |
557 | 544 | ||
545 | static inline loff_t fat_i_pos_read(struct msdos_sb_info *sbi, | ||
546 | struct inode *inode) | ||
547 | { | ||
548 | loff_t i_pos; | ||
549 | #if BITS_PER_LONG == 32 | ||
550 | spin_lock(&sbi->inode_hash_lock); | ||
551 | #endif | ||
552 | i_pos = MSDOS_I(inode)->i_pos; | ||
553 | #if BITS_PER_LONG == 32 | ||
554 | spin_unlock(&sbi->inode_hash_lock); | ||
555 | #endif | ||
556 | return i_pos; | ||
557 | } | ||
558 | |||
558 | static int fat_write_inode(struct inode *inode, int wait) | 559 | static int fat_write_inode(struct inode *inode, int wait) |
559 | { | 560 | { |
560 | struct super_block *sb = inode->i_sb; | 561 | struct super_block *sb = inode->i_sb; |
@@ -564,9 +565,12 @@ static int fat_write_inode(struct inode *inode, int wait) | |||
564 | loff_t i_pos; | 565 | loff_t i_pos; |
565 | int err; | 566 | int err; |
566 | 567 | ||
568 | if (inode->i_ino == MSDOS_ROOT_INO) | ||
569 | return 0; | ||
570 | |||
567 | retry: | 571 | retry: |
568 | i_pos = MSDOS_I(inode)->i_pos; | 572 | i_pos = fat_i_pos_read(sbi, inode); |
569 | if (inode->i_ino == MSDOS_ROOT_INO || !i_pos) | 573 | if (!i_pos) |
570 | return 0; | 574 | return 0; |
571 | 575 | ||
572 | bh = sb_bread(sb, i_pos >> sbi->dir_per_block_bits); | 576 | bh = sb_bread(sb, i_pos >> sbi->dir_per_block_bits); |
@@ -588,19 +592,17 @@ retry: | |||
588 | raw_entry->size = 0; | 592 | raw_entry->size = 0; |
589 | else | 593 | else |
590 | raw_entry->size = cpu_to_le32(inode->i_size); | 594 | raw_entry->size = cpu_to_le32(inode->i_size); |
591 | raw_entry->attr = fat_attr(inode); | 595 | raw_entry->attr = fat_make_attrs(inode); |
592 | raw_entry->start = cpu_to_le16(MSDOS_I(inode)->i_logstart); | 596 | raw_entry->start = cpu_to_le16(MSDOS_I(inode)->i_logstart); |
593 | raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16); | 597 | raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16); |
594 | fat_date_unix2dos(inode->i_mtime.tv_sec, &raw_entry->time, | 598 | fat_time_unix2fat(sbi, &inode->i_mtime, &raw_entry->time, |
595 | &raw_entry->date, sbi->options.tz_utc); | 599 | &raw_entry->date, NULL); |
596 | if (sbi->options.isvfat) { | 600 | if (sbi->options.isvfat) { |
597 | __le16 atime; | 601 | __le16 atime; |
598 | fat_date_unix2dos(inode->i_ctime.tv_sec, &raw_entry->ctime, | 602 | fat_time_unix2fat(sbi, &inode->i_ctime, &raw_entry->ctime, |
599 | &raw_entry->cdate, sbi->options.tz_utc); | 603 | &raw_entry->cdate, &raw_entry->ctime_cs); |
600 | fat_date_unix2dos(inode->i_atime.tv_sec, &atime, | 604 | fat_time_unix2fat(sbi, &inode->i_atime, &atime, |
601 | &raw_entry->adate, sbi->options.tz_utc); | 605 | &raw_entry->adate, NULL); |
602 | raw_entry->ctime_cs = (inode->i_ctime.tv_sec & 1) * 100 + | ||
603 | inode->i_ctime.tv_nsec / 10000000; | ||
604 | } | 606 | } |
605 | spin_unlock(&sbi->inode_hash_lock); | 607 | spin_unlock(&sbi->inode_hash_lock); |
606 | mark_buffer_dirty(bh); | 608 | mark_buffer_dirty(bh); |
@@ -819,8 +821,10 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
819 | seq_puts(m, ",uni_xlate"); | 821 | seq_puts(m, ",uni_xlate"); |
820 | if (!opts->numtail) | 822 | if (!opts->numtail) |
821 | seq_puts(m, ",nonumtail"); | 823 | seq_puts(m, ",nonumtail"); |
824 | if (opts->rodir) | ||
825 | seq_puts(m, ",rodir"); | ||
822 | } | 826 | } |
823 | if (sbi->options.flush) | 827 | if (opts->flush) |
824 | seq_puts(m, ",flush"); | 828 | seq_puts(m, ",flush"); |
825 | if (opts->tz_utc) | 829 | if (opts->tz_utc) |
826 | seq_puts(m, ",tz=UTC"); | 830 | seq_puts(m, ",tz=UTC"); |
@@ -836,7 +840,7 @@ enum { | |||
836 | Opt_charset, Opt_shortname_lower, Opt_shortname_win95, | 840 | Opt_charset, Opt_shortname_lower, Opt_shortname_win95, |
837 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, | 841 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, |
838 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, | 842 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, |
839 | Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_err, | 843 | Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err, |
840 | }; | 844 | }; |
841 | 845 | ||
842 | static const match_table_t fat_tokens = { | 846 | static const match_table_t fat_tokens = { |
@@ -908,6 +912,7 @@ static const match_table_t vfat_tokens = { | |||
908 | {Opt_nonumtail_yes, "nonumtail=yes"}, | 912 | {Opt_nonumtail_yes, "nonumtail=yes"}, |
909 | {Opt_nonumtail_yes, "nonumtail=true"}, | 913 | {Opt_nonumtail_yes, "nonumtail=true"}, |
910 | {Opt_nonumtail_yes, "nonumtail"}, | 914 | {Opt_nonumtail_yes, "nonumtail"}, |
915 | {Opt_rodir, "rodir"}, | ||
911 | {Opt_err, NULL} | 916 | {Opt_err, NULL} |
912 | }; | 917 | }; |
913 | 918 | ||
@@ -927,10 +932,13 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, | |||
927 | opts->allow_utime = -1; | 932 | opts->allow_utime = -1; |
928 | opts->codepage = fat_default_codepage; | 933 | opts->codepage = fat_default_codepage; |
929 | opts->iocharset = fat_default_iocharset; | 934 | opts->iocharset = fat_default_iocharset; |
930 | if (is_vfat) | 935 | if (is_vfat) { |
931 | opts->shortname = VFAT_SFN_DISPLAY_LOWER|VFAT_SFN_CREATE_WIN95; | 936 | opts->shortname = VFAT_SFN_DISPLAY_LOWER|VFAT_SFN_CREATE_WIN95; |
932 | else | 937 | opts->rodir = 0; |
938 | } else { | ||
933 | opts->shortname = 0; | 939 | opts->shortname = 0; |
940 | opts->rodir = 1; | ||
941 | } | ||
934 | opts->name_check = 'n'; | 942 | opts->name_check = 'n'; |
935 | opts->quiet = opts->showexec = opts->sys_immutable = opts->dotsOK = 0; | 943 | opts->quiet = opts->showexec = opts->sys_immutable = opts->dotsOK = 0; |
936 | opts->utf8 = opts->unicode_xlate = 0; | 944 | opts->utf8 = opts->unicode_xlate = 0; |
@@ -1081,6 +1089,9 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, | |||
1081 | case Opt_nonumtail_yes: /* empty or 1 or yes or true */ | 1089 | case Opt_nonumtail_yes: /* empty or 1 or yes or true */ |
1082 | opts->numtail = 0; /* negated option */ | 1090 | opts->numtail = 0; /* negated option */ |
1083 | break; | 1091 | break; |
1092 | case Opt_rodir: | ||
1093 | opts->rodir = 1; | ||
1094 | break; | ||
1084 | 1095 | ||
1085 | /* obsolete mount options */ | 1096 | /* obsolete mount options */ |
1086 | case Opt_obsolate: | 1097 | case Opt_obsolate: |
@@ -1126,7 +1137,7 @@ static int fat_read_root(struct inode *inode) | |||
1126 | inode->i_gid = sbi->options.fs_gid; | 1137 | inode->i_gid = sbi->options.fs_gid; |
1127 | inode->i_version++; | 1138 | inode->i_version++; |
1128 | inode->i_generation = 0; | 1139 | inode->i_generation = 0; |
1129 | inode->i_mode = (S_IRWXUGO & ~sbi->options.fs_dmask) | S_IFDIR; | 1140 | inode->i_mode = fat_make_mode(sbi, ATTR_DIR, S_IRWXUGO); |
1130 | inode->i_op = sbi->dir_ops; | 1141 | inode->i_op = sbi->dir_ops; |
1131 | inode->i_fop = &fat_dir_operations; | 1142 | inode->i_fop = &fat_dir_operations; |
1132 | if (sbi->fat_bits == 32) { | 1143 | if (sbi->fat_bits == 32) { |
@@ -1143,7 +1154,7 @@ static int fat_read_root(struct inode *inode) | |||
1143 | MSDOS_I(inode)->i_logstart = 0; | 1154 | MSDOS_I(inode)->i_logstart = 0; |
1144 | MSDOS_I(inode)->mmu_private = inode->i_size; | 1155 | MSDOS_I(inode)->mmu_private = inode->i_size; |
1145 | 1156 | ||
1146 | MSDOS_I(inode)->i_attrs = ATTR_NONE; | 1157 | fat_save_attrs(inode, ATTR_DIR); |
1147 | inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = 0; | 1158 | inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = 0; |
1148 | inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = 0; | 1159 | inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = 0; |
1149 | inode->i_nlink = fat_subdirs(inode)+2; | 1160 | inode->i_nlink = fat_subdirs(inode)+2; |
diff --git a/fs/fat/misc.c b/fs/fat/misc.c index 79fb98ad36d4..ac39ebcc1496 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c | |||
@@ -8,8 +8,8 @@ | |||
8 | 8 | ||
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
10 | #include <linux/fs.h> | 10 | #include <linux/fs.h> |
11 | #include <linux/msdos_fs.h> | ||
12 | #include <linux/buffer_head.h> | 11 | #include <linux/buffer_head.h> |
12 | #include "fat.h" | ||
13 | 13 | ||
14 | /* | 14 | /* |
15 | * fat_fs_panic reports a severe file system problem and sets the file system | 15 | * fat_fs_panic reports a severe file system problem and sets the file system |
@@ -124,8 +124,9 @@ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster) | |||
124 | mark_inode_dirty(inode); | 124 | mark_inode_dirty(inode); |
125 | } | 125 | } |
126 | if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) { | 126 | if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) { |
127 | fat_fs_panic(sb, "clusters badly computed (%d != %lu)", | 127 | fat_fs_panic(sb, "clusters badly computed (%d != %llu)", |
128 | new_fclus, inode->i_blocks >> (sbi->cluster_bits - 9)); | 128 | new_fclus, |
129 | (llu)(inode->i_blocks >> (sbi->cluster_bits - 9))); | ||
129 | fat_cache_inval_inode(inode); | 130 | fat_cache_inval_inode(inode); |
130 | } | 131 | } |
131 | inode->i_blocks += nr_cluster << (sbi->cluster_bits - 9); | 132 | inode->i_blocks += nr_cluster << (sbi->cluster_bits - 9); |
@@ -135,65 +136,131 @@ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster) | |||
135 | 136 | ||
136 | extern struct timezone sys_tz; | 137 | extern struct timezone sys_tz; |
137 | 138 | ||
139 | /* | ||
140 | * The epoch of FAT timestamp is 1980. | ||
141 | * : bits : value | ||
142 | * date: 0 - 4: day (1 - 31) | ||
143 | * date: 5 - 8: month (1 - 12) | ||
144 | * date: 9 - 15: year (0 - 127) from 1980 | ||
145 | * time: 0 - 4: sec (0 - 29) 2sec counts | ||
146 | * time: 5 - 10: min (0 - 59) | ||
147 | * time: 11 - 15: hour (0 - 23) | ||
148 | */ | ||
149 | #define SECS_PER_MIN 60 | ||
150 | #define SECS_PER_HOUR (60 * 60) | ||
151 | #define SECS_PER_DAY (SECS_PER_HOUR * 24) | ||
152 | #define UNIX_SECS_1980 315532800L | ||
153 | #if BITS_PER_LONG == 64 | ||
154 | #define UNIX_SECS_2108 4354819200L | ||
155 | #endif | ||
156 | /* days between 1.1.70 and 1.1.80 (2 leap days) */ | ||
157 | #define DAYS_DELTA (365 * 10 + 2) | ||
158 | /* 120 (2100 - 1980) isn't leap year */ | ||
159 | #define YEAR_2100 120 | ||
160 | #define IS_LEAP_YEAR(y) (!((y) & 3) && (y) != YEAR_2100) | ||
161 | |||
138 | /* Linear day numbers of the respective 1sts in non-leap years. */ | 162 | /* Linear day numbers of the respective 1sts in non-leap years. */ |
139 | static int day_n[] = { | 163 | static time_t days_in_year[] = { |
140 | /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ | 164 | /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ |
141 | 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0 | 165 | 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, |
142 | }; | 166 | }; |
143 | 167 | ||
144 | /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ | 168 | /* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */ |
145 | int date_dos2unix(unsigned short time, unsigned short date, int tz_utc) | 169 | void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec *ts, |
170 | __le16 __time, __le16 __date, u8 time_cs) | ||
146 | { | 171 | { |
147 | int month, year, secs; | 172 | u16 time = le16_to_cpu(__time), date = le16_to_cpu(__date); |
173 | time_t second, day, leap_day, month, year; | ||
148 | 174 | ||
149 | /* | 175 | year = date >> 9; |
150 | * first subtract and mask after that... Otherwise, if | 176 | month = max(1, (date >> 5) & 0xf); |
151 | * date == 0, bad things happen | 177 | day = max(1, date & 0x1f) - 1; |
152 | */ | 178 | |
153 | month = ((date >> 5) - 1) & 15; | 179 | leap_day = (year + 3) / 4; |
154 | year = date >> 9; | 180 | if (year > YEAR_2100) /* 2100 isn't leap year */ |
155 | secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400* | 181 | leap_day--; |
156 | ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 && | 182 | if (IS_LEAP_YEAR(year) && month > 2) |
157 | month < 2 ? 1 : 0)+3653); | 183 | leap_day++; |
158 | /* days since 1.1.70 plus 80's leap day */ | 184 | |
159 | if (!tz_utc) | 185 | second = (time & 0x1f) << 1; |
160 | secs += sys_tz.tz_minuteswest*60; | 186 | second += ((time >> 5) & 0x3f) * SECS_PER_MIN; |
161 | return secs; | 187 | second += (time >> 11) * SECS_PER_HOUR; |
188 | second += (year * 365 + leap_day | ||
189 | + days_in_year[month] + day | ||
190 | + DAYS_DELTA) * SECS_PER_DAY; | ||
191 | |||
192 | if (!sbi->options.tz_utc) | ||
193 | second += sys_tz.tz_minuteswest * SECS_PER_MIN; | ||
194 | |||
195 | if (time_cs) { | ||
196 | ts->tv_sec = second + (time_cs / 100); | ||
197 | ts->tv_nsec = (time_cs % 100) * 10000000; | ||
198 | } else { | ||
199 | ts->tv_sec = second; | ||
200 | ts->tv_nsec = 0; | ||
201 | } | ||
162 | } | 202 | } |
163 | 203 | ||
164 | /* Convert linear UNIX date to a MS-DOS time/date pair. */ | 204 | /* Convert linear UNIX date to a FAT time/date pair. */ |
165 | void fat_date_unix2dos(int unix_date, __le16 *time, __le16 *date, int tz_utc) | 205 | void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec *ts, |
206 | __le16 *time, __le16 *date, u8 *time_cs) | ||
166 | { | 207 | { |
167 | int day, year, nl_day, month; | 208 | time_t second = ts->tv_sec; |
209 | time_t day, leap_day, month, year; | ||
168 | 210 | ||
169 | if (!tz_utc) | 211 | if (!sbi->options.tz_utc) |
170 | unix_date -= sys_tz.tz_minuteswest*60; | 212 | second -= sys_tz.tz_minuteswest * SECS_PER_MIN; |
171 | 213 | ||
172 | /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ | 214 | /* Jan 1 GMT 00:00:00 1980. But what about another time zone? */ |
173 | if (unix_date < 315532800) | 215 | if (second < UNIX_SECS_1980) { |
174 | unix_date = 315532800; | 216 | *time = 0; |
175 | 217 | *date = cpu_to_le16((0 << 9) | (1 << 5) | 1); | |
176 | *time = cpu_to_le16((unix_date % 60)/2+(((unix_date/60) % 60) << 5)+ | 218 | if (time_cs) |
177 | (((unix_date/3600) % 24) << 11)); | 219 | *time_cs = 0; |
178 | day = unix_date/86400-3652; | 220 | return; |
179 | year = day/365; | 221 | } |
180 | if ((year+3)/4+365*year > day) | 222 | #if BITS_PER_LONG == 64 |
223 | if (second >= UNIX_SECS_2108) { | ||
224 | *time = cpu_to_le16((23 << 11) | (59 << 5) | 29); | ||
225 | *date = cpu_to_le16((127 << 9) | (12 << 5) | 31); | ||
226 | if (time_cs) | ||
227 | *time_cs = 199; | ||
228 | return; | ||
229 | } | ||
230 | #endif | ||
231 | |||
232 | day = second / SECS_PER_DAY - DAYS_DELTA; | ||
233 | year = day / 365; | ||
234 | leap_day = (year + 3) / 4; | ||
235 | if (year > YEAR_2100) /* 2100 isn't leap year */ | ||
236 | leap_day--; | ||
237 | if (year * 365 + leap_day > day) | ||
181 | year--; | 238 | year--; |
182 | day -= (year+3)/4+365*year; | 239 | leap_day = (year + 3) / 4; |
183 | if (day == 59 && !(year & 3)) { | 240 | if (year > YEAR_2100) /* 2100 isn't leap year */ |
184 | nl_day = day; | 241 | leap_day--; |
242 | day -= year * 365 + leap_day; | ||
243 | |||
244 | if (IS_LEAP_YEAR(year) && day == days_in_year[3]) { | ||
185 | month = 2; | 245 | month = 2; |
186 | } else { | 246 | } else { |
187 | nl_day = (year & 3) || day <= 59 ? day : day-1; | 247 | if (IS_LEAP_YEAR(year) && day > days_in_year[3]) |
188 | for (month = 0; month < 12; month++) { | 248 | day--; |
189 | if (day_n[month] > nl_day) | 249 | for (month = 1; month < 12; month++) { |
250 | if (days_in_year[month + 1] > day) | ||
190 | break; | 251 | break; |
191 | } | 252 | } |
192 | } | 253 | } |
193 | *date = cpu_to_le16(nl_day-day_n[month-1]+1+(month << 5)+(year << 9)); | 254 | day -= days_in_year[month]; |
194 | } | ||
195 | 255 | ||
196 | EXPORT_SYMBOL_GPL(fat_date_unix2dos); | 256 | *time = cpu_to_le16(((second / SECS_PER_HOUR) % 24) << 11 |
257 | | ((second / SECS_PER_MIN) % 60) << 5 | ||
258 | | (second % SECS_PER_MIN) >> 1); | ||
259 | *date = cpu_to_le16((year << 9) | (month << 5) | (day + 1)); | ||
260 | if (time_cs) | ||
261 | *time_cs = (ts->tv_sec & 1) * 100 + ts->tv_nsec / 10000000; | ||
262 | } | ||
263 | EXPORT_SYMBOL_GPL(fat_time_unix2fat); | ||
197 | 264 | ||
198 | int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs) | 265 | int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs) |
199 | { | 266 | { |
diff --git a/fs/msdos/namei.c b/fs/fat/namei_msdos.c index e844b9809d27..7ba03a4acbe0 100644 --- a/fs/msdos/namei.c +++ b/fs/fat/namei_msdos.c | |||
@@ -9,8 +9,8 @@ | |||
9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
10 | #include <linux/time.h> | 10 | #include <linux/time.h> |
11 | #include <linux/buffer_head.h> | 11 | #include <linux/buffer_head.h> |
12 | #include <linux/msdos_fs.h> | ||
13 | #include <linux/smp_lock.h> | 12 | #include <linux/smp_lock.h> |
13 | #include "fat.h" | ||
14 | 14 | ||
15 | /* Characters that are undesirable in an MS-DOS file name */ | 15 | /* Characters that are undesirable in an MS-DOS file name */ |
16 | static unsigned char bad_chars[] = "*?<>|\""; | 16 | static unsigned char bad_chars[] = "*?<>|\""; |
@@ -203,33 +203,37 @@ static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry, | |||
203 | { | 203 | { |
204 | struct super_block *sb = dir->i_sb; | 204 | struct super_block *sb = dir->i_sb; |
205 | struct fat_slot_info sinfo; | 205 | struct fat_slot_info sinfo; |
206 | struct inode *inode = NULL; | 206 | struct inode *inode; |
207 | int res; | 207 | int err; |
208 | |||
209 | dentry->d_op = &msdos_dentry_operations; | ||
210 | 208 | ||
211 | lock_super(sb); | 209 | lock_super(sb); |
212 | res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo); | 210 | |
213 | if (res == -ENOENT) | 211 | err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo); |
214 | goto add; | 212 | if (err) { |
215 | if (res < 0) | 213 | if (err == -ENOENT) { |
216 | goto out; | 214 | inode = NULL; |
215 | goto out; | ||
216 | } | ||
217 | goto error; | ||
218 | } | ||
219 | |||
217 | inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos); | 220 | inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos); |
218 | brelse(sinfo.bh); | 221 | brelse(sinfo.bh); |
219 | if (IS_ERR(inode)) { | 222 | if (IS_ERR(inode)) { |
220 | res = PTR_ERR(inode); | 223 | err = PTR_ERR(inode); |
221 | goto out; | 224 | goto error; |
222 | } | 225 | } |
223 | add: | 226 | out: |
224 | res = 0; | 227 | unlock_super(sb); |
228 | dentry->d_op = &msdos_dentry_operations; | ||
225 | dentry = d_splice_alias(inode, dentry); | 229 | dentry = d_splice_alias(inode, dentry); |
226 | if (dentry) | 230 | if (dentry) |
227 | dentry->d_op = &msdos_dentry_operations; | 231 | dentry->d_op = &msdos_dentry_operations; |
228 | out: | 232 | return dentry; |
233 | |||
234 | error: | ||
229 | unlock_super(sb); | 235 | unlock_super(sb); |
230 | if (!res) | 236 | return ERR_PTR(err); |
231 | return dentry; | ||
232 | return ERR_PTR(res); | ||
233 | } | 237 | } |
234 | 238 | ||
235 | /***** Creates a directory entry (name is already formatted). */ | 239 | /***** Creates a directory entry (name is already formatted). */ |
@@ -247,7 +251,7 @@ static int msdos_add_entry(struct inode *dir, const unsigned char *name, | |||
247 | if (is_hid) | 251 | if (is_hid) |
248 | de.attr |= ATTR_HIDDEN; | 252 | de.attr |= ATTR_HIDDEN; |
249 | de.lcase = 0; | 253 | de.lcase = 0; |
250 | fat_date_unix2dos(ts->tv_sec, &time, &date, sbi->options.tz_utc); | 254 | fat_time_unix2fat(sbi, ts, &time, &date, NULL); |
251 | de.cdate = de.adate = 0; | 255 | de.cdate = de.adate = 0; |
252 | de.ctime = 0; | 256 | de.ctime = 0; |
253 | de.ctime_cs = 0; | 257 | de.ctime_cs = 0; |
diff --git a/fs/vfat/namei.c b/fs/fat/namei_vfat.c index 155c10b4adbd..bf326d4356a3 100644 --- a/fs/vfat/namei.c +++ b/fs/fat/namei_vfat.c | |||
@@ -16,36 +16,75 @@ | |||
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | |||
20 | #include <linux/jiffies.h> | 19 | #include <linux/jiffies.h> |
21 | #include <linux/msdos_fs.h> | ||
22 | #include <linux/ctype.h> | 20 | #include <linux/ctype.h> |
23 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
24 | #include <linux/smp_lock.h> | 22 | #include <linux/smp_lock.h> |
25 | #include <linux/buffer_head.h> | 23 | #include <linux/buffer_head.h> |
26 | #include <linux/namei.h> | 24 | #include <linux/namei.h> |
25 | #include "fat.h" | ||
27 | 26 | ||
28 | static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd) | 27 | /* |
28 | * If new entry was created in the parent, it could create the 8.3 | ||
29 | * alias (the shortname of logname). So, the parent may have the | ||
30 | * negative-dentry which matches the created 8.3 alias. | ||
31 | * | ||
32 | * If it happened, the negative dentry isn't actually negative | ||
33 | * anymore. So, drop it. | ||
34 | */ | ||
35 | static int vfat_revalidate_shortname(struct dentry *dentry) | ||
29 | { | 36 | { |
30 | int ret = 1; | 37 | int ret = 1; |
31 | 38 | spin_lock(&dentry->d_lock); | |
32 | if (!dentry->d_inode && | 39 | if (dentry->d_time != dentry->d_parent->d_inode->i_version) |
33 | nd && !(nd->flags & LOOKUP_CONTINUE) && (nd->flags & LOOKUP_CREATE)) | ||
34 | /* | ||
35 | * negative dentry is dropped, in order to make sure | ||
36 | * to use the name which a user desires if this is | ||
37 | * create path. | ||
38 | */ | ||
39 | ret = 0; | 40 | ret = 0; |
40 | else { | 41 | spin_unlock(&dentry->d_lock); |
41 | spin_lock(&dentry->d_lock); | ||
42 | if (dentry->d_time != dentry->d_parent->d_inode->i_version) | ||
43 | ret = 0; | ||
44 | spin_unlock(&dentry->d_lock); | ||
45 | } | ||
46 | return ret; | 42 | return ret; |
47 | } | 43 | } |
48 | 44 | ||
45 | static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd) | ||
46 | { | ||
47 | /* This is not negative dentry. Always valid. */ | ||
48 | if (dentry->d_inode) | ||
49 | return 1; | ||
50 | return vfat_revalidate_shortname(dentry); | ||
51 | } | ||
52 | |||
53 | static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd) | ||
54 | { | ||
55 | /* | ||
56 | * This is not negative dentry. Always valid. | ||
57 | * | ||
58 | * Note, rename() to existing directory entry will have ->d_inode, | ||
59 | * and will use existing name which isn't specified name by user. | ||
60 | * | ||
61 | * We may be able to drop this positive dentry here. But dropping | ||
62 | * positive dentry isn't good idea. So it's unsupported like | ||
63 | * rename("filename", "FILENAME") for now. | ||
64 | */ | ||
65 | if (dentry->d_inode) | ||
66 | return 1; | ||
67 | |||
68 | /* | ||
69 | * This may be nfsd (or something), anyway, we can't see the | ||
70 | * intent of this. So, since this can be for creation, drop it. | ||
71 | */ | ||
72 | if (!nd) | ||
73 | return 0; | ||
74 | |||
75 | /* | ||
76 | * Drop the negative dentry, in order to make sure to use the | ||
77 | * case sensitive name which is specified by user if this is | ||
78 | * for creation. | ||
79 | */ | ||
80 | if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) { | ||
81 | if (nd->flags & LOOKUP_CREATE) | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | return vfat_revalidate_shortname(dentry); | ||
86 | } | ||
87 | |||
49 | /* returns the length of a struct qstr, ignoring trailing dots */ | 88 | /* returns the length of a struct qstr, ignoring trailing dots */ |
50 | static unsigned int vfat_striptail_len(struct qstr *qstr) | 89 | static unsigned int vfat_striptail_len(struct qstr *qstr) |
51 | { | 90 | { |
@@ -127,25 +166,16 @@ static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b) | |||
127 | return 1; | 166 | return 1; |
128 | } | 167 | } |
129 | 168 | ||
130 | static struct dentry_operations vfat_dentry_ops[4] = { | 169 | static struct dentry_operations vfat_ci_dentry_ops = { |
131 | { | 170 | .d_revalidate = vfat_revalidate_ci, |
132 | .d_hash = vfat_hashi, | 171 | .d_hash = vfat_hashi, |
133 | .d_compare = vfat_cmpi, | 172 | .d_compare = vfat_cmpi, |
134 | }, | 173 | }; |
135 | { | 174 | |
136 | .d_revalidate = vfat_revalidate, | 175 | static struct dentry_operations vfat_dentry_ops = { |
137 | .d_hash = vfat_hashi, | 176 | .d_revalidate = vfat_revalidate, |
138 | .d_compare = vfat_cmpi, | 177 | .d_hash = vfat_hash, |
139 | }, | 178 | .d_compare = vfat_cmp, |
140 | { | ||
141 | .d_hash = vfat_hash, | ||
142 | .d_compare = vfat_cmp, | ||
143 | }, | ||
144 | { | ||
145 | .d_revalidate = vfat_revalidate, | ||
146 | .d_hash = vfat_hash, | ||
147 | .d_compare = vfat_cmp, | ||
148 | } | ||
149 | }; | 179 | }; |
150 | 180 | ||
151 | /* Characters that are undesirable in an MS-DOS file name */ | 181 | /* Characters that are undesirable in an MS-DOS file name */ |
@@ -569,6 +599,7 @@ static int vfat_build_slots(struct inode *dir, const unsigned char *name, | |||
569 | unsigned char msdos_name[MSDOS_NAME]; | 599 | unsigned char msdos_name[MSDOS_NAME]; |
570 | wchar_t *uname; | 600 | wchar_t *uname; |
571 | __le16 time, date; | 601 | __le16 time, date; |
602 | u8 time_cs; | ||
572 | int err, ulen, usize, i; | 603 | int err, ulen, usize, i; |
573 | loff_t offset; | 604 | loff_t offset; |
574 | 605 | ||
@@ -621,10 +652,10 @@ shortname: | |||
621 | memcpy(de->name, msdos_name, MSDOS_NAME); | 652 | memcpy(de->name, msdos_name, MSDOS_NAME); |
622 | de->attr = is_dir ? ATTR_DIR : ATTR_ARCH; | 653 | de->attr = is_dir ? ATTR_DIR : ATTR_ARCH; |
623 | de->lcase = lcase; | 654 | de->lcase = lcase; |
624 | fat_date_unix2dos(ts->tv_sec, &time, &date, sbi->options.tz_utc); | 655 | fat_time_unix2fat(sbi, ts, &time, &date, &time_cs); |
625 | de->time = de->ctime = time; | 656 | de->time = de->ctime = time; |
626 | de->date = de->cdate = de->adate = date; | 657 | de->date = de->cdate = de->adate = date; |
627 | de->ctime_cs = 0; | 658 | de->ctime_cs = time_cs; |
628 | de->start = cpu_to_le16(cluster); | 659 | de->start = cpu_to_le16(cluster); |
629 | de->starthi = cpu_to_le16(cluster >> 16); | 660 | de->starthi = cpu_to_le16(cluster >> 16); |
630 | de->size = 0; | 661 | de->size = 0; |
@@ -683,46 +714,58 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry, | |||
683 | { | 714 | { |
684 | struct super_block *sb = dir->i_sb; | 715 | struct super_block *sb = dir->i_sb; |
685 | struct fat_slot_info sinfo; | 716 | struct fat_slot_info sinfo; |
686 | struct inode *inode = NULL; | 717 | struct inode *inode; |
687 | struct dentry *alias; | 718 | struct dentry *alias; |
688 | int err, table; | 719 | int err; |
689 | 720 | ||
690 | lock_super(sb); | 721 | lock_super(sb); |
691 | table = (MSDOS_SB(sb)->options.name_check == 's') ? 2 : 0; | ||
692 | dentry->d_op = &vfat_dentry_ops[table]; | ||
693 | 722 | ||
694 | err = vfat_find(dir, &dentry->d_name, &sinfo); | 723 | err = vfat_find(dir, &dentry->d_name, &sinfo); |
695 | if (err) { | 724 | if (err) { |
696 | table++; | 725 | if (err == -ENOENT) { |
726 | inode = NULL; | ||
727 | goto out; | ||
728 | } | ||
697 | goto error; | 729 | goto error; |
698 | } | 730 | } |
731 | |||
699 | inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos); | 732 | inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos); |
700 | brelse(sinfo.bh); | 733 | brelse(sinfo.bh); |
701 | if (IS_ERR(inode)) { | 734 | if (IS_ERR(inode)) { |
702 | unlock_super(sb); | 735 | err = PTR_ERR(inode); |
703 | return ERR_CAST(inode); | 736 | goto error; |
704 | } | 737 | } |
705 | alias = d_find_alias(inode); | ||
706 | if (alias) { | ||
707 | if (d_invalidate(alias) == 0) | ||
708 | dput(alias); | ||
709 | else { | ||
710 | iput(inode); | ||
711 | unlock_super(sb); | ||
712 | return alias; | ||
713 | } | ||
714 | 738 | ||
739 | alias = d_find_alias(inode); | ||
740 | if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) { | ||
741 | /* | ||
742 | * This inode has non DCACHE_DISCONNECTED dentry. This | ||
743 | * means, the user did ->lookup() by an another name | ||
744 | * (longname vs 8.3 alias of it) in past. | ||
745 | * | ||
746 | * Switch to new one for reason of locality if possible. | ||
747 | */ | ||
748 | BUG_ON(d_unhashed(alias)); | ||
749 | if (!S_ISDIR(inode->i_mode)) | ||
750 | d_move(alias, dentry); | ||
751 | iput(inode); | ||
752 | unlock_super(sb); | ||
753 | return alias; | ||
715 | } | 754 | } |
716 | error: | 755 | out: |
717 | unlock_super(sb); | 756 | unlock_super(sb); |
718 | dentry->d_op = &vfat_dentry_ops[table]; | 757 | dentry->d_op = sb->s_root->d_op; |
719 | dentry->d_time = dentry->d_parent->d_inode->i_version; | 758 | dentry->d_time = dentry->d_parent->d_inode->i_version; |
720 | dentry = d_splice_alias(inode, dentry); | 759 | dentry = d_splice_alias(inode, dentry); |
721 | if (dentry) { | 760 | if (dentry) { |
722 | dentry->d_op = &vfat_dentry_ops[table]; | 761 | dentry->d_op = sb->s_root->d_op; |
723 | dentry->d_time = dentry->d_parent->d_inode->i_version; | 762 | dentry->d_time = dentry->d_parent->d_inode->i_version; |
724 | } | 763 | } |
725 | return dentry; | 764 | return dentry; |
765 | |||
766 | error: | ||
767 | unlock_super(sb); | ||
768 | return ERR_PTR(err); | ||
726 | } | 769 | } |
727 | 770 | ||
728 | static int vfat_create(struct inode *dir, struct dentry *dentry, int mode, | 771 | static int vfat_create(struct inode *dir, struct dentry *dentry, int mode, |
@@ -1014,9 +1057,9 @@ static int vfat_fill_super(struct super_block *sb, void *data, int silent) | |||
1014 | return res; | 1057 | return res; |
1015 | 1058 | ||
1016 | if (MSDOS_SB(sb)->options.name_check != 's') | 1059 | if (MSDOS_SB(sb)->options.name_check != 's') |
1017 | sb->s_root->d_op = &vfat_dentry_ops[0]; | 1060 | sb->s_root->d_op = &vfat_ci_dentry_ops; |
1018 | else | 1061 | else |
1019 | sb->s_root->d_op = &vfat_dentry_ops[2]; | 1062 | sb->s_root->d_op = &vfat_dentry_ops; |
1020 | 1063 | ||
1021 | return 0; | 1064 | return 0; |
1022 | } | 1065 | } |
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 8adebd3e43c6..3cceef4ad2b7 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c | |||
@@ -85,15 +85,15 @@ static int jffs2_garbage_collect_thread(void *_c) | |||
85 | for (;;) { | 85 | for (;;) { |
86 | allow_signal(SIGHUP); | 86 | allow_signal(SIGHUP); |
87 | again: | 87 | again: |
88 | spin_lock(&c->erase_completion_lock); | ||
88 | if (!jffs2_thread_should_wake(c)) { | 89 | if (!jffs2_thread_should_wake(c)) { |
89 | set_current_state (TASK_INTERRUPTIBLE); | 90 | set_current_state (TASK_INTERRUPTIBLE); |
91 | spin_unlock(&c->erase_completion_lock); | ||
90 | D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread sleeping...\n")); | 92 | D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread sleeping...\n")); |
91 | /* Yes, there's a race here; we checked jffs2_thread_should_wake() | ||
92 | before setting current->state to TASK_INTERRUPTIBLE. But it doesn't | ||
93 | matter - We don't care if we miss a wakeup, because the GC thread | ||
94 | is only an optimisation anyway. */ | ||
95 | schedule(); | 93 | schedule(); |
96 | } | 94 | } else |
95 | spin_unlock(&c->erase_completion_lock); | ||
96 | |||
97 | 97 | ||
98 | /* This thread is purely an optimisation. But if it runs when | 98 | /* This thread is purely an optimisation. But if it runs when |
99 | other things could be running, it actually makes things a | 99 | other things could be running, it actually makes things a |
diff --git a/fs/jffs2/compr_lzo.c b/fs/jffs2/compr_lzo.c index 47b045797e42..90cb60d09787 100644 --- a/fs/jffs2/compr_lzo.c +++ b/fs/jffs2/compr_lzo.c | |||
@@ -19,7 +19,7 @@ | |||
19 | 19 | ||
20 | static void *lzo_mem; | 20 | static void *lzo_mem; |
21 | static void *lzo_compress_buf; | 21 | static void *lzo_compress_buf; |
22 | static DEFINE_MUTEX(deflate_mutex); | 22 | static DEFINE_MUTEX(deflate_mutex); /* for lzo_mem and lzo_compress_buf */ |
23 | 23 | ||
24 | static void free_workspace(void) | 24 | static void free_workspace(void) |
25 | { | 25 | { |
@@ -49,18 +49,21 @@ static int jffs2_lzo_compress(unsigned char *data_in, unsigned char *cpage_out, | |||
49 | 49 | ||
50 | mutex_lock(&deflate_mutex); | 50 | mutex_lock(&deflate_mutex); |
51 | ret = lzo1x_1_compress(data_in, *sourcelen, lzo_compress_buf, &compress_size, lzo_mem); | 51 | ret = lzo1x_1_compress(data_in, *sourcelen, lzo_compress_buf, &compress_size, lzo_mem); |
52 | mutex_unlock(&deflate_mutex); | ||
53 | |||
54 | if (ret != LZO_E_OK) | 52 | if (ret != LZO_E_OK) |
55 | return -1; | 53 | goto fail; |
56 | 54 | ||
57 | if (compress_size > *dstlen) | 55 | if (compress_size > *dstlen) |
58 | return -1; | 56 | goto fail; |
59 | 57 | ||
60 | memcpy(cpage_out, lzo_compress_buf, compress_size); | 58 | memcpy(cpage_out, lzo_compress_buf, compress_size); |
61 | *dstlen = compress_size; | 59 | mutex_unlock(&deflate_mutex); |
62 | 60 | ||
61 | *dstlen = compress_size; | ||
63 | return 0; | 62 | return 0; |
63 | |||
64 | fail: | ||
65 | mutex_unlock(&deflate_mutex); | ||
66 | return -1; | ||
64 | } | 67 | } |
65 | 68 | ||
66 | static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out, | 69 | static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out, |
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 0875b60b4bf7..21a052915aa9 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c | |||
@@ -261,9 +261,11 @@ static int jffs2_find_nextblock(struct jffs2_sb_info *c) | |||
261 | 261 | ||
262 | jffs2_sum_reset_collected(c->summary); /* reset collected summary */ | 262 | jffs2_sum_reset_collected(c->summary); /* reset collected summary */ |
263 | 263 | ||
264 | #ifdef CONFIG_JFFS2_FS_WRITEBUFFER | ||
264 | /* adjust write buffer offset, else we get a non contiguous write bug */ | 265 | /* adjust write buffer offset, else we get a non contiguous write bug */ |
265 | if (!(c->wbuf_ofs % c->sector_size) && !c->wbuf_len) | 266 | if (!(c->wbuf_ofs % c->sector_size) && !c->wbuf_len) |
266 | c->wbuf_ofs = 0xffffffff; | 267 | c->wbuf_ofs = 0xffffffff; |
268 | #endif | ||
267 | 269 | ||
268 | D1(printk(KERN_DEBUG "jffs2_find_nextblock(): new nextblock = 0x%08x\n", c->nextblock->offset)); | 270 | D1(printk(KERN_DEBUG "jffs2_find_nextblock(): new nextblock = 0x%08x\n", c->nextblock->offset)); |
269 | 271 | ||
diff --git a/fs/msdos/Makefile b/fs/msdos/Makefile deleted file mode 100644 index ea67646fcb95..000000000000 --- a/fs/msdos/Makefile +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | # | ||
2 | # Makefile for the Linux msdos filesystem routines. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_MSDOS_FS) += msdos.o | ||
6 | |||
7 | msdos-y := namei.o | ||
diff --git a/fs/proc/uptime.c b/fs/proc/uptime.c index 0c10a0b3f146..df26aa88fa47 100644 --- a/fs/proc/uptime.c +++ b/fs/proc/uptime.c | |||
@@ -1,43 +1,45 @@ | |||
1 | #include <linux/fs.h> | ||
2 | #include <linux/init.h> | 1 | #include <linux/init.h> |
3 | #include <linux/proc_fs.h> | 2 | #include <linux/proc_fs.h> |
4 | #include <linux/sched.h> | 3 | #include <linux/sched.h> |
5 | #include <linux/seq_file.h> | ||
6 | #include <linux/time.h> | 4 | #include <linux/time.h> |
7 | #include <asm/cputime.h> | 5 | #include <asm/cputime.h> |
8 | 6 | ||
9 | static int uptime_proc_show(struct seq_file *m, void *v) | 7 | static int proc_calc_metrics(char *page, char **start, off_t off, |
8 | int count, int *eof, int len) | ||
9 | { | ||
10 | if (len <= off + count) | ||
11 | *eof = 1; | ||
12 | *start = page + off; | ||
13 | len -= off; | ||
14 | if (len > count) | ||
15 | len = count; | ||
16 | if (len < 0) | ||
17 | len = 0; | ||
18 | return len; | ||
19 | } | ||
20 | |||
21 | static int uptime_read_proc(char *page, char **start, off_t off, int count, | ||
22 | int *eof, void *data) | ||
10 | { | 23 | { |
11 | struct timespec uptime; | 24 | struct timespec uptime; |
12 | struct timespec idle; | 25 | struct timespec idle; |
26 | int len; | ||
13 | cputime_t idletime = cputime_add(init_task.utime, init_task.stime); | 27 | cputime_t idletime = cputime_add(init_task.utime, init_task.stime); |
14 | 28 | ||
15 | do_posix_clock_monotonic_gettime(&uptime); | 29 | do_posix_clock_monotonic_gettime(&uptime); |
16 | monotonic_to_bootbased(&uptime); | 30 | monotonic_to_bootbased(&uptime); |
17 | cputime_to_timespec(idletime, &idle); | 31 | cputime_to_timespec(idletime, &idle); |
18 | seq_printf(m, "%lu.%02lu %lu.%02lu\n", | 32 | len = sprintf(page, "%lu.%02lu %lu.%02lu\n", |
19 | (unsigned long) uptime.tv_sec, | 33 | (unsigned long) uptime.tv_sec, |
20 | (uptime.tv_nsec / (NSEC_PER_SEC / 100)), | 34 | (uptime.tv_nsec / (NSEC_PER_SEC / 100)), |
21 | (unsigned long) idle.tv_sec, | 35 | (unsigned long) idle.tv_sec, |
22 | (idle.tv_nsec / (NSEC_PER_SEC / 100))); | 36 | (idle.tv_nsec / (NSEC_PER_SEC / 100))); |
23 | return 0; | 37 | return proc_calc_metrics(page, start, off, count, eof, len); |
24 | } | 38 | } |
25 | 39 | ||
26 | static int uptime_proc_open(struct inode *inode, struct file *file) | ||
27 | { | ||
28 | return single_open(file, uptime_proc_show, NULL); | ||
29 | } | ||
30 | |||
31 | static const struct file_operations uptime_proc_fops = { | ||
32 | .open = uptime_proc_open, | ||
33 | .read = seq_read, | ||
34 | .llseek = seq_lseek, | ||
35 | .release = single_release, | ||
36 | }; | ||
37 | |||
38 | static int __init proc_uptime_init(void) | 40 | static int __init proc_uptime_init(void) |
39 | { | 41 | { |
40 | proc_create("uptime", 0, NULL, &uptime_proc_fops); | 42 | create_proc_read_entry("uptime", 0, NULL, uptime_read_proc, NULL); |
41 | return 0; | 43 | return 0; |
42 | } | 44 | } |
43 | module_init(proc_uptime_init); | 45 | module_init(proc_uptime_init); |
diff --git a/fs/vfat/Makefile b/fs/vfat/Makefile deleted file mode 100644 index 40f2798a4f08..000000000000 --- a/fs/vfat/Makefile +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | # | ||
2 | # Makefile for the linux vfat-filesystem routines. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_VFAT_FS) += vfat.o | ||
6 | |||
7 | vfat-y := namei.o | ||