📄 base.c
字号:
time_t ctime; unsigned int ino; /* Inode number as seen in the VFS */ uid_t uid; gid_t gid;};struct devfs_entry{#ifdef CONFIG_DEVFS_DEBUG unsigned int magic_number;#endif void *info; atomic_t refcount; /* When this drops to zero, it's unused */ union { struct directory_type dir; struct fcb_type fcb; struct symlink_type symlink; const char *name; /* Only used for (mode == 0) */ } u; struct devfs_entry *prev; /* Previous entry in the parent directory */ struct devfs_entry *next; /* Next entry in the parent directory */ struct devfs_entry *parent; /* The parent directory */ struct devfs_entry *slave; /* Another entry to unregister */ struct devfs_inode inode; umode_t mode; unsigned short namelen; /* I think 64k+ filenames are a way off... */ unsigned char hide:1; unsigned char vfs_deletable:1;/* Whether the VFS may delete the entry */ char name[1]; /* This is just a dummy: the allocated array is bigger. This is NULL-terminated */};/* The root of the device tree */static struct devfs_entry *root_entry;struct devfsd_buf_entry{ struct devfs_entry *de; /* The name is generated with this */ unsigned short type; /* The type of event */ umode_t mode; uid_t uid; gid_t gid; struct devfsd_buf_entry *next;};struct fs_info /* This structure is for the mounted devfs */{ struct super_block *sb; spinlock_t devfsd_buffer_lock; /* Lock when inserting/deleting events */ struct devfsd_buf_entry *devfsd_first_event; struct devfsd_buf_entry *devfsd_last_event; volatile int devfsd_sleeping; volatile struct task_struct *devfsd_task; volatile pid_t devfsd_pgrp; volatile struct file *devfsd_file; struct devfsd_notify_struct *devfsd_info; volatile unsigned long devfsd_event_mask; atomic_t devfsd_overrun_count; wait_queue_head_t devfsd_wait_queue; /* Wake devfsd on input */ wait_queue_head_t revalidate_wait_queue; /* Wake when devfsd sleeps */};static struct fs_info fs_info = {devfsd_buffer_lock: SPIN_LOCK_UNLOCKED};static kmem_cache_t *devfsd_buf_cache;#ifdef CONFIG_DEVFS_DEBUGstatic unsigned int devfs_debug_init __initdata = DEBUG_NONE;static unsigned int devfs_debug = DEBUG_NONE;static spinlock_t stat_lock = SPIN_LOCK_UNLOCKED;static unsigned int stat_num_entries;static unsigned int stat_num_bytes;#endifstatic unsigned char poison_array[8] = {0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a};#ifdef CONFIG_DEVFS_MOUNTstatic unsigned int boot_options = OPTION_MOUNT;#elsestatic unsigned int boot_options = OPTION_NONE;#endif/* Forward function declarations */static devfs_handle_t _devfs_walk_path (struct devfs_entry *dir, const char *name, int namelen, int traverse_symlink);static ssize_t devfsd_read (struct file *file, char *buf, size_t len, loff_t *ppos);static int devfsd_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);static int devfsd_close (struct inode *inode, struct file *file);#ifdef CONFIG_DEVFS_DEBUGstatic int stat_read (struct file *file, char *buf, size_t len, loff_t *ppos);static struct file_operations stat_fops ={ read: stat_read,};#endif/* Devfs daemon file operations */static struct file_operations devfsd_fops ={ read: devfsd_read, ioctl: devfsd_ioctl, release: devfsd_close,};/* Support functions follow *//** * devfs_get - Get a reference to a devfs entry. * @de: The devfs entry. */static struct devfs_entry *devfs_get (struct devfs_entry *de){ VERIFY_ENTRY (de); if (de) atomic_inc (&de->refcount); return de;} /* End Function devfs_get *//** * devfs_put - Put (release) a reference to a devfs entry. * @de: The handle to the devfs entry. */void devfs_put (devfs_handle_t de){ if (!de) return; VERIFY_ENTRY (de); if (de->info == POISON_PTR) OOPS ("(%p): poisoned pointer\n", de); if ( !atomic_dec_and_test (&de->refcount) ) return; if (de == root_entry) OOPS ("(%p): root entry being freed\n", de); DPRINTK (DEBUG_FREE, "(%s): de: %p, parent: %p \"%s\"\n", de->name, de, de->parent, de->parent ? de->parent->name : "no parent"); if ( S_ISLNK (de->mode) ) kfree (de->u.symlink.linkname); if ( ( S_ISCHR (de->mode) || S_ISBLK (de->mode) ) && de->u.fcb.autogen ) { devfs_dealloc_devnum ( S_ISCHR (de->mode) ? DEVFS_SPECIAL_CHR : DEVFS_SPECIAL_BLK, mk_kdev (de->u.fcb.u.device.major, de->u.fcb.u.device.minor) ); } WRITE_ENTRY_MAGIC (de, 0);#ifdef CONFIG_DEVFS_DEBUG spin_lock (&stat_lock); --stat_num_entries; stat_num_bytes -= sizeof *de + de->namelen; if ( S_ISLNK (de->mode) ) stat_num_bytes -= de->u.symlink.length + 1; spin_unlock (&stat_lock);#endif de->info = POISON_PTR; kfree (de);} /* End Function devfs_put *//** * _devfs_search_dir - Search for a devfs entry in a directory. * @dir: The directory to search. * @name: The name of the entry to search for. * @namelen: The number of characters in @name. * * Search for a devfs entry in a directory and returns a pointer to the entry * on success, else %NULL. The directory must be locked already. * An implicit devfs_get() is performed on the returned entry. */static struct devfs_entry *_devfs_search_dir (struct devfs_entry *dir, const char *name, unsigned int namelen){ struct devfs_entry *curr; if ( !S_ISDIR (dir->mode) ) { PRINTK ("(%s): not a directory\n", dir->name); return NULL; } for (curr = dir->u.dir.first; curr != NULL; curr = curr->next) { if (curr->namelen != namelen) continue; if (memcmp (curr->name, name, namelen) == 0) break; /* Not found: try the next one */ } return devfs_get (curr);} /* End Function _devfs_search_dir *//** * _devfs_alloc_entry - Allocate a devfs entry. * @name: The name of the entry. * @namelen: The number of characters in @name. * * Allocate a devfs entry and returns a pointer to the entry on success, else * %NULL. */static struct devfs_entry *_devfs_alloc_entry (const char *name, unsigned int namelen, umode_t mode){ struct devfs_entry *new; static unsigned long inode_counter = FIRST_INODE; static spinlock_t counter_lock = SPIN_LOCK_UNLOCKED; if ( name && (namelen < 1) ) namelen = strlen (name); if ( ( new = kmalloc (sizeof *new + namelen, GFP_KERNEL) ) == NULL ) return NULL; memset (new, 0, sizeof *new + namelen); /* Will set '\0' on name */ new->mode = mode; if ( S_ISDIR (mode) ) rwlock_init (&new->u.dir.lock); atomic_set (&new->refcount, 1); spin_lock (&counter_lock); new->inode.ino = inode_counter++; spin_unlock (&counter_lock); if (name) memcpy (new->name, name, namelen); new->namelen = namelen; WRITE_ENTRY_MAGIC (new, MAGIC_VALUE);#ifdef CONFIG_DEVFS_DEBUG spin_lock (&stat_lock); ++stat_num_entries; stat_num_bytes += sizeof *new + namelen; spin_unlock (&stat_lock);#endif return new;} /* End Function _devfs_alloc_entry *//** * _devfs_append_entry - Append a devfs entry to a directory's child list. * @dir: The directory to add to. * @de: The devfs entry to append. * @removable: If TRUE, increment the count of removable devices for %dir. * @old_de: If an existing entry exists, it will be written here. This may * be %NULL. An implicit devfs_get() is performed on this entry. * * Append a devfs entry to a directory's list of children, checking first to * see if an entry of the same name exists. The directory will be locked. * The value 0 is returned on success, else a negative error code. * On failure, an implicit devfs_put() is performed on %de. */static int _devfs_append_entry (devfs_handle_t dir, devfs_handle_t de, int removable, devfs_handle_t *old_de){ int retval; if (old_de) *old_de = NULL; if ( !S_ISDIR (dir->mode) ) { PRINTK ("(%s): dir: \"%s\" is not a directory\n", de->name, dir->name); devfs_put (de); return -ENOTDIR; } write_lock (&dir->u.dir.lock); if (dir->u.dir.no_more_additions) retval = -ENOENT; else { struct devfs_entry *old; old = _devfs_search_dir (dir, de->name, de->namelen); if (old_de) *old_de = old; else devfs_put (old); if (old == NULL) { de->parent = dir; de->prev = dir->u.dir.last; /* Append to the directory's list of children */ if (dir->u.dir.first == NULL) dir->u.dir.first = de; else dir->u.dir.last->next = de; dir->u.dir.last = de; if (removable) ++dir->u.dir.num_removable; retval = 0; } else retval = -EEXIST; } write_unlock (&dir->u.dir.lock); if (retval) devfs_put (de); return retval;} /* End Function _devfs_append_entry *//** * _devfs_get_root_entry - Get the root devfs entry. * * Returns the root devfs entry on success, else %NULL. */static struct devfs_entry *_devfs_get_root_entry (void){ kdev_t devnum; struct devfs_entry *new; static spinlock_t root_lock = SPIN_LOCK_UNLOCKED; /* Always ensure the root is created */ if (root_entry) return root_entry; if ( ( new = _devfs_alloc_entry (NULL, 0,MODE_DIR) ) == NULL ) return NULL; spin_lock (&root_lock); if (root_entry) { spin_unlock (&root_lock); devfs_put (new); return (root_entry); } root_entry = new; spin_unlock (&root_lock); /* And create the entry for ".devfsd" */ if ( ( new = _devfs_alloc_entry (".devfsd", 0, S_IFCHR |S_IRUSR |S_IWUSR) ) == NULL ) return NULL; devnum = devfs_alloc_devnum (DEVFS_SPECIAL_CHR); new->u.fcb.u.device.major = major (devnum); new->u.fcb.u.device.minor = minor (devnum); new->u.fcb.ops = &devfsd_fops; _devfs_append_entry (root_entry, new, FALSE, NULL);#ifdef CONFIG_DEVFS_DEBUG if ( ( new = _devfs_alloc_entry (".stat", 0, S_IFCHR | S_IRUGO | S_IWUGO) ) == NULL ) return NULL; devnum = devfs_alloc_devnum (DEVFS_SPECIAL_CHR); new->u.fcb.u.device.major = major (devnum); new->u.fcb.u.device.minor = minor (devnum); new->u.fcb.ops = &stat_fops; _devfs_append_entry (root_entry, new, FALSE, NULL);#endif return root_entry;} /* End Function _devfs_get_root_entry *//** * _devfs_descend - Descend down a tree using the next component name. * @dir: The directory to search. * @name: The component name to search for. * @namelen: The length of %name. * @next_pos: The position of the next '/' or '\0' is written here. * * Descend into a directory, searching for a component. This function forms * the core of a tree-walking algorithm. The directory will be locked. * The devfs entry corresponding to the component is returned. If there is * no matching entry, %NULL is returned. * An implicit devfs_get() is performed on the returned entry. */static struct devfs_entry *_devfs_descend (struct devfs_entry *dir, const char *name, int namelen, int *next_pos){ const char *stop, *ptr; struct devfs_entry *entry; if ( (namelen >= 3) && (strncmp (name, "../", 3) == 0) ) { /* Special-case going to parent directory */ *next_pos = 3; return devfs_get (dir->parent); } stop = name + namelen; /* Search for a possible '/' */ for (ptr = name; (ptr < stop) && (*ptr != '/'); ++ptr); *next_pos = ptr - name; read_lock (&dir->u.dir.lock); entry = _devfs_search_dir (dir, name, *next_pos); read_unlock (&dir->u.dir.lock); return entry;} /* End Function _devfs_descend */static devfs_handle_t _devfs_make_parent_for_leaf (struct devfs_entry *dir, const char *name, int namelen, int *leaf_pos){ int next_pos = 0; if (dir == NULL) dir = _devfs_get_root_entry (); if (dir == NULL) return NULL; devfs_get (dir); /* Search for possible trailing component and ignore it */ for (--namelen; (namelen > 0) && (name[namelen] != '/'); --namelen);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -