diff options
Diffstat (limited to 'fs/fat')
-rw-r--r-- | fs/fat/fat.h | 8 | ||||
-rw-r--r-- | fs/fat/file.c | 5 | ||||
-rw-r--r-- | fs/fat/inode.c | 13 | ||||
-rw-r--r-- | fs/fat/nfs.c | 130 |
4 files changed, 136 insertions, 20 deletions
diff --git a/fs/fat/fat.h b/fs/fat/fat.h index 980c0346c168..c517fc066cf7 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h | |||
@@ -406,12 +406,8 @@ int fat_cache_init(void); | |||
406 | void fat_cache_destroy(void); | 406 | void fat_cache_destroy(void); |
407 | 407 | ||
408 | /* fat/nfs.c */ | 408 | /* fat/nfs.c */ |
409 | struct fid; | 409 | extern const struct export_operations fat_export_ops; |
410 | extern struct dentry *fat_fh_to_dentry(struct super_block *sb, struct fid *fid, | 410 | extern const struct export_operations fat_export_ops_nostale; |
411 | int fh_len, int fh_type); | ||
412 | extern struct dentry *fat_fh_to_parent(struct super_block *sb, struct fid *fid, | ||
413 | int fh_len, int fh_type); | ||
414 | extern struct dentry *fat_get_parent(struct dentry *child_dir); | ||
415 | 411 | ||
416 | /* helper for printk */ | 412 | /* helper for printk */ |
417 | typedef unsigned long long llu; | 413 | typedef unsigned long long llu; |
diff --git a/fs/fat/file.c b/fs/fat/file.c index 3978f8ca1823..b0b632e50ddb 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c | |||
@@ -306,6 +306,11 @@ int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
306 | struct inode *inode = dentry->d_inode; | 306 | struct inode *inode = dentry->d_inode; |
307 | generic_fillattr(inode, stat); | 307 | generic_fillattr(inode, stat); |
308 | stat->blksize = MSDOS_SB(inode->i_sb)->cluster_size; | 308 | stat->blksize = MSDOS_SB(inode->i_sb)->cluster_size; |
309 | |||
310 | if (MSDOS_SB(inode->i_sb)->options.nfs == FAT_NFS_NOSTALE_RO) { | ||
311 | /* Use i_pos for ino. This is used as fileid of nfs. */ | ||
312 | stat->ino = fat_i_pos_read(MSDOS_SB(inode->i_sb), inode); | ||
313 | } | ||
309 | return 0; | 314 | return 0; |
310 | } | 315 | } |
311 | EXPORT_SYMBOL_GPL(fat_getattr); | 316 | EXPORT_SYMBOL_GPL(fat_getattr); |
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 68cb5a6eb539..27f49f4fa0d3 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <linux/pagemap.h> | 18 | #include <linux/pagemap.h> |
19 | #include <linux/mpage.h> | 19 | #include <linux/mpage.h> |
20 | #include <linux/buffer_head.h> | 20 | #include <linux/buffer_head.h> |
21 | #include <linux/exportfs.h> | ||
22 | #include <linux/mount.h> | 21 | #include <linux/mount.h> |
23 | #include <linux/vfs.h> | 22 | #include <linux/vfs.h> |
24 | #include <linux/parser.h> | 23 | #include <linux/parser.h> |
@@ -748,12 +747,6 @@ static const struct super_operations fat_sops = { | |||
748 | .show_options = fat_show_options, | 747 | .show_options = fat_show_options, |
749 | }; | 748 | }; |
750 | 749 | ||
751 | static const struct export_operations fat_export_ops = { | ||
752 | .fh_to_dentry = fat_fh_to_dentry, | ||
753 | .fh_to_parent = fat_fh_to_parent, | ||
754 | .get_parent = fat_get_parent, | ||
755 | }; | ||
756 | |||
757 | static int fat_show_options(struct seq_file *m, struct dentry *root) | 750 | static int fat_show_options(struct seq_file *m, struct dentry *root) |
758 | { | 751 | { |
759 | struct msdos_sb_info *sbi = MSDOS_SB(root->d_sb); | 752 | struct msdos_sb_info *sbi = MSDOS_SB(root->d_sb); |
@@ -1177,8 +1170,10 @@ out: | |||
1177 | opts->allow_utime = ~opts->fs_dmask & (S_IWGRP | S_IWOTH); | 1170 | opts->allow_utime = ~opts->fs_dmask & (S_IWGRP | S_IWOTH); |
1178 | if (opts->unicode_xlate) | 1171 | if (opts->unicode_xlate) |
1179 | opts->utf8 = 0; | 1172 | opts->utf8 = 0; |
1180 | if (opts->nfs == FAT_NFS_NOSTALE_RO) | 1173 | if (opts->nfs == FAT_NFS_NOSTALE_RO) { |
1181 | sb->s_flags |= MS_RDONLY; | 1174 | sb->s_flags |= MS_RDONLY; |
1175 | sb->s_export_op = &fat_export_ops_nostale; | ||
1176 | } | ||
1182 | 1177 | ||
1183 | return 0; | 1178 | return 0; |
1184 | } | 1179 | } |
@@ -1189,7 +1184,7 @@ static int fat_read_root(struct inode *inode) | |||
1189 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | 1184 | struct msdos_sb_info *sbi = MSDOS_SB(sb); |
1190 | int error; | 1185 | int error; |
1191 | 1186 | ||
1192 | MSDOS_I(inode)->i_pos = 0; | 1187 | MSDOS_I(inode)->i_pos = MSDOS_ROOT_INO; |
1193 | inode->i_uid = sbi->options.fs_uid; | 1188 | inode->i_uid = sbi->options.fs_uid; |
1194 | inode->i_gid = sbi->options.fs_gid; | 1189 | inode->i_gid = sbi->options.fs_gid; |
1195 | inode->i_version++; | 1190 | inode->i_version++; |
diff --git a/fs/fat/nfs.c b/fs/fat/nfs.c index 499c10438ca2..d59c02543a10 100644 --- a/fs/fat/nfs.c +++ b/fs/fat/nfs.c | |||
@@ -14,6 +14,18 @@ | |||
14 | #include <linux/exportfs.h> | 14 | #include <linux/exportfs.h> |
15 | #include "fat.h" | 15 | #include "fat.h" |
16 | 16 | ||
17 | struct fat_fid { | ||
18 | u32 i_gen; | ||
19 | u32 i_pos_low; | ||
20 | u16 i_pos_hi; | ||
21 | u16 parent_i_pos_hi; | ||
22 | u32 parent_i_pos_low; | ||
23 | u32 parent_i_gen; | ||
24 | }; | ||
25 | |||
26 | #define FAT_FID_SIZE_WITHOUT_PARENT 3 | ||
27 | #define FAT_FID_SIZE_WITH_PARENT (sizeof(struct fat_fid)/sizeof(u32)) | ||
28 | |||
17 | /** | 29 | /** |
18 | * Look up a directory inode given its starting cluster. | 30 | * Look up a directory inode given its starting cluster. |
19 | */ | 31 | */ |
@@ -38,8 +50,8 @@ static struct inode *fat_dget(struct super_block *sb, int i_logstart) | |||
38 | return inode; | 50 | return inode; |
39 | } | 51 | } |
40 | 52 | ||
41 | static struct inode *fat_nfs_get_inode(struct super_block *sb, | 53 | static struct inode *__fat_nfs_get_inode(struct super_block *sb, |
42 | u64 ino, u32 generation) | 54 | u64 ino, u32 generation, loff_t i_pos) |
43 | { | 55 | { |
44 | struct inode *inode; | 56 | struct inode *inode; |
45 | 57 | ||
@@ -55,35 +67,130 @@ static struct inode *fat_nfs_get_inode(struct super_block *sb, | |||
55 | return inode; | 67 | return inode; |
56 | } | 68 | } |
57 | 69 | ||
70 | static struct inode *fat_nfs_get_inode(struct super_block *sb, | ||
71 | u64 ino, u32 generation) | ||
72 | { | ||
73 | |||
74 | return __fat_nfs_get_inode(sb, ino, generation, 0); | ||
75 | } | ||
76 | |||
77 | static int | ||
78 | fat_encode_fh_nostale(struct inode *inode, __u32 *fh, int *lenp, | ||
79 | struct inode *parent) | ||
80 | { | ||
81 | int len = *lenp; | ||
82 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | ||
83 | struct fat_fid *fid = (struct fat_fid *) fh; | ||
84 | loff_t i_pos; | ||
85 | int type = FILEID_FAT_WITHOUT_PARENT; | ||
86 | |||
87 | if (parent) { | ||
88 | if (len < FAT_FID_SIZE_WITH_PARENT) { | ||
89 | *lenp = FAT_FID_SIZE_WITH_PARENT; | ||
90 | return FILEID_INVALID; | ||
91 | } | ||
92 | } else { | ||
93 | if (len < FAT_FID_SIZE_WITHOUT_PARENT) { | ||
94 | *lenp = FAT_FID_SIZE_WITHOUT_PARENT; | ||
95 | return FILEID_INVALID; | ||
96 | } | ||
97 | } | ||
98 | |||
99 | i_pos = fat_i_pos_read(sbi, inode); | ||
100 | *lenp = FAT_FID_SIZE_WITHOUT_PARENT; | ||
101 | fid->i_gen = inode->i_generation; | ||
102 | fid->i_pos_low = i_pos & 0xFFFFFFFF; | ||
103 | fid->i_pos_hi = (i_pos >> 32) & 0xFFFF; | ||
104 | if (parent) { | ||
105 | i_pos = fat_i_pos_read(sbi, parent); | ||
106 | fid->parent_i_pos_hi = (i_pos >> 32) & 0xFFFF; | ||
107 | fid->parent_i_pos_low = i_pos & 0xFFFFFFFF; | ||
108 | fid->parent_i_gen = parent->i_generation; | ||
109 | type = FILEID_FAT_WITH_PARENT; | ||
110 | *lenp = FAT_FID_SIZE_WITH_PARENT; | ||
111 | } | ||
112 | |||
113 | return type; | ||
114 | } | ||
115 | |||
58 | /** | 116 | /** |
59 | * Map a NFS file handle to a corresponding dentry. | 117 | * Map a NFS file handle to a corresponding dentry. |
60 | * The dentry may or may not be connected to the filesystem root. | 118 | * The dentry may or may not be connected to the filesystem root. |
61 | */ | 119 | */ |
62 | struct dentry *fat_fh_to_dentry(struct super_block *sb, struct fid *fid, | 120 | static struct dentry *fat_fh_to_dentry(struct super_block *sb, struct fid *fid, |
63 | int fh_len, int fh_type) | 121 | int fh_len, int fh_type) |
64 | { | 122 | { |
65 | return generic_fh_to_dentry(sb, fid, fh_len, fh_type, | 123 | return generic_fh_to_dentry(sb, fid, fh_len, fh_type, |
66 | fat_nfs_get_inode); | 124 | fat_nfs_get_inode); |
67 | } | 125 | } |
68 | 126 | ||
127 | static struct dentry *fat_fh_to_dentry_nostale(struct super_block *sb, | ||
128 | struct fid *fh, int fh_len, | ||
129 | int fh_type) | ||
130 | { | ||
131 | struct inode *inode = NULL; | ||
132 | struct fat_fid *fid = (struct fat_fid *)fh; | ||
133 | loff_t i_pos; | ||
134 | |||
135 | switch (fh_type) { | ||
136 | case FILEID_FAT_WITHOUT_PARENT: | ||
137 | if (fh_len < FAT_FID_SIZE_WITHOUT_PARENT) | ||
138 | return NULL; | ||
139 | break; | ||
140 | case FILEID_FAT_WITH_PARENT: | ||
141 | if (fh_len < FAT_FID_SIZE_WITH_PARENT) | ||
142 | return NULL; | ||
143 | break; | ||
144 | default: | ||
145 | return NULL; | ||
146 | } | ||
147 | i_pos = fid->i_pos_hi; | ||
148 | i_pos = (i_pos << 32) | (fid->i_pos_low); | ||
149 | inode = __fat_nfs_get_inode(sb, 0, fid->i_gen, i_pos); | ||
150 | |||
151 | return d_obtain_alias(inode); | ||
152 | } | ||
153 | |||
69 | /* | 154 | /* |
70 | * Find the parent for a file specified by NFS handle. | 155 | * Find the parent for a file specified by NFS handle. |
71 | * This requires that the handle contain the i_ino of the parent. | 156 | * This requires that the handle contain the i_ino of the parent. |
72 | */ | 157 | */ |
73 | struct dentry *fat_fh_to_parent(struct super_block *sb, struct fid *fid, | 158 | static struct dentry *fat_fh_to_parent(struct super_block *sb, struct fid *fid, |
74 | int fh_len, int fh_type) | 159 | int fh_len, int fh_type) |
75 | { | 160 | { |
76 | return generic_fh_to_parent(sb, fid, fh_len, fh_type, | 161 | return generic_fh_to_parent(sb, fid, fh_len, fh_type, |
77 | fat_nfs_get_inode); | 162 | fat_nfs_get_inode); |
78 | } | 163 | } |
79 | 164 | ||
165 | static struct dentry *fat_fh_to_parent_nostale(struct super_block *sb, | ||
166 | struct fid *fh, int fh_len, | ||
167 | int fh_type) | ||
168 | { | ||
169 | struct inode *inode = NULL; | ||
170 | struct fat_fid *fid = (struct fat_fid *)fh; | ||
171 | loff_t i_pos; | ||
172 | |||
173 | if (fh_len < FAT_FID_SIZE_WITH_PARENT) | ||
174 | return NULL; | ||
175 | |||
176 | switch (fh_type) { | ||
177 | case FILEID_FAT_WITH_PARENT: | ||
178 | i_pos = fid->parent_i_pos_hi; | ||
179 | i_pos = (i_pos << 32) | (fid->parent_i_pos_low); | ||
180 | inode = __fat_nfs_get_inode(sb, 0, fid->parent_i_gen, i_pos); | ||
181 | break; | ||
182 | } | ||
183 | |||
184 | return d_obtain_alias(inode); | ||
185 | } | ||
186 | |||
80 | /* | 187 | /* |
81 | * Find the parent for a directory that is not currently connected to | 188 | * Find the parent for a directory that is not currently connected to |
82 | * the filesystem root. | 189 | * the filesystem root. |
83 | * | 190 | * |
84 | * On entry, the caller holds child_dir->d_inode->i_mutex. | 191 | * On entry, the caller holds child_dir->d_inode->i_mutex. |
85 | */ | 192 | */ |
86 | struct dentry *fat_get_parent(struct dentry *child_dir) | 193 | static struct dentry *fat_get_parent(struct dentry *child_dir) |
87 | { | 194 | { |
88 | struct super_block *sb = child_dir->d_sb; | 195 | struct super_block *sb = child_dir->d_sb; |
89 | struct buffer_head *bh = NULL; | 196 | struct buffer_head *bh = NULL; |
@@ -98,3 +205,16 @@ struct dentry *fat_get_parent(struct dentry *child_dir) | |||
98 | 205 | ||
99 | return d_obtain_alias(parent_inode); | 206 | return d_obtain_alias(parent_inode); |
100 | } | 207 | } |
208 | |||
209 | const struct export_operations fat_export_ops = { | ||
210 | .fh_to_dentry = fat_fh_to_dentry, | ||
211 | .fh_to_parent = fat_fh_to_parent, | ||
212 | .get_parent = fat_get_parent, | ||
213 | }; | ||
214 | |||
215 | const struct export_operations fat_export_ops_nostale = { | ||
216 | .encode_fh = fat_encode_fh_nostale, | ||
217 | .fh_to_dentry = fat_fh_to_dentry_nostale, | ||
218 | .fh_to_parent = fat_fh_to_parent_nostale, | ||
219 | .get_parent = fat_get_parent, | ||
220 | }; | ||