~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/kernfs/mount.c

Version: ~ [ linux-5.8 ] ~ [ linux-5.7.12 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.55 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.136 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.191 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.232 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.232 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * fs/kernfs/mount.c - kernfs mount implementation
  3  *
  4  * Copyright (c) 2001-3 Patrick Mochel
  5  * Copyright (c) 2007 SUSE Linux Products GmbH
  6  * Copyright (c) 2007, 2013 Tejun Heo <tj@kernel.org>
  7  *
  8  * This file is released under the GPLv2.
  9  */
 10 
 11 #include <linux/fs.h>
 12 #include <linux/mount.h>
 13 #include <linux/init.h>
 14 #include <linux/magic.h>
 15 #include <linux/slab.h>
 16 #include <linux/pagemap.h>
 17 
 18 #include "kernfs-internal.h"
 19 
 20 struct kmem_cache *kernfs_node_cache;
 21 
 22 static int kernfs_sop_remount_fs(struct super_block *sb, int *flags, char *data)
 23 {
 24         struct kernfs_root *root = kernfs_info(sb)->root;
 25         struct kernfs_syscall_ops *scops = root->syscall_ops;
 26 
 27         if (scops && scops->remount_fs)
 28                 return scops->remount_fs(root, flags, data);
 29         return 0;
 30 }
 31 
 32 static int kernfs_sop_show_options(struct seq_file *sf, struct dentry *dentry)
 33 {
 34         struct kernfs_root *root = kernfs_root(dentry->d_fsdata);
 35         struct kernfs_syscall_ops *scops = root->syscall_ops;
 36 
 37         if (scops && scops->show_options)
 38                 return scops->show_options(sf, root);
 39         return 0;
 40 }
 41 
 42 const struct super_operations kernfs_sops = {
 43         .statfs         = simple_statfs,
 44         .drop_inode     = generic_delete_inode,
 45         .evict_inode    = kernfs_evict_inode,
 46 
 47         .remount_fs     = kernfs_sop_remount_fs,
 48         .show_options   = kernfs_sop_show_options,
 49 };
 50 
 51 /**
 52  * kernfs_root_from_sb - determine kernfs_root associated with a super_block
 53  * @sb: the super_block in question
 54  *
 55  * Return the kernfs_root associated with @sb.  If @sb is not a kernfs one,
 56  * %NULL is returned.
 57  */
 58 struct kernfs_root *kernfs_root_from_sb(struct super_block *sb)
 59 {
 60         if (sb->s_op == &kernfs_sops)
 61                 return kernfs_info(sb)->root;
 62         return NULL;
 63 }
 64 
 65 static int kernfs_fill_super(struct super_block *sb, unsigned long magic)
 66 {
 67         struct kernfs_super_info *info = kernfs_info(sb);
 68         struct inode *inode;
 69         struct dentry *root;
 70 
 71         info->sb = sb;
 72         sb->s_blocksize = PAGE_CACHE_SIZE;
 73         sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
 74         sb->s_magic = magic;
 75         sb->s_op = &kernfs_sops;
 76         sb->s_time_gran = 1;
 77 
 78         /* get root inode, initialize and unlock it */
 79         mutex_lock(&kernfs_mutex);
 80         inode = kernfs_get_inode(sb, info->root->kn);
 81         mutex_unlock(&kernfs_mutex);
 82         if (!inode) {
 83                 pr_debug("kernfs: could not get root inode\n");
 84                 return -ENOMEM;
 85         }
 86 
 87         /* instantiate and link root dentry */
 88         root = d_make_root(inode);
 89         if (!root) {
 90                 pr_debug("%s: could not get root dentry!\n", __func__);
 91                 return -ENOMEM;
 92         }
 93         kernfs_get(info->root->kn);
 94         root->d_fsdata = info->root->kn;
 95         sb->s_root = root;
 96         sb->s_d_op = &kernfs_dops;
 97         return 0;
 98 }
 99 
100 static int kernfs_test_super(struct super_block *sb, void *data)
101 {
102         struct kernfs_super_info *sb_info = kernfs_info(sb);
103         struct kernfs_super_info *info = data;
104 
105         return sb_info->root == info->root && sb_info->ns == info->ns;
106 }
107 
108 static int kernfs_set_super(struct super_block *sb, void *data)
109 {
110         int error;
111         error = set_anon_super(sb, data);
112         if (!error)
113                 sb->s_fs_info = data;
114         return error;
115 }
116 
117 /**
118  * kernfs_super_ns - determine the namespace tag of a kernfs super_block
119  * @sb: super_block of interest
120  *
121  * Return the namespace tag associated with kernfs super_block @sb.
122  */
123 const void *kernfs_super_ns(struct super_block *sb)
124 {
125         struct kernfs_super_info *info = kernfs_info(sb);
126 
127         return info->ns;
128 }
129 
130 /**
131  * kernfs_mount_ns - kernfs mount helper
132  * @fs_type: file_system_type of the fs being mounted
133  * @flags: mount flags specified for the mount
134  * @root: kernfs_root of the hierarchy being mounted
135  * @magic: file system specific magic number
136  * @new_sb_created: tell the caller if we allocated a new superblock
137  * @ns: optional namespace tag of the mount
138  *
139  * This is to be called from each kernfs user's file_system_type->mount()
140  * implementation, which should pass through the specified @fs_type and
141  * @flags, and specify the hierarchy and namespace tag to mount via @root
142  * and @ns, respectively.
143  *
144  * The return value can be passed to the vfs layer verbatim.
145  */
146 struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags,
147                                 struct kernfs_root *root, unsigned long magic,
148                                 bool *new_sb_created, const void *ns)
149 {
150         struct super_block *sb;
151         struct kernfs_super_info *info;
152         int error;
153 
154         info = kzalloc(sizeof(*info), GFP_KERNEL);
155         if (!info)
156                 return ERR_PTR(-ENOMEM);
157 
158         info->root = root;
159         info->ns = ns;
160 
161         sb = sget(fs_type, kernfs_test_super, kernfs_set_super, flags, info);
162         if (IS_ERR(sb) || sb->s_fs_info != info)
163                 kfree(info);
164         if (IS_ERR(sb))
165                 return ERR_CAST(sb);
166 
167         if (new_sb_created)
168                 *new_sb_created = !sb->s_root;
169 
170         if (!sb->s_root) {
171                 struct kernfs_super_info *info = kernfs_info(sb);
172 
173                 error = kernfs_fill_super(sb, magic);
174                 if (error) {
175                         deactivate_locked_super(sb);
176                         return ERR_PTR(error);
177                 }
178                 sb->s_flags |= MS_ACTIVE;
179 
180                 mutex_lock(&kernfs_mutex);
181                 list_add(&info->node, &root->supers);
182                 mutex_unlock(&kernfs_mutex);
183         }
184 
185         return dget(sb->s_root);
186 }
187 
188 /**
189  * kernfs_kill_sb - kill_sb for kernfs
190  * @sb: super_block being killed
191  *
192  * This can be used directly for file_system_type->kill_sb().  If a kernfs
193  * user needs extra cleanup, it can implement its own kill_sb() and call
194  * this function at the end.
195  */
196 void kernfs_kill_sb(struct super_block *sb)
197 {
198         struct kernfs_super_info *info = kernfs_info(sb);
199         struct kernfs_node *root_kn = sb->s_root->d_fsdata;
200 
201         mutex_lock(&kernfs_mutex);
202         list_del(&info->node);
203         mutex_unlock(&kernfs_mutex);
204 
205         /*
206          * Remove the superblock from fs_supers/s_instances
207          * so we can't find it, before freeing kernfs_super_info.
208          */
209         kill_anon_super(sb);
210         kfree(info);
211         kernfs_put(root_kn);
212 }
213 
214 /**
215  * kernfs_pin_sb: try to pin the superblock associated with a kernfs_root
216  * @kernfs_root: the kernfs_root in question
217  * @ns: the namespace tag
218  *
219  * Pin the superblock so the superblock won't be destroyed in subsequent
220  * operations.  This can be used to block ->kill_sb() which may be useful
221  * for kernfs users which dynamically manage superblocks.
222  *
223  * Returns NULL if there's no superblock associated to this kernfs_root, or
224  * -EINVAL if the superblock is being freed.
225  */
226 struct super_block *kernfs_pin_sb(struct kernfs_root *root, const void *ns)
227 {
228         struct kernfs_super_info *info;
229         struct super_block *sb = NULL;
230 
231         mutex_lock(&kernfs_mutex);
232         list_for_each_entry(info, &root->supers, node) {
233                 if (info->ns == ns) {
234                         sb = info->sb;
235                         if (!atomic_inc_not_zero(&info->sb->s_active))
236                                 sb = ERR_PTR(-EINVAL);
237                         break;
238                 }
239         }
240         mutex_unlock(&kernfs_mutex);
241         return sb;
242 }
243 
244 void __init kernfs_init(void)
245 {
246         kernfs_node_cache = kmem_cache_create("kernfs_node_cache",
247                                               sizeof(struct kernfs_node),
248                                               0, SLAB_PANIC, NULL);
249         kernfs_inode_init();
250 }
251 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp