mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 16:48:26 +02:00 
			
		
		
		
	fat: restructure export_operations
Define two nfs export_operation structures,one for 'stale_rw' mounts and the other for 'nostale_ro'. The latter uses i_pos as a basis for encoding and decoding file handles. Also, assign i_pos to kstat->ino. The logic for rebuilding the inode is added in the subsequent patches. Signed-off-by: Namjae Jeon <namjae.jeon@samsung.com> Signed-off-by: Ravishankar N <ravi.n1@samsung.com> Signed-off-by: Amit Sahrawat <a.sahrawat@samsung.com> Acked-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
		
							parent
							
								
									e22a444275
								
							
						
					
					
						commit
						ea3983ace6
					
				
					 5 changed files with 147 additions and 20 deletions
				
			
		|  | @ -406,12 +406,8 @@ int fat_cache_init(void); | ||||||
| void fat_cache_destroy(void); | void fat_cache_destroy(void); | ||||||
| 
 | 
 | ||||||
| /* fat/nfs.c */ | /* fat/nfs.c */ | ||||||
| struct fid; | extern const struct export_operations fat_export_ops; | ||||||
| extern struct dentry *fat_fh_to_dentry(struct super_block *sb, struct fid *fid, | extern const struct export_operations fat_export_ops_nostale; | ||||||
| 				       int fh_len, int fh_type); |  | ||||||
| extern struct dentry *fat_fh_to_parent(struct super_block *sb, struct fid *fid, |  | ||||||
| 				       int fh_len, int fh_type); |  | ||||||
| extern struct dentry *fat_get_parent(struct dentry *child_dir); |  | ||||||
| 
 | 
 | ||||||
| /* helper for printk */ | /* helper for printk */ | ||||||
| typedef unsigned long long	llu; | typedef unsigned long long	llu; | ||||||
|  |  | ||||||
|  | @ -306,6 +306,11 @@ int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | ||||||
| 	struct inode *inode = dentry->d_inode; | 	struct inode *inode = dentry->d_inode; | ||||||
| 	generic_fillattr(inode, stat); | 	generic_fillattr(inode, stat); | ||||||
| 	stat->blksize = MSDOS_SB(inode->i_sb)->cluster_size; | 	stat->blksize = MSDOS_SB(inode->i_sb)->cluster_size; | ||||||
|  | 
 | ||||||
|  | 	if (MSDOS_SB(inode->i_sb)->options.nfs == FAT_NFS_NOSTALE_RO) { | ||||||
|  | 		/* Use i_pos for ino. This is used as fileid of nfs. */ | ||||||
|  | 		stat->ino = fat_i_pos_read(MSDOS_SB(inode->i_sb), inode); | ||||||
|  | 	} | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(fat_getattr); | EXPORT_SYMBOL_GPL(fat_getattr); | ||||||
|  |  | ||||||
|  | @ -18,7 +18,6 @@ | ||||||
| #include <linux/pagemap.h> | #include <linux/pagemap.h> | ||||||
| #include <linux/mpage.h> | #include <linux/mpage.h> | ||||||
| #include <linux/buffer_head.h> | #include <linux/buffer_head.h> | ||||||
| #include <linux/exportfs.h> |  | ||||||
| #include <linux/mount.h> | #include <linux/mount.h> | ||||||
| #include <linux/vfs.h> | #include <linux/vfs.h> | ||||||
| #include <linux/parser.h> | #include <linux/parser.h> | ||||||
|  | @ -748,12 +747,6 @@ static const struct super_operations fat_sops = { | ||||||
| 	.show_options	= fat_show_options, | 	.show_options	= fat_show_options, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static const struct export_operations fat_export_ops = { |  | ||||||
| 	.fh_to_dentry	= fat_fh_to_dentry, |  | ||||||
| 	.fh_to_parent	= fat_fh_to_parent, |  | ||||||
| 	.get_parent	= fat_get_parent, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| static int fat_show_options(struct seq_file *m, struct dentry *root) | static int fat_show_options(struct seq_file *m, struct dentry *root) | ||||||
| { | { | ||||||
| 	struct msdos_sb_info *sbi = MSDOS_SB(root->d_sb); | 	struct msdos_sb_info *sbi = MSDOS_SB(root->d_sb); | ||||||
|  | @ -1177,8 +1170,10 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat, | ||||||
| 		opts->allow_utime = ~opts->fs_dmask & (S_IWGRP | S_IWOTH); | 		opts->allow_utime = ~opts->fs_dmask & (S_IWGRP | S_IWOTH); | ||||||
| 	if (opts->unicode_xlate) | 	if (opts->unicode_xlate) | ||||||
| 		opts->utf8 = 0; | 		opts->utf8 = 0; | ||||||
| 	if (opts->nfs == FAT_NFS_NOSTALE_RO) | 	if (opts->nfs == FAT_NFS_NOSTALE_RO) { | ||||||
| 		sb->s_flags |= MS_RDONLY; | 		sb->s_flags |= MS_RDONLY; | ||||||
|  | 		sb->s_export_op = &fat_export_ops_nostale; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | @ -1189,7 +1184,7 @@ static int fat_read_root(struct inode *inode) | ||||||
| 	struct msdos_sb_info *sbi = MSDOS_SB(sb); | 	struct msdos_sb_info *sbi = MSDOS_SB(sb); | ||||||
| 	int error; | 	int error; | ||||||
| 
 | 
 | ||||||
| 	MSDOS_I(inode)->i_pos = 0; | 	MSDOS_I(inode)->i_pos = MSDOS_ROOT_INO; | ||||||
| 	inode->i_uid = sbi->options.fs_uid; | 	inode->i_uid = sbi->options.fs_uid; | ||||||
| 	inode->i_gid = sbi->options.fs_gid; | 	inode->i_gid = sbi->options.fs_gid; | ||||||
| 	inode->i_version++; | 	inode->i_version++; | ||||||
|  |  | ||||||
							
								
								
									
										130
									
								
								fs/fat/nfs.c
									
									
									
									
									
								
							
							
						
						
									
										130
									
								
								fs/fat/nfs.c
									
									
									
									
									
								
							|  | @ -14,6 +14,18 @@ | ||||||
| #include <linux/exportfs.h> | #include <linux/exportfs.h> | ||||||
| #include "fat.h" | #include "fat.h" | ||||||
| 
 | 
 | ||||||
|  | struct fat_fid { | ||||||
|  | 	u32 i_gen; | ||||||
|  | 	u32 i_pos_low; | ||||||
|  | 	u16 i_pos_hi; | ||||||
|  | 	u16 parent_i_pos_hi; | ||||||
|  | 	u32 parent_i_pos_low; | ||||||
|  | 	u32 parent_i_gen; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #define FAT_FID_SIZE_WITHOUT_PARENT 3 | ||||||
|  | #define FAT_FID_SIZE_WITH_PARENT (sizeof(struct fat_fid)/sizeof(u32)) | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Look up a directory inode given its starting cluster. |  * Look up a directory inode given its starting cluster. | ||||||
|  */ |  */ | ||||||
|  | @ -38,8 +50,8 @@ static struct inode *fat_dget(struct super_block *sb, int i_logstart) | ||||||
| 	return inode; | 	return inode; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static struct inode *fat_nfs_get_inode(struct super_block *sb, | static struct inode *__fat_nfs_get_inode(struct super_block *sb, | ||||||
| 				       u64 ino, u32 generation) | 				       u64 ino, u32 generation, loff_t i_pos) | ||||||
| { | { | ||||||
| 	struct inode *inode; | 	struct inode *inode; | ||||||
| 
 | 
 | ||||||
|  | @ -55,35 +67,130 @@ static struct inode *fat_nfs_get_inode(struct super_block *sb, | ||||||
| 	return inode; | 	return inode; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static struct inode *fat_nfs_get_inode(struct super_block *sb, | ||||||
|  | 				       u64 ino, u32 generation) | ||||||
|  | { | ||||||
|  | 
 | ||||||
|  | 	return __fat_nfs_get_inode(sb, ino, generation, 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int | ||||||
|  | fat_encode_fh_nostale(struct inode *inode, __u32 *fh, int *lenp, | ||||||
|  | 		      struct inode *parent) | ||||||
|  | { | ||||||
|  | 	int len = *lenp; | ||||||
|  | 	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | ||||||
|  | 	struct fat_fid *fid = (struct fat_fid *) fh; | ||||||
|  | 	loff_t i_pos; | ||||||
|  | 	int type = FILEID_FAT_WITHOUT_PARENT; | ||||||
|  | 
 | ||||||
|  | 	if (parent) { | ||||||
|  | 		if (len < FAT_FID_SIZE_WITH_PARENT) { | ||||||
|  | 			*lenp = FAT_FID_SIZE_WITH_PARENT; | ||||||
|  | 			return FILEID_INVALID; | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		if (len < FAT_FID_SIZE_WITHOUT_PARENT) { | ||||||
|  | 			*lenp = FAT_FID_SIZE_WITHOUT_PARENT; | ||||||
|  | 			return FILEID_INVALID; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	i_pos = fat_i_pos_read(sbi, inode); | ||||||
|  | 	*lenp = FAT_FID_SIZE_WITHOUT_PARENT; | ||||||
|  | 	fid->i_gen = inode->i_generation; | ||||||
|  | 	fid->i_pos_low = i_pos & 0xFFFFFFFF; | ||||||
|  | 	fid->i_pos_hi = (i_pos >> 32) & 0xFFFF; | ||||||
|  | 	if (parent) { | ||||||
|  | 		i_pos = fat_i_pos_read(sbi, parent); | ||||||
|  | 		fid->parent_i_pos_hi = (i_pos >> 32) & 0xFFFF; | ||||||
|  | 		fid->parent_i_pos_low = i_pos & 0xFFFFFFFF; | ||||||
|  | 		fid->parent_i_gen = parent->i_generation; | ||||||
|  | 		type = FILEID_FAT_WITH_PARENT; | ||||||
|  | 		*lenp = FAT_FID_SIZE_WITH_PARENT; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return type; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Map a NFS file handle to a corresponding dentry. |  * Map a NFS file handle to a corresponding dentry. | ||||||
|  * The dentry may or may not be connected to the filesystem root. |  * The dentry may or may not be connected to the filesystem root. | ||||||
|  */ |  */ | ||||||
| struct dentry *fat_fh_to_dentry(struct super_block *sb, struct fid *fid, | static struct dentry *fat_fh_to_dentry(struct super_block *sb, struct fid *fid, | ||||||
| 				int fh_len, int fh_type) | 				int fh_len, int fh_type) | ||||||
| { | { | ||||||
| 	return generic_fh_to_dentry(sb, fid, fh_len, fh_type, | 	return generic_fh_to_dentry(sb, fid, fh_len, fh_type, | ||||||
| 				    fat_nfs_get_inode); | 				    fat_nfs_get_inode); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static struct dentry *fat_fh_to_dentry_nostale(struct super_block *sb, | ||||||
|  | 					       struct fid *fh, int fh_len, | ||||||
|  | 					       int fh_type) | ||||||
|  | { | ||||||
|  | 	struct inode *inode = NULL; | ||||||
|  | 	struct fat_fid *fid = (struct fat_fid *)fh; | ||||||
|  | 	loff_t i_pos; | ||||||
|  | 
 | ||||||
|  | 	switch (fh_type) { | ||||||
|  | 	case FILEID_FAT_WITHOUT_PARENT: | ||||||
|  | 		if (fh_len < FAT_FID_SIZE_WITHOUT_PARENT) | ||||||
|  | 			return NULL; | ||||||
|  | 		break; | ||||||
|  | 	case FILEID_FAT_WITH_PARENT: | ||||||
|  | 		if (fh_len < FAT_FID_SIZE_WITH_PARENT) | ||||||
|  | 			return NULL; | ||||||
|  | 		break; | ||||||
|  | 	default: | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	i_pos = fid->i_pos_hi; | ||||||
|  | 	i_pos = (i_pos << 32) | (fid->i_pos_low); | ||||||
|  | 	inode = __fat_nfs_get_inode(sb, 0, fid->i_gen, i_pos); | ||||||
|  | 
 | ||||||
|  | 	return d_obtain_alias(inode); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Find the parent for a file specified by NFS handle. |  * Find the parent for a file specified by NFS handle. | ||||||
|  * This requires that the handle contain the i_ino of the parent. |  * This requires that the handle contain the i_ino of the parent. | ||||||
|  */ |  */ | ||||||
| struct dentry *fat_fh_to_parent(struct super_block *sb, struct fid *fid, | static struct dentry *fat_fh_to_parent(struct super_block *sb, struct fid *fid, | ||||||
| 				int fh_len, int fh_type) | 				int fh_len, int fh_type) | ||||||
| { | { | ||||||
| 	return generic_fh_to_parent(sb, fid, fh_len, fh_type, | 	return generic_fh_to_parent(sb, fid, fh_len, fh_type, | ||||||
| 				    fat_nfs_get_inode); | 				    fat_nfs_get_inode); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static struct dentry *fat_fh_to_parent_nostale(struct super_block *sb, | ||||||
|  | 					       struct fid *fh, int fh_len, | ||||||
|  | 					       int fh_type) | ||||||
|  | { | ||||||
|  | 	struct inode *inode = NULL; | ||||||
|  | 	struct fat_fid *fid = (struct fat_fid *)fh; | ||||||
|  | 	loff_t i_pos; | ||||||
|  | 
 | ||||||
|  | 	if (fh_len < FAT_FID_SIZE_WITH_PARENT) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	switch (fh_type) { | ||||||
|  | 	case FILEID_FAT_WITH_PARENT: | ||||||
|  | 		i_pos = fid->parent_i_pos_hi; | ||||||
|  | 		i_pos = (i_pos << 32) | (fid->parent_i_pos_low); | ||||||
|  | 		inode = __fat_nfs_get_inode(sb, 0, fid->parent_i_gen, i_pos); | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return d_obtain_alias(inode); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Find the parent for a directory that is not currently connected to |  * Find the parent for a directory that is not currently connected to | ||||||
|  * the filesystem root. |  * the filesystem root. | ||||||
|  * |  * | ||||||
|  * On entry, the caller holds child_dir->d_inode->i_mutex. |  * On entry, the caller holds child_dir->d_inode->i_mutex. | ||||||
|  */ |  */ | ||||||
| struct dentry *fat_get_parent(struct dentry *child_dir) | static struct dentry *fat_get_parent(struct dentry *child_dir) | ||||||
| { | { | ||||||
| 	struct super_block *sb = child_dir->d_sb; | 	struct super_block *sb = child_dir->d_sb; | ||||||
| 	struct buffer_head *bh = NULL; | 	struct buffer_head *bh = NULL; | ||||||
|  | @ -98,3 +205,16 @@ struct dentry *fat_get_parent(struct dentry *child_dir) | ||||||
| 
 | 
 | ||||||
| 	return d_obtain_alias(parent_inode); | 	return d_obtain_alias(parent_inode); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | const struct export_operations fat_export_ops = { | ||||||
|  | 	.fh_to_dentry   = fat_fh_to_dentry, | ||||||
|  | 	.fh_to_parent   = fat_fh_to_parent, | ||||||
|  | 	.get_parent     = fat_get_parent, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const struct export_operations fat_export_ops_nostale = { | ||||||
|  | 	.encode_fh      = fat_encode_fh_nostale, | ||||||
|  | 	.fh_to_dentry   = fat_fh_to_dentry_nostale, | ||||||
|  | 	.fh_to_parent   = fat_fh_to_parent_nostale, | ||||||
|  | 	.get_parent     = fat_get_parent, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | @ -84,6 +84,17 @@ enum fid_type { | ||||||
| 	 */ | 	 */ | ||||||
| 	FILEID_NILFS_WITH_PARENT = 0x62, | 	FILEID_NILFS_WITH_PARENT = 0x62, | ||||||
| 
 | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * 32 bit generation number, 40 bit i_pos. | ||||||
|  | 	 */ | ||||||
|  | 	FILEID_FAT_WITHOUT_PARENT = 0x71, | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * 32 bit generation number, 40 bit i_pos, | ||||||
|  | 	 * 32 bit parent generation number, 40 bit parent i_pos | ||||||
|  | 	 */ | ||||||
|  | 	FILEID_FAT_WITH_PARENT = 0x72, | ||||||
|  | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Filesystems must not use 0xff file ID. | 	 * Filesystems must not use 0xff file ID. | ||||||
| 	 */ | 	 */ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Namjae Jeon
						Namjae Jeon