nfs.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /* fs/fat/nfs.c
  2. *
  3. * This software is licensed under the terms of the GNU General Public
  4. * License version 2, as published by the Free Software Foundation, and
  5. * may be copied, distributed, and modified under those terms.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. */
  13. #include <linux/exportfs.h>
  14. #include "fat.h"
  15. struct fat_fid {
  16. u32 i_gen;
  17. u32 i_pos_low;
  18. u16 i_pos_hi;
  19. u16 parent_i_pos_hi;
  20. u32 parent_i_pos_low;
  21. u32 parent_i_gen;
  22. };
  23. #define FAT_FID_SIZE_WITHOUT_PARENT 3
  24. #define FAT_FID_SIZE_WITH_PARENT (sizeof(struct fat_fid)/sizeof(u32))
  25. /**
  26. * Look up a directory inode given its starting cluster.
  27. */
  28. static struct inode *fat_dget(struct super_block *sb, int i_logstart)
  29. {
  30. struct msdos_sb_info *sbi = MSDOS_SB(sb);
  31. struct hlist_head *head;
  32. struct msdos_inode_info *i;
  33. struct inode *inode = NULL;
  34. head = sbi->dir_hashtable + fat_dir_hash(i_logstart);
  35. spin_lock(&sbi->dir_hash_lock);
  36. hlist_for_each_entry(i, head, i_dir_hash) {
  37. BUG_ON(i->vfs_inode.i_sb != sb);
  38. if (i->i_logstart != i_logstart)
  39. continue;
  40. inode = igrab(&i->vfs_inode);
  41. if (inode)
  42. break;
  43. }
  44. spin_unlock(&sbi->dir_hash_lock);
  45. return inode;
  46. }
  47. static struct inode *fat_ilookup(struct super_block *sb, u64 ino, loff_t i_pos)
  48. {
  49. if (MSDOS_SB(sb)->options.nfs == FAT_NFS_NOSTALE_RO)
  50. return fat_iget(sb, i_pos);
  51. else {
  52. if ((ino < MSDOS_ROOT_INO) || (ino == MSDOS_FSINFO_INO))
  53. return NULL;
  54. return ilookup(sb, ino);
  55. }
  56. }
  57. static struct inode *__fat_nfs_get_inode(struct super_block *sb,
  58. u64 ino, u32 generation, loff_t i_pos)
  59. {
  60. struct inode *inode = fat_ilookup(sb, ino, i_pos);
  61. if (inode && generation && (inode->i_generation != generation)) {
  62. iput(inode);
  63. inode = NULL;
  64. }
  65. if (inode == NULL && MSDOS_SB(sb)->options.nfs == FAT_NFS_NOSTALE_RO) {
  66. struct buffer_head *bh = NULL;
  67. struct msdos_dir_entry *de ;
  68. sector_t blocknr;
  69. int offset;
  70. fat_get_blknr_offset(MSDOS_SB(sb), i_pos, &blocknr, &offset);
  71. bh = sb_bread(sb, blocknr);
  72. if (!bh) {
  73. fat_msg(sb, KERN_ERR,
  74. "unable to read block(%llu) for building NFS inode",
  75. (llu)blocknr);
  76. return inode;
  77. }
  78. de = (struct msdos_dir_entry *)bh->b_data;
  79. /* If a file is deleted on server and client is not updated
  80. * yet, we must not build the inode upon a lookup call.
  81. */
  82. if (IS_FREE(de[offset].name))
  83. inode = NULL;
  84. else
  85. inode = fat_build_inode(sb, &de[offset], i_pos);
  86. brelse(bh);
  87. }
  88. return inode;
  89. }
  90. static struct inode *fat_nfs_get_inode(struct super_block *sb,
  91. u64 ino, u32 generation)
  92. {
  93. return __fat_nfs_get_inode(sb, ino, generation, 0);
  94. }
  95. static int
  96. fat_encode_fh_nostale(struct inode *inode, __u32 *fh, int *lenp,
  97. struct inode *parent)
  98. {
  99. int len = *lenp;
  100. struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
  101. struct fat_fid *fid = (struct fat_fid *) fh;
  102. loff_t i_pos;
  103. int type = FILEID_FAT_WITHOUT_PARENT;
  104. if (parent) {
  105. if (len < FAT_FID_SIZE_WITH_PARENT) {
  106. *lenp = FAT_FID_SIZE_WITH_PARENT;
  107. return FILEID_INVALID;
  108. }
  109. } else {
  110. if (len < FAT_FID_SIZE_WITHOUT_PARENT) {
  111. *lenp = FAT_FID_SIZE_WITHOUT_PARENT;
  112. return FILEID_INVALID;
  113. }
  114. }
  115. i_pos = fat_i_pos_read(sbi, inode);
  116. *lenp = FAT_FID_SIZE_WITHOUT_PARENT;
  117. fid->i_gen = inode->i_generation;
  118. fid->i_pos_low = i_pos & 0xFFFFFFFF;
  119. fid->i_pos_hi = (i_pos >> 32) & 0xFFFF;
  120. if (parent) {
  121. i_pos = fat_i_pos_read(sbi, parent);
  122. fid->parent_i_pos_hi = (i_pos >> 32) & 0xFFFF;
  123. fid->parent_i_pos_low = i_pos & 0xFFFFFFFF;
  124. fid->parent_i_gen = parent->i_generation;
  125. type = FILEID_FAT_WITH_PARENT;
  126. *lenp = FAT_FID_SIZE_WITH_PARENT;
  127. }
  128. return type;
  129. }
  130. /**
  131. * Map a NFS file handle to a corresponding dentry.
  132. * The dentry may or may not be connected to the filesystem root.
  133. */
  134. static struct dentry *fat_fh_to_dentry(struct super_block *sb, struct fid *fid,
  135. int fh_len, int fh_type)
  136. {
  137. return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
  138. fat_nfs_get_inode);
  139. }
  140. static struct dentry *fat_fh_to_dentry_nostale(struct super_block *sb,
  141. struct fid *fh, int fh_len,
  142. int fh_type)
  143. {
  144. struct inode *inode = NULL;
  145. struct fat_fid *fid = (struct fat_fid *)fh;
  146. loff_t i_pos;
  147. switch (fh_type) {
  148. case FILEID_FAT_WITHOUT_PARENT:
  149. if (fh_len < FAT_FID_SIZE_WITHOUT_PARENT)
  150. return NULL;
  151. break;
  152. case FILEID_FAT_WITH_PARENT:
  153. if (fh_len < FAT_FID_SIZE_WITH_PARENT)
  154. return NULL;
  155. break;
  156. default:
  157. return NULL;
  158. }
  159. i_pos = fid->i_pos_hi;
  160. i_pos = (i_pos << 32) | (fid->i_pos_low);
  161. inode = __fat_nfs_get_inode(sb, 0, fid->i_gen, i_pos);
  162. return d_obtain_alias(inode);
  163. }
  164. /*
  165. * Find the parent for a file specified by NFS handle.
  166. * This requires that the handle contain the i_ino of the parent.
  167. */
  168. static struct dentry *fat_fh_to_parent(struct super_block *sb, struct fid *fid,
  169. int fh_len, int fh_type)
  170. {
  171. return generic_fh_to_parent(sb, fid, fh_len, fh_type,
  172. fat_nfs_get_inode);
  173. }
  174. static struct dentry *fat_fh_to_parent_nostale(struct super_block *sb,
  175. struct fid *fh, int fh_len,
  176. int fh_type)
  177. {
  178. struct inode *inode = NULL;
  179. struct fat_fid *fid = (struct fat_fid *)fh;
  180. loff_t i_pos;
  181. if (fh_len < FAT_FID_SIZE_WITH_PARENT)
  182. return NULL;
  183. switch (fh_type) {
  184. case FILEID_FAT_WITH_PARENT:
  185. i_pos = fid->parent_i_pos_hi;
  186. i_pos = (i_pos << 32) | (fid->parent_i_pos_low);
  187. inode = __fat_nfs_get_inode(sb, 0, fid->parent_i_gen, i_pos);
  188. break;
  189. }
  190. return d_obtain_alias(inode);
  191. }
  192. /*
  193. * Rebuild the parent for a directory that is not connected
  194. * to the filesystem root
  195. */
  196. static
  197. struct inode *fat_rebuild_parent(struct super_block *sb, int parent_logstart)
  198. {
  199. int search_clus, clus_to_match;
  200. struct msdos_dir_entry *de;
  201. struct inode *parent = NULL;
  202. struct inode *dummy_grand_parent = NULL;
  203. struct fat_slot_info sinfo;
  204. struct msdos_sb_info *sbi = MSDOS_SB(sb);
  205. sector_t blknr = fat_clus_to_blknr(sbi, parent_logstart);
  206. struct buffer_head *parent_bh = sb_bread(sb, blknr);
  207. if (!parent_bh) {
  208. fat_msg(sb, KERN_ERR,
  209. "unable to read cluster of parent directory");
  210. return NULL;
  211. }
  212. de = (struct msdos_dir_entry *) parent_bh->b_data;
  213. clus_to_match = fat_get_start(sbi, &de[0]);
  214. search_clus = fat_get_start(sbi, &de[1]);
  215. dummy_grand_parent = fat_dget(sb, search_clus);
  216. if (!dummy_grand_parent) {
  217. dummy_grand_parent = new_inode(sb);
  218. if (!dummy_grand_parent) {
  219. brelse(parent_bh);
  220. return parent;
  221. }
  222. dummy_grand_parent->i_ino = iunique(sb, MSDOS_ROOT_INO);
  223. fat_fill_inode(dummy_grand_parent, &de[1]);
  224. MSDOS_I(dummy_grand_parent)->i_pos = -1;
  225. }
  226. if (!fat_scan_logstart(dummy_grand_parent, clus_to_match, &sinfo))
  227. parent = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
  228. brelse(parent_bh);
  229. iput(dummy_grand_parent);
  230. return parent;
  231. }
  232. /*
  233. * Find the parent for a directory that is not currently connected to
  234. * the filesystem root.
  235. *
  236. * On entry, the caller holds d_inode(child_dir)->i_mutex.
  237. */
  238. static struct dentry *fat_get_parent(struct dentry *child_dir)
  239. {
  240. struct super_block *sb = child_dir->d_sb;
  241. struct buffer_head *bh = NULL;
  242. struct msdos_dir_entry *de;
  243. struct inode *parent_inode = NULL;
  244. struct msdos_sb_info *sbi = MSDOS_SB(sb);
  245. if (!fat_get_dotdot_entry(d_inode(child_dir), &bh, &de)) {
  246. int parent_logstart = fat_get_start(sbi, de);
  247. parent_inode = fat_dget(sb, parent_logstart);
  248. if (!parent_inode && sbi->options.nfs == FAT_NFS_NOSTALE_RO)
  249. parent_inode = fat_rebuild_parent(sb, parent_logstart);
  250. }
  251. brelse(bh);
  252. return d_obtain_alias(parent_inode);
  253. }
  254. const struct export_operations fat_export_ops = {
  255. .fh_to_dentry = fat_fh_to_dentry,
  256. .fh_to_parent = fat_fh_to_parent,
  257. .get_parent = fat_get_parent,
  258. };
  259. const struct export_operations fat_export_ops_nostale = {
  260. .encode_fh = fat_encode_fh_nostale,
  261. .fh_to_dentry = fat_fh_to_dentry_nostale,
  262. .fh_to_parent = fat_fh_to_parent_nostale,
  263. .get_parent = fat_get_parent,
  264. };