| Start/ | End/ | |||
| True | False | - | Line | Source |
| 1 | /* | |||
| 2 | * linux/fs/fat/inode.c | |||
| 3 | * | |||
| 4 | * Written 1992,1993 by Werner Almesberger | |||
| 5 | * VFAT extensions by Gordon Chaffee, merged with msdos fs by Henrik Storner | |||
| 6 | * Rewritten for the constant inumbers support by Al Viro | |||
| 7 | * | |||
| 8 | * Fixes: | |||
| 9 | * | |||
| 10 | * Max Cohan: Fixed invalid FSINFO offset when info_sector is 0 | |||
| 11 | */ | |||
| 12 | ||||
| 13 | #include <linux/module.h> | |||
| 14 | #include <linux/init.h> | |||
| 15 | #include <linux/time.h> | |||
| 16 | #include <linux/slab.h> | |||
| 17 | #include <linux/smp_lock.h> | |||
| 18 | #include <linux/seq_file.h> | |||
| 19 | #include <linux/msdos_fs.h> | |||
| 20 | #include <linux/pagemap.h> | |||
| 21 | #include <linux/mpage.h> | |||
| 22 | #include <linux/buffer_head.h> | |||
| 23 | #include <linux/mount.h> | |||
| 24 | #include <linux/vfs.h> | |||
| 25 | #include <linux/parser.h> | |||
| 26 | #include <linux/uio.h> | |||
| 27 | #include <asm/unaligned.h> | |||
| 28 | ||||
| 29 | #ifndef CONFIG_FAT_DEFAULT_IOCHARSET | |||
| 30 | /* if user don't select VFAT, this is undefined. */ | |||
| 31 | #define CONFIG_FAT_DEFAULT_IOCHARSET "" | |||
| 32 | #endif | |||
| 33 | ||||
| 34 | static int fat_default_codepage = CONFIG_FAT_DEFAULT_CODEPAGE; | |||
| 35 | static char fat_default_iocharset[] = CONFIG_FAT_DEFAULT_IOCHARSET; | |||
| 36 | ||||
| 37 | ||||
| 392 | 0 | 38 | static int fat_add_cluster(struct inode *inode) | |
| 39 | { | |||
| 40 | int err, cluster; | |||
| 41 | ||||
| 42 | err = fat_alloc_clusters(inode, &cluster, 1); | |||
| 0 | 392 | - | 43 | if (err) |
| 0 | - | 44 | return err; | |
| 45 | /* FIXME: this cluster should be added after data of this | |||
| 46 | * cluster is writed */ | |||
| 47 | err = fat_chain_add(inode, cluster, 1); | |||
| 0 | 392 | - | 48 | if (err) |
| 49 | fat_free_clusters(inode, cluster); | |||
| 392 | 50 | return err; | ||
| 51 | } | |||
| 52 | ||||
| 265019 | 0 | 53 | static int __fat_get_blocks(struct inode *inode, sector_t iblock, | |
| 54 | unsigned long *max_blocks, | |||
| 55 | struct buffer_head *bh_result, int create) | |||
| 56 | { | |||
| 57 | struct super_block *sb = inode->i_sb; | |||
| 58 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | |||
| 59 | sector_t phys; | |||
| 60 | unsigned long mapped_blocks; | |||
| 61 | int err, offset; | |||
| 62 | ||||
| 63 | err = fat_bmap(inode, iblock, &phys, &mapped_blocks); | |||
| 0 | 265019 | - | 64 | if (err) |
| 0 | - | 65 | return err; | |
| 239978 | 25041 | 66 | if (phys) { | |
| 67 | map_bh(bh_result, sb, phys); | |||
| 68 | *max_blocks = min(mapped_blocks, *max_blocks); | |||
| 239978 | 69 | return 0; | ||
| 70 | } | |||
| 0 | 25041 | - | 71 | if (!create) |
| 0 | - | 72 | return 0; | |
| 73 | ||||
| 0 | 25041 | - | 74 | if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) { |
| 75 | fat_fs_panic(sb, "corrupted file size (i_pos %lld, %lld)", | |||
| 76 | MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private); | |||
| 0 | - | 77 | return -EIO; | |
| 78 | } | |||
| 79 | ||||
| 80 | offset = (unsigned long)iblock & (sbi->sec_per_clus - 1); | |||
| 392 | 24649 | 81 | if (!offset) { | |
| 82 | /* TODO: multiple cluster allocation would be desirable. */ | |||
| 83 | err = fat_add_cluster(inode); | |||
| 0 | 392 | - | 84 | if (err) |
| 0 | - | 85 | return err; | |
| 86 | } | |||
| 87 | /* available blocks on this cluster */ | |||
| 88 | mapped_blocks = sbi->sec_per_clus - offset; | |||
| 89 | ||||
| 90 | *max_blocks = min(mapped_blocks, *max_blocks); | |||
| 91 | MSDOS_I(inode)->mmu_private += *max_blocks << sb->s_blocksize_bits; | |||
| 92 | ||||
| 93 | err = fat_bmap(inode, iblock, &phys, &mapped_blocks); | |||
| 0 | 25041 | - | 94 | if (err) |
| 0 | - | 95 | return err; | |
| 96 | BUG_ON(!phys); | |||
| 0 | 25041 | - | 96 | if (__builtin_expect ( ! ! ( ( ! phys ) != 0.. |
| 0 | 25041 | - | 96 | do-while (0) |
| 97 | BUG_ON(*max_blocks != mapped_blocks); | |||
| 0 | 25041 | - | 97 | if (__builtin_expect ( ! ! ( ( * max_blocks .. |
| 0 | 25041 | - | 97 | do-while (0) |
| 98 | set_buffer_new(bh_result); | |||
| 99 | map_bh(bh_result, sb, phys); | |||
| 25041 | 100 | return 0; | ||
| 101 | } | |||
| 102 | ||||
| 0 | 0 | - | 103 | static int fat_get_blocks(struct inode *inode, sector_t iblock, |
| 104 | unsigned long max_blocks, | |||
| 105 | struct buffer_head *bh_result, int create) | |||
| 106 | { | |||
| 107 | struct super_block *sb = inode->i_sb; | |||
| 108 | int err; | |||
| 109 | ||||
| 110 | err = __fat_get_blocks(inode, iblock, &max_blocks, bh_result, create); | |||
| 0 | 0 | - | 111 | if (err) |
| 0 | - | 112 | return err; | |
| 113 | bh_result->b_size = max_blocks << sb->s_blocksize_bits; | |||
| 0 | - | 114 | return 0; | |
| 115 | } | |||
| 116 | ||||
| 265019 | 0 | 117 | static int fat_get_block(struct inode *inode, sector_t iblock, | |
| 118 | struct buffer_head *bh_result, int create) | |||
| 119 | { | |||
| 120 | unsigned long max_blocks = 1; | |||
| 265019 | 121 | return __fat_get_blocks(inode, iblock, &max_blocks, bh_result, create); | ||
| 122 | } | |||
| 123 | ||||
| 0 | 0 | - | 124 | static int fat_writepage(struct page *page, struct writeback_control *wbc) |
| 125 | { | |||
| 0 | - | 126 | return block_write_full_page(page, fat_get_block, wbc); | |
| 127 | } | |||
| 128 | ||||
| 209 | 0 | 129 | static int fat_writepages(struct address_space *mapping, | |
| 130 | struct writeback_control *wbc) | |||
| 131 | { | |||
| 209 | 132 | return mpage_writepages(mapping, wbc, fat_get_block); | ||
| 133 | } | |||
| 134 | ||||
| 0 | 0 | - | 135 | static int fat_readpage(struct file *file, struct page *page) |
| 136 | { | |||
| 0 | - | 137 | return mpage_readpage(page, fat_get_block); | |
| 138 | } | |||
| 139 | ||||
| 1120 | 0 | 140 | static int fat_readpages(struct file *file, struct address_space *mapping, | |
| 141 | struct list_head *pages, unsigned nr_pages) | |||
| 142 | { | |||
| 1120 | 143 | return mpage_readpages(mapping, pages, nr_pages, fat_get_block); | ||
| 144 | } | |||
| 145 | ||||
| 3131 | 0 | 146 | static int fat_prepare_write(struct file *file, struct page *page, | |
| 147 | unsigned from, unsigned to) | |||
| 148 | { | |||
| 149 | return cont_prepare_write(page, from, to, fat_get_block, | |||
| 3131 | 150 | &MSDOS_I(page->mapping->host)->mmu_private); | ||
| 151 | } | |||
| 152 | ||||
| 3131 | 0 | 153 | static int fat_commit_write(struct file *file, struct page *page, | |
| 154 | unsigned from, unsigned to) | |||
| 155 | { | |||
| 156 | struct inode *inode = page->mapping->host; | |||
| 157 | int err = generic_commit_write(file, page, from, to); | |||
| 0 | 3131 | - | 158 | if (!err && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) { |
| 0 | - | 158 | T && !(F) | |
| 3131 | 158 | T && !(T) | ||
| 0 | - | 158 | F && !(_) | |
| 159 | inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; | |||
| 160 | MSDOS_I(inode)->i_attrs |= ATTR_ARCH; | |||
| 161 | mark_inode_dirty(inode); | |||
| 162 | } | |||
| 3131 | 163 | return err; | ||
| 164 | } | |||
| 165 | ||||
| 0 | 0 | - | 166 | static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, |
| 167 | const struct iovec *iov, | |||
| 168 | loff_t offset, unsigned long nr_segs) | |||
| 169 | { | |||
| 170 | struct file *file = iocb->ki_filp; | |||
| 171 | struct inode *inode = file->f_mapping->host; | |||
| 172 | ||||
| 0 | 0 | - | 173 | if (rw == WRITE) { |
| 174 | /* | |||
| 175 | * FIXME: blockdev_direct_IO() doesn't use ->prepare_write(), | |||
| 176 | * so we need to update the ->mmu_private to block boundary. | |||
| 177 | * | |||
| 178 | * But we must fill the remaining area or hole by nul for | |||
| 179 | * updating ->mmu_private. | |||
| 180 | */ | |||
| 181 | loff_t size = offset + iov_length(iov, nr_segs); | |||
| 0 | 0 | - | 182 | if (MSDOS_I(inode)->mmu_private < size) |
| 0 | - | 183 | return -EINVAL; | |
| 184 | } | |||
| 185 | ||||
| 186 | /* | |||
| 187 | * FAT need to use the DIO_LOCKING for avoiding the race | |||
| 188 | * condition of fat_get_block() and ->truncate(). | |||
| 189 | */ | |||
| 190 | return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, | |||
| 0 | - | 191 | offset, nr_segs, fat_get_blocks, NULL); | |
| 192 | } | |||
| 193 | ||||
| 0 | 0 | - | 194 | static sector_t _fat_bmap(struct address_space *mapping, sector_t block) |
| 195 | { | |||
| 0 | - | 196 | return generic_block_bmap(mapping, block, fat_get_block); | |
| 197 | } | |||
| 198 | ||||
| 199 | static struct address_space_operations fat_aops = { | |||
| 200 | .readpage = fat_readpage, | |||
| 201 | .readpages = fat_readpages, | |||
| 202 | .writepage = fat_writepage, | |||
| 203 | .writepages = fat_writepages, | |||
| 204 | .sync_page = block_sync_page, | |||
| 205 | .prepare_write = fat_prepare_write, | |||
| 206 | .commit_write = fat_commit_write, | |||
| 207 | .direct_IO = fat_direct_IO, | |||
| 208 | .bmap = _fat_bmap | |||
| 209 | }; | |||
| 210 | ||||
| 211 | /* | |||
| 212 | * New FAT inode stuff. We do the following: | |||
| 213 | * a) i_ino is constant and has nothing with on-disk location. | |||
| 214 | * b) FAT manages its own cache of directory entries. | |||
| 215 | * c) *This* cache is indexed by on-disk location. | |||
| 216 | * d) inode has an associated directory entry, all right, but | |||
| 217 | * it may be unhashed. | |||
| 218 | * e) currently entries are stored within struct inode. That should | |||
| 219 | * change. | |||
| 220 | * f) we deal with races in the following way: | |||
| 221 | * 1. readdir() and lookup() do FAT-dir-cache lookup. | |||
| 222 | * 2. rename() unhashes the F-d-c entry and rehashes it in | |||
| 223 | * a new place. | |||
| 224 | * 3. unlink() and rmdir() unhash F-d-c entry. | |||
| 225 | * 4. fat_write_inode() checks whether the thing is unhashed. | |||
| 226 | * If it is we silently return. If it isn't we do bread(), | |||
| 227 | * check if the location is still valid and retry if it | |||
| 228 | * isn't. Otherwise we do changes. | |||
| 229 | * 5. Spinlock is used to protect hash/unhash/location check/lookup | |||
| 230 | * 6. fat_clear_inode() unhashes the F-d-c entry. | |||
| 231 | * 7. lookup() and readdir() do igrab() if they find a F-d-c entry | |||
| 232 | * and consider negative result as cache miss. | |||
| 233 | */ | |||
| 234 | ||||
| 13 | 13 | 235 | static void fat_hash_init(struct super_block *sb) | |
| 236 | { | |||
| 237 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | |||
| 238 | int i; | |||
| 239 | ||||
| 240 | spin_lock_init(&sbi->inode_hash_lock); | |||
| 0 | 13 | - | 240 | do-while (0) |
| 3328 | 13 | 241 | for (i = 0; i < FAT_HASH_SIZE; i++) | |
| 242 | INIT_HLIST_HEAD(&sbi->inode_hashtable[i]); | |||
| 243 | } | |||
| 244 | ||||
| 646128 | 0 | 245 | static inline unsigned long fat_hash(struct super_block *sb, loff_t i_pos) | |
| 246 | { | |||
| 247 | unsigned long tmp = (unsigned long)i_pos | (unsigned long) sb; | |||
| 248 | tmp = tmp + (tmp >> FAT_HASH_BITS) + (tmp >> FAT_HASH_BITS * 2); | |||
| 646128 | 249 | return tmp & FAT_HASH_MASK; | ||
| 250 | } | |||
| 251 | ||||
| 215153 | 215153 | 252 | void fat_attach(struct inode *inode, loff_t i_pos) | |
| 253 | { | |||
| 254 | struct super_block *sb = inode->i_sb; | |||
| 255 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | |||
| 256 | ||||
| 257 | spin_lock(&sbi->inode_hash_lock); | |||
| 257 | do | |||
| 0 | 215153 | - | 257 | do-while (0) |
| 0 | 215153 | - | 257 | do-while (0) |
| 258 | MSDOS_I(inode)->i_pos = i_pos; | |||
| 259 | hlist_add_head(&MSDOS_I(inode)->i_fat_hash, | |||
| 260 | sbi->inode_hashtable + fat_hash(sb, i_pos)); | |||
| 261 | spin_unlock(&sbi->inode_hash_lock); | |||
| 261 | do | |||
| 0 | 215153 | - | 261 | do-while (0) |
| 0 | 215153 | - | 261 | do-while (0) |
| 262 | } | |||
| 263 | ||||
| 264 | EXPORT_SYMBOL_GPL(fat_attach); | |||
| 265 | ||||
| 0 | 0 | - | 266 | void fat_detach(struct inode *inode) |
| 267 | { | |||
| 268 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | |||
| 269 | spin_lock(&sbi->inode_hash_lock); | |||
| 269 | do | |||
| 0 | 0 | - | 269 | do-while (0) |
| 0 | 0 | - | 269 | do-while (0) |
| 270 | MSDOS_I(inode)->i_pos = 0; | |||
| 271 | hlist_del_init(&MSDOS_I(inode)->i_fat_hash); | |||
| 272 | spin_unlock(&sbi->inode_hash_lock); | |||
| 272 | do | |||
| 0 | 0 | - | 272 | do-while (0) |
| 0 | 0 | - | 272 | do-while (0) |
| 273 | } | |||
| 274 | ||||
| 275 | EXPORT_SYMBOL_GPL(fat_detach); | |||
| 276 | ||||
| 430975 | 0 | 277 | struct inode *fat_iget(struct super_block *sb, loff_t i_pos) | |
| 278 | { | |||
| 279 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | |||
| 280 | struct hlist_head *head = sbi->inode_hashtable + fat_hash(sb, i_pos); | |||
| 281 | struct hlist_node *_p; | |||
| 282 | struct msdos_inode_info *i; | |||
| 283 | struct inode *inode = NULL; | |||
| 284 | ||||
| 285 | spin_lock(&sbi->inode_hash_lock); | |||
| 285 | do | |||
| 0 | 430975 | - | 285 | do-while (0) |
| 0 | 430975 | - | 285 | do-while (0) |
| 6019E4 | 430477 | 286 | hlist_for_each_entry(i, _p, head, i_fat_hash) { | |
| 6019E4 | 286 | T && (T) && (T) | ||
| 0 | - | 286 | T && (T) && (F) | |
| 0 | - | 286 | T && (F) && (_) | |
| 430477 | 286 | F && (_) && (_) | ||
| 287 | BUG_ON(i->vfs_inode.i_sb != sb); | |||
| 0 | 6019E4 | - | 287 | if (__builtin_expect ( ! ! ( ( i -> vfs_in.. |
| 0 | 6019E4 | - | 287 | do-while (0) |
| 6019E4 | 498 | 288 | if (i->i_pos != i_pos) | |
| 6019E4 | 289 | continue; | ||
| 290 | inode = igrab(&i->vfs_inode); | |||
| 498 | 0 | - | 291 | if (inode) |
| 498 | 292 | break; | ||
| 293 | } | |||
| 294 | spin_unlock(&sbi->inode_hash_lock); | |||
| 294 | do | |||
| 0 | 430975 | - | 294 | do-while (0) |
| 0 | 430975 | - | 294 | do-while (0) |
| 430975 | 295 | return inode; | ||
| 296 | } | |||
| 297 | ||||
| 0 | 0 | - | 298 | static int is_exec(unsigned char *extension) |
| 299 | { | |||
| 300 | unsigned char *exe_extensions = "EXECOMBAT", *walk; | |||
| 301 | ||||
| 0 | 0 | - | 302 | for (walk = exe_extensions; *walk; walk += 3) |
| 0 | 0 | - | 303 | if (!strncmp(extension, walk, 3)) |
| 0 | - | 304 | return 1; | |
| 0 | - | 305 | return 0; | |
| 306 | } | |||
| 307 | ||||
| 20601 | 0 | 308 | static int fat_calc_dir_size(struct inode *inode) | |
| 309 | { | |||
| 310 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | |||
| 311 | int ret, fclus, dclus; | |||
| 312 | ||||
| 313 | inode->i_size = 0; | |||
| 0 | 20601 | - | 314 | if (MSDOS_I(inode)->i_start == 0) |
| 0 | - | 315 | return 0; | |
| 316 | ||||
| 317 | ret = fat_get_cluster(inode, FAT_ENT_EOF, &fclus, &dclus); | |||
| 0 | 20601 | - | 318 | if (ret < 0) |
| 0 | - | 319 | return ret; | |
| 320 | inode->i_size = (fclus + 1) << sbi->cluster_bits; | |||
| 321 | ||||
| 20601 | 322 | return 0; | ||
| 323 | } | |||
| 324 | ||||
| 325 | /* doesn't deal with root inode */ | |||
| 215153 | 0 | 326 | static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) | |
| 327 | { | |||
| 328 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | |||
| 329 | int error; | |||
| 330 | ||||
| 331 | MSDOS_I(inode)->i_pos = 0; | |||
| 332 | inode->i_uid = sbi->options.fs_uid; | |||
| 333 | inode->i_gid = sbi->options.fs_gid; | |||
| 334 | inode->i_version++; | |||
| 335 | inode->i_generation = get_seconds(); | |||
| 336 | ||||
| 20589 | 194564 | 337 | if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) { | |
| 20589 | 337 | (T) && !(F || F) | ||
| 0 | - | 337 | (T) && !(T || _) | |
| 0 | - | 337 | (T) && !(F || T) | |
| 194564 | 337 | (F) && !(_ || _) | ||
| 338 | inode->i_generation &= ~1; | |||
| 339 | inode->i_mode = MSDOS_MKMODE(de->attr, | |||
| 289 | 20300 | 339 | ternary-?: de -> attr & 1 | |
| 340 | S_IRWXUGO & ~sbi->options.fs_dmask) | S_IFDIR; | |||
| 341 | inode->i_op = sbi->dir_ops; | |||
| 342 | inode->i_fop = &fat_dir_operations; | |||
| 343 | ||||
| 344 | MSDOS_I(inode)->i_start = le16_to_cpu(de->start); | |||
| 20586 | 3 | 345 | if (sbi->fat_bits == 32) | |
| 346 | MSDOS_I(inode)->i_start |= (le16_to_cpu(de->starthi) << 16); | |||
| 347 | ||||
| 348 | MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start; | |||
| 349 | error = fat_calc_dir_size(inode); | |||
| 0 | 20589 | - | 350 | if (error < 0) |
| 0 | - | 351 | return error; | |
| 352 | MSDOS_I(inode)->mmu_private = inode->i_size; | |||
| 353 | ||||
| 354 | inode->i_nlink = fat_subdirs(inode); | |||
| 355 | } else { /* not a directory */ | |||
| 356 | inode->i_generation |= 1; | |||
| 357 | inode->i_mode = MSDOS_MKMODE(de->attr, | |||
| 0 | 194564 | - | 357 | ternary-?: ( sbi -> options . showexec && ! .. |
| 4546 | 190018 | 357 | ternary-?: de -> attr & 1 | |
| 358 | ((sbi->options.showexec && | |||
| 359 | !is_exec(de->ext)) | |||
| 360 | ? S_IRUGO|S_IWUGO : S_IRWXUGO) | |||
| 361 | & ~sbi->options.fs_fmask) | S_IFREG; | |||
| 362 | MSDOS_I(inode)->i_start = le16_to_cpu(de->start); | |||
| 194468 | 96 | 363 | if (sbi->fat_bits == 32) | |
| 364 | MSDOS_I(inode)->i_start |= (le16_to_cpu(de->starthi) << 16); | |||
| 365 | ||||
| 366 | MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start; | |||
| 367 | inode->i_size = le32_to_cpu(de->size); | |||
| 368 | inode->i_op = &fat_file_inode_operations; | |||
| 369 | inode->i_fop = &fat_file_operations; | |||
| 370 | inode->i_mapping->a_ops = &fat_aops; | |||
| 371 | MSDOS_I(inode)->mmu_private = inode->i_size; | |||
| 372 | } | |||
| 1050 | 214103 | 373 | if (de->attr & ATTR_SYS) { | |
| 0 | 1050 | - | 374 | if (sbi->options.sys_immutable) |
| 375 | inode->i_flags |= S_IMMUTABLE; | |||
| 376 | } | |||
| 377 | MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED; | |||
| 378 | /* this is as close to the truth as we can get ... */ | |||
| 379 | inode->i_blksize = sbi->cluster_size; | |||
| 380 | inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1)) | |||
| 381 | & ~((loff_t)sbi->cluster_size - 1)) >> 9; | |||
| 382 | inode->i_mtime.tv_sec = | |||
| 383 | date_dos2unix(le16_to_cpu(de->time), le16_to_cpu(de->date)); | |||
| 384 | inode->i_mtime.tv_nsec = 0; | |||
| 215153 | 0 | - | 385 | if (sbi->options.isvfat) { |
| 386 | int secs = de->ctime_cs / 100; | |||
| 387 | int csecs = de->ctime_cs % 100; | |||
| 388 | inode->i_ctime.tv_sec = | |||
| 389 | date_dos2unix(le16_to_cpu(de->ctime), | |||
| 390 | le16_to_cpu(de->cdate)) + secs; | |||
| 391 | inode->i_ctime.tv_nsec = csecs * 10000000; | |||
| 392 | inode->i_atime.tv_sec = | |||
| 393 | date_dos2unix(le16_to_cpu(0), le16_to_cpu(de->adate)); | |||
| 394 | inode->i_atime.tv_nsec = 0; | |||
| 395 | } else | |||
| 396 | inode->i_ctime = inode->i_atime = inode->i_mtime; | |||
| 397 | ||||
| 215153 | 398 | return 0; | ||
| 399 | } | |||
| 400 | ||||
| 215219 | 0 | 401 | struct inode *fat_build_inode(struct super_block *sb, | |
| 402 | struct msdos_dir_entry *de, loff_t i_pos) | |||
| 403 | { | |||
| 404 | struct inode *inode; | |||
| 405 | int err; | |||
| 406 | ||||
| 407 | inode = fat_iget(sb, i_pos); | |||
| 66 | 215153 | 408 | if (inode) | |
| 66 | 409 | goto out; | ||
| 410 | inode = new_inode(sb); | |||
| 0 | 215153 | - | 411 | if (!inode) { |
| 412 | inode = ERR_PTR(-ENOMEM); | |||
| 0 | - | 413 | goto out; | |
| 414 | } | |||
| 415 | inode->i_ino = iunique(sb, MSDOS_ROOT_INO); | |||
| 416 | inode->i_version = 1; | |||
| 417 | err = fat_fill_inode(inode, de); | |||
| 0 | 215153 | - | 418 | if (err) { |
| 419 | iput(inode); | |||
| 420 | inode = ERR_PTR(err); | |||
| 0 | - | 421 | goto out; | |
| 422 | } | |||
| 423 | fat_attach(inode, i_pos); | |||
| 424 | insert_inode_hash(inode); | |||
| 425 | out: | |||
| 215219 | 426 | return inode; | ||
| 427 | } | |||
| 428 | ||||
| 429 | EXPORT_SYMBOL_GPL(fat_build_inode); | |||
| 430 | ||||
| 0 | 0 | - | 431 | static void fat_delete_inode(struct inode *inode) |
| 432 | { | |||
| 433 | truncate_inode_pages(&inode->i_data, 0); | |||
| 434 | ||||
| 0 | 0 | - | 435 | if (!is_bad_inode(inode)) { |
| 436 | inode->i_size = 0; | |||
| 437 | fat_truncate(inode); | |||
| 438 | } | |||
| 439 | clear_inode(inode); | |||
| 440 | } | |||
| 441 | ||||
| 211509 | 211509 | 442 | static void fat_clear_inode(struct inode *inode) | |
| 443 | { | |||
| 444 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | |||
| 445 | ||||
| 0 | 211509 | - | 446 | if (is_bad_inode(inode)) |
| 0 | - | 447 | return; | |
| 448 | lock_kernel(); | |||
| 0 | 211509 | - | 448 | do-while (0) |
| 449 | spin_lock(&sbi->inode_hash_lock); | |||
| 449 | do | |||
| 0 | 211509 | - | 449 | do-while (0) |
| 0 | 211509 | - | 449 | do-while (0) |
| 450 | fat_cache_inval_inode(inode); | |||
| 451 | hlist_del_init(&MSDOS_I(inode)->i_fat_hash); | |||
| 452 | spin_unlock(&sbi->inode_hash_lock); | |||
| 452 | do | |||
| 0 | 211509 | - | 452 | do-while (0) |
| 0 | 211509 | - | 452 | do-while (0) |
| 453 | unlock_kernel(); | |||
| 0 | 211509 | - | 453 | do-while (0) |
| 454 | } | |||
| 455 | ||||
| 3 | 3 | 456 | static void fat_write_super(struct super_block *sb) | |
| 457 | { | |||
| 458 | sb->s_dirt = 0; | |||
| 459 | ||||
| 3 | 0 | - | 460 | if (!(sb->s_flags & MS_RDONLY)) |
| 461 | fat_clusters_flush(sb); | |||
| 462 | } | |||
| 463 | ||||
| 1 | 1 | 464 | static void fat_put_super(struct super_block *sb) | |
| 465 | { | |||
| 466 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | |||
| 467 | ||||
| 1 | 0 | - | 468 | if (sbi->nls_disk) { |
| 469 | unload_nls(sbi->nls_disk); | |||
| 470 | sbi->nls_disk = NULL; | |||
| 471 | sbi->options.codepage = fat_default_codepage; | |||
| 472 | } | |||
| 1 | 0 | - | 473 | if (sbi->nls_io) { |
| 474 | unload_nls(sbi->nls_io); | |||
| 475 | sbi->nls_io = NULL; | |||
| 476 | } | |||
| 0 | 1 | - | 477&n | |