sys_open analysis, find the file from the file name information

2011-06-23  来源:本站原创  分类:OS  人气:113 

http://blog.csdn.net/air_snake/archive/2008/07/22/2690554.aspx

Find the file information from the file name (namei)

This document Copyleft owned yfydz all use under the GPL, can be freely copied, reproduced, reprinted, please maintain the integrity of the document, for any commercial purposes is strictly prohibited.
MSN: [email protected]
Source: http://yfydz.cublog.cn

1 Introduction

inode is a Unix-like file system, basic indexing method, each file corresponds to an inode, and then find the file by inode actual data, therefore, according to the specific file path name to find the inode node is a very important processing steps. The system used in each cache file or directory corresponding to the dentry structure from the structure can point to the corresponding inode, each time you open the file, the file will eventually correspond to the inode, find the middle of the process known as namei.

This article describes the path to a file under Linux pointer conversion process, the kernel version is 2.6.19.2.

Conversion of the virtual file system source code in fs / namei.c, specific and relevant part of the file system in fs / * / namei.c file.

2 Introduction

Because of this conversion is an intermediate process in the specific analysis namei process before the system call sequence to see how to enter the conversion:
When a user space program using the open system call to open a file, the kernel corresponding treatment is sys_open:
/ * Fs / open.c * /
asmlinkage long sys_open (const char __user * filename, int flags, int mode)
{
long ret;
if (force_o_largefile ())
flags | = O_LARGEFILE;
ret = do_sys_open (AT_FDCWD, filename, flags, mode);
/ * Avoid REGPARM breakage on x86: * /
prevent_tail_call (ret);
return ret;
}
The real open function is do_sys_open:
/ * Fs / open.c * /
/ / Dfd of AT_FDCWD
long do_sys_open (int dfd, const char __user * filename, int flags, int mode)
{
/ / Function to user space through the file name passed to the kernel
/ / Tmp is a class of dynamic cache memory, to save the file path name
/ /
char * tmp = getname (filename);
int fd = PTR_ERR (tmp);
if (! IS_ERR (tmp)) {
/ / Get a file descriptor is not used, and has nothing to do inode
fd = get_unused_fd ();
if (fd> = 0) {
/ / Open the file, the file name into a file structure
struct file * f = do_filp_open (dfd, tmp, flags, mode);
if (IS_ERR (f)) {
put_unused_fd (fd);
fd = PTR_ERR (f);
} Else {
fsnotify_open (f-> f_dentry);
fd_install (fd, f);
}
}
putname (tmp);
}
return fd;
}

/ / File Open
static struct file * do_filp_open (int dfd, const char * filename, int flags,
int mode)
{
int namei_flags, error;
/ / Note that this is a structural rather than a pointer
struct nameidata nd;
namei_flags = flags;
if ((namei_flags +1) & O_ACCMODE)
namei_flags + +;
/ / According to the file name to be nameidata, nd space to save the results as namei
error = open_namei (dfd, filename, namei_flags, mode, & nd);
if (! error)
/ / Success, nameidata file pointer and then converted to
return nameidata_to_filp (& nd, flags);
return ERR_PTR (error);
}

Therefore, the function key function is open_namei realized from the file name to inode conversion, the processing is namei entrance.

In the analysis open_namei ago, and then analyze getname, which uses kmem_cache to deal with:
/ / File name conversion, copy from user space to kernel space
/ * Fs / namei.c * /
char * getname (const char __user * filename)
{
char * tmp, * result;
result = ERR_PTR (-ENOMEM);
/ * Include / linux / fs.h * /
/ / __getname And __putname definition is in fact a kernel cache allocation and release
/ / # Define __getname () kmem_cache_alloc (names_cachep, SLAB_KERNEL)
/ / # Define __putname (name) kmem_cache_free (names_cachep, (void *) (name))
/ / Here is the actual distribution of names of the cache, the cache is defined as
/ / Names_cachep = kmem_cache_create ("names_cache", PATH_MAX, 0,
/ / SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL, NULL);
tmp = __getname ();
if (tmp) {
/ / Cache allocation success
/ / Function to enter the actual operation
int retval = do_getname (filename, tmp);
/ / To return to the results point to the cache
result = tmp;
if (retval <0) {
/ / Fails, the release of cache, return an error
__putname (tmp);
result = ERR_PTR (retval);
}
}
/ / Compile the kernel if not set CONFIG_AUDITSYSCALL, then audit_getname is empty
/ / Audit the results of system calls
audit_getname (result);
return result;
}

static int do_getname (const char __user * filename, char * page)
{
int retval;
unsigned long len = PATH_MAX;
if (! segment_eq (get_fs (), KERNEL_DS)) {
if ((unsigned long) filename> = TASK_SIZE)
return-EFAULT;
if (TASK_SIZE - (unsigned long) filename <PATH_MAX)
len = TASK_SIZE - (unsigned long) filename;
}
/ / User space copy provided to the cache file name
retval = strncpy_from_user (page, filename, len);
if (retval> 0) {
if (retval <len)
return 0;
return-ENAMETOOLONG;
} Else if (! Retval)
retval =-ENOENT;
return retval;
}

3. Namei data structure
/ * Include / linux / namei.h * /
struct nameidata {
/ / Path points
struct dentry * dentry;
/ / Virtual system mount point
struct vfsmount * mnt;
/ / Path name of the last file or directory name
struct qstr last;
unsigned int flags;
int last_type;
/ / Directory depth
unsigned depth;
char * saved_names [MAX_NESTED_LINKS + 1]; / / 9
/ * Intent data * /
/ / Data
union {
/ / Open a file that contains a pointer
struct open_intent open;
} Intent;
};

struct open_intent {
/ / Sign
int flags;
/ / Create mode
int create_mode;
/ / File pointer
struct file * file;
};

/ / Path structure, belonging to the middle of processing structure, the file system mount points and tied it dentry
struct path {
struct vfsmount * mnt;
struct dentry * dentry;
};

/ * Include / linux / dcache.h * /
/ / File directory entry, the cache in the system
struct dentry {
atomic_t d_count;
unsigned int d_flags; / * protected by d_lock * /
spinlock_t d_lock; / * per dentry lock * /
struct inode * d_inode; / * Where the name belongs to - NULL is
* Negative * /
/ *
* The next three fields are touched by __d_lookup. Place them here
* So they all fit in a cache line.
* /
struct hlist_node d_hash; / * lookup hash list * /
struct dentry * d_parent; / * parent directory * /
struct qstr d_name;
struct list_head d_lru; / * LRU list * /
/ *
* D_child and d_rcu can share memory
* /
union {
struct list_head d_child; / * child of parent list * /
struct rcu_head d_rcu;
} D_u;
struct list_head d_subdirs; / * our children * /
struct list_head d_alias; / * inode alias list * /
unsigned long d_time; / * used by d_revalidate * /
struct dentry_operations * d_op;
struct super_block * d_sb; / * The root of the dentry tree * /
void * d_fsdata; / * fs-specific data * /
# Ifdef CONFIG_PROFILING
struct dcookie_struct * d_cookie; / * cookie, if any * /
# Endif
int d_mounted;
unsigned char d_iname [DNAME_INLINE_LEN_MIN]; / * small names * /
};

/ * Include / linux / fs.h * /
/ / File structure
struct file {
/ *
* Fu_list becomes invalid after file_free is called and queued via
* Fu_rcuhead for RCU freeing
* /
union {
struct list_head fu_list;
struct rcu_head fu_rcuhead;
} F_u;
/ / File's dentry
struct dentry * f_dentry;
/ / Virtual file system mount point
struct vfsmount * f_vfsmnt;
/ / File operations
const struct file_operations * f_op;
atomic_t f_count;
unsigned int f_flags;
mode_t f_mode;
loff_t f_pos;
struct fown_struct f_owner;
unsigned int f_uid, f_gid;
struct file_ra_state f_ra;
unsigned long f_version;
# Ifdef CONFIG_SECURITY
void * f_security;
# Endif
/ * Needed for tty driver, and maybe others * /
void * private_data;
# Ifdef CONFIG_EPOLL
/ * Used by fs / eventpoll.c to link all the hooks to this file * /
struct list_head f_ep_links;
spinlock_t f_ep_lock;
# Endif / * # ifdef CONFIG_EPOLL * /
struct address_space * f_mapping;
};

4. Namei operation

4.1 open_namei

/ * Fs / namei.c * /
/ *
* Open_namei ()
*
* Namei for open - this is in fact almost the whole open-routine.
*
* Note that the low bits of "flag" aren't the same as in the open
* System call - they are 00 - no permissions needed
* 01 - read permission needed
* 10 - write permission needed
* 11 - read / write permissions needed
* Which is a lot more logical, and also allows the "no perm" needed
* For symlinks (where the permissions are checked later).
* SMP-safe
* /
int open_namei (int dfd, const char * pathname, int flag,
int mode, struct nameidata * nd)
{
int acc_mode, error;
struct path path;
struct dentry * dir;
int count = 0;
/ / # Define ACC_MODE (x) ("\ 000 \ 004 \ 002 \ 006" [(x) & O_ACCMODE])
/ / Audit model
acc_mode = ACC_MODE (flag);
/ * O_TRUNC implies we need access checks for write permissions * /
/ / Truncation symbol, basically need to write permission, unless you cut the length of the actual length is greater than the file itself
if (flag & O_TRUNC)
acc_mode | = MAY_WRITE;
/ * Allow the LSM permission hook to distinguish append
access from general write access. * /
/ / Add the logo, but also need write access
if (flag & O_APPEND)
acc_mode | = MAY_APPEND;
/ *
* The simplest case - just a plain lookup.
* /
/ / Do not need to create a file
if (! (flag & O_CREAT)) {
/ / Pathname directly to the dentry and the mount point, fill in the nd the results
error = path_lookup_open (dfd, pathname, lookup_flags (flag),
nd, flag);
if (error)
return error;
goto ok;
}
/ *
* Create - we need to know the parent.
* /
/ / Create a file and mount point dentry, nd in the data to fill
error = path_lookup_create (dfd, pathname, LOOKUP_PARENT, nd, flag, mode);
if (error)
return error;
/ *
* We have the parent and last component. First of all, check
* That we are not asked to creat (2) an obvious directory - that
* Will not do.
* /
error =-EISDIR;
/ / Check nameidata structure of the last parameter is legitimate
if (nd-> last_type! = LAST_NORM | | nd-> last.name [nd-> last.len])
goto exit;
/ / File item dentry
dir = nd-> dentry;
/ / Remove the check mark parent directory
nd-> flags & = ~ LOOKUP_PARENT;
mutex_lock (& ​​dir-> d_inode-> i_mutex);
/ / Fill path parameters, and nd the information search based on a current dentry cache
/ / But not the same dir and path.dentry do it?
path.dentry = lookup_hash (nd);
path.mnt = nd-> mnt;
do_last:
/ / Check the legality of path.entry
error = PTR_ERR (path.dentry);
if (IS_ERR (path.dentry)) {
mutex_unlock (& ​​dir-> d_inode-> i_mutex);
goto exit;
}
/ / Check the nd-> intent.open.file legality, which is ultimately to return the file pointer
if (IS_ERR (nd-> intent.open.file)) {
mutex_unlock (& ​​dir-> d_inode-> i_mutex);
error = PTR_ERR (nd-> intent.open.file);
goto exit_dput;
}
/ * Negative dentry, just create the file * /
if (! path.dentry-> d_inode) {
/ / Create a new file inode, and then return
error = open_namei_create (nd, & path, flag, mode);
if (error)
goto exit;
return 0;
}
/ / Now open the file already exists
/ *
* It already exists.
* /
mutex_unlock (& ​​dir-> d_inode-> i_mutex);
audit_inode_update (path.dentry-> d_inode);
error =-EEXIST;
/ / O_EXCL flag is only to be opened is non-existent file, the file already exists error
if (flag & O_EXCL)
goto exit_dput;
if (__follow_mount (& path)) {
error =-ELOOP;
if (flag & O_NOFOLLOW)
goto exit_dput;
}
error =-ENOENT;
if (! path.dentry-> d_inode)
goto exit_dput;
/ / If the dentry of the concrete implementation of FS is defined follow_link operation, turn
/ / FS, but most implementations do not define the function
if (path.dentry-> d_inode-> i_op & & path.dentry-> d_inode-> i_op-> follow_link)
goto do_link;
/ / From the path assigned to the dentry and mnt information nameidata
path_to_nameidata (& path, nd);
error =-EISDIR;
/ / If a directory, return an error
if (path.dentry-> d_inode & & S_ISDIR (path.dentry-> d_inode-> i_mode))
goto exit;
ok:
/ / For nd in the dentry and inode to open before the error checking
error = may_open (nd, acc_mode, flag);
if (error)
goto exit;
return 0;
/ / Here is error handling, freed the allocated resources, return an error
exit_dput:
dput_path (& path, nd);
exit:
if (! IS_ERR (nd-> intent.open.file))
release_open_intent (nd);
path_release (nd);
return error;
/ / Handle symbolic links, find the actual file inode, and then re-cycle, pay attention to the case of error handling loop
do_link:
error =-ELOOP;
if (flag & O_NOFOLLOW)
goto exit_dput;
/ *
* This is subtle. Instead of calling do_follow_link () we do the
* Thing by hands. The reason is that this way we have zero link_count
* And path_walk () (called from -> follow_link) honoring LOOKUP_PARENT.
* After that we have the parent and last component, ie
* We are in the same situation as after the first path_walk ().
* Well, almost - if the last component is normal we get its copy
* Stored in nd-> last.name and we will have to putname () it when we
* Are done. Procfs-like symlinks just set LAST_BIND.
* /
/ / Set flag to find LOOKUP_PARENT
nd-> flags | = LOOKUP_PARENT;
error = security_inode_follow_link (path.dentry, nd);
if (error)
goto exit_dput;
/ / With symbolic links.
error = __do_follow_link (& path, nd);
if (error) {
/ * Does someone understand code flow here? Or it is only
* Me so stupid? Anathema to whoever designed this non-sense
* With "intent.open".
* /
release_open_intent (nd);
return error;
}
nd-> flags & = ~ LOOKUP_PARENT;
/ / Check the last paragraph of the attributes of a file or directory name case
if (nd-> last_type == LAST_BIND)
goto ok;
error =-EISDIR;
if (nd-> last_type! = LAST_NORM)
goto exit;
if (nd-> last.name [nd-> last.len]) {
__putname (nd-> last.name);
goto exit;
}
error =-ELOOP;
/ / Loop symbol appears: recycling more than 32 times
if (count + + == 32) {
__putname (nd-> last.name);
goto exit;
}
dir = nd-> dentry;
mutex_lock (& ​​dir-> d_inode-> i_mutex);
/ / Update the path of the mount point and dentry
path.dentry = lookup_hash (nd);
path.mnt = nd-> mnt;
__putname (nd-> last.name);
goto do_last;
}

4.2 path_lookup_open and path_lookup_create

These functions find the path name of the corresponding mount point and dentry structure, assignment to nameidata structure, create time if the file does not exist, create a new document:
/ **
* Path_lookup_open - lookup a file path with open intent
* @ Dfd: the directory to use as base, or AT_FDCWD
* @ Name: pointer to file name
* @ Lookup_flags: lookup intent flags
* @ Nd: pointer to nameidata
* @ Open_flags: open intent flags
* /
int path_lookup_open (int dfd, const char * name, unsigned int lookup_flags,
struct nameidata * nd, int open_flags)
{
return __path_lookup_intent_open (dfd, name, lookup_flags, nd,
open_flags, 0);
}

/ **
* Path_lookup_create - lookup a file path with open + create intent
* @ Dfd: the directory to use as base, or AT_FDCWD
* @ Name: pointer to file name
* @ Lookup_flags: lookup intent flags
* @ Nd: pointer to nameidata
* @ Open_flags: open intent flags
* @ Create_mode: create intent flags
* /
static int path_lookup_create (int dfd, const char * name,
unsigned int lookup_flags, struct nameidata * nd,
int open_flags, int create_mode)
{
return __path_lookup_intent_open (dfd, name, lookup_flags | LOOKUP_CREATE,
nd, open_flags, create_mode);
}

These two functions are called __path_lookup_intent_open, but with different parameters, create added LOOKUP_CREATE signs and create_mode:

static int __path_lookup_intent_open (int dfd, const char * name,
unsigned int lookup_flags, struct nameidata * nd,
int open_flags, int create_mode)
{
/ / Find a free file pointer
struct file * filp = get_empty_filp ();
int err;
/ / Not found return an error, a file table overflow
if (filp == NULL)
return-ENFILE;
/ / Fill in nameidate open files in the argument, which is eventually returned file pointer
nd-> intent.open.file = filp;
nd-> intent.open.flags = open_flags;
nd-> intent.open.create_mode = create_mode;
/ / Search for a specific path, name is the path name
err = do_path_lookup (dfd, name, lookup_flags | LOOKUP_OPEN, nd);
/ / Check nd-> intent.open.file not err
if (IS_ERR (nd-> intent.open.file)) {
/ / Open file pointer error
if (err == 0) {
/ / Do_path_lookup has been successful, the release path, err the error value is set to re-
err = PTR_ERR (nd-> intent.open.file);
path_release (nd);
}
} Else if (err! = 0)
release_open_intent (nd);
return err;
}

/ / Find the path
/ * Returns 0 and nd will be valid on success; Retuns error, otherwise. * /
static int fastcall do_path_lookup (int dfd, const char * name,
unsigned int flags, struct nameidata * nd)
{
int retval = 0;
int fput_needed;
struct file * file;
/ / File system to get from the process pointer
struct fs_struct * fs = current-> fs;
/ / Default last_type an absolute path to "/" at the beginning of the format
nd-> last_type = LAST_ROOT; / * if there are only slashes ... * /
nd-> flags = flags;
nd-> depth = 0;
/ / Here are just some of the variables used to increase the use count, get the increase, put to reduce the
if (* name =='/') {
/ / Absolute path format
read_lock (& ​​fs-> lock);
if (fs-> altroot & &! (nd-> flags & LOOKUP_NOALT)) {
/ / Check changed root, which uses chroot
/ / Add altrootmnt use count, which is a structure pointer vfsmount
nd-> mnt = mntget (fs-> altrootmnt);
nd-> dentry = dget (fs-> altroot);
read_unlock (& ​​fs-> lock);
if (__emul_lookup_dentry (name, nd))
goto out; / * found in altroot * /
read_lock (& ​​fs-> lock);
}
/ / Add rootmnt use assigned to count and then nd the
nd-> mnt = mntget (fs-> rootmnt);
/ / Increase the use of the root dentry to nd in the count and then assign
nd-> dentry = dget (fs-> root);
read_unlock (& ​​fs-> lock);
} Else if (dfd == AT_FDCWD) {
/ / From sys_open will call it here, that the path from the current working directory relative path starting
read_lock (& ​​fs-> lock);
/ / Increase the count and then use the assignment to pwdmnt nd in
nd-> mnt = mntget (fs-> pwdmnt);
/ / Increase the count and then use the pwd to nd the assignment
nd-> dentry = dget (fs-> pwd);
read_unlock (& ​​fs-> lock);
} Else {
struct dentry * dentry;
/ / Lightweight Pathfinder, fd is not shared, then the reference count will not increase
file = fget_light (dfd, & fput_needed);
retval =-EBADF;
if (! file)
goto out_fail;
dentry = file-> f_dentry;
retval =-ENOTDIR;
if (! S_ISDIR (dentry-> d_inode-> i_mode))
goto fput_fail;
/ / Check the file execute permission
retval = file_permission (file, MAY_EXEC);
if (retval)
goto fput_fail;
/ / Increase the use count f_vfsmnt
nd-> mnt = mntget (file-> f_vfsmnt);
nd-> dentry = dget (dentry);
/ / Lightweight release
fput_light (file, fput_needed);
}
/ / Clear the total number of links
current-> total_link_count = 0;
/ / Variable path query, the core function
retval = link_path_walk (name, nd);
out:
if (likely (retval == 0)) {
/ / In most cases this will be executed, open the path to the right
if (unlikely (! audit_dummy_context () & & nd & & nd-> dentry & &
nd-> dentry-> d_inode))
audit_inode (name, nd-> dentry-> d_inode);
}
out_fail:
return retval;
fput_fail:
fput_light (file, fput_needed);
goto out_fail;
}

do_path_lookup called core function is link_path_walk:

/ *
* Wrapper to retry pathname resolution whenever the underlying
* File system returns an ESTALE.
*
* Retry the whole path once, forcing real lookup requests
* Instead of relying on the dcache.
* /
int fastcall link_path_walk (const char * name, struct nameidata * nd)
{
/ / Back up what
struct nameidata save = * nd;
int result;
/ * Make sure the stuff we saved doesn't go away * /
dget (save.dentry);
mntget (save.mnt);
result = __link_path_walk (name, nd);
if (result ==-ESTALE) {
/ / ESTALE is invalid file handle error
/ / Use the backup nameidate restored, re-check mark set LOOKUP_REVAL
* Nd = save;
dget (nd-> dentry);
mntget (nd-> mnt);
nd-> flags | = LOOKUP_REVAL;
result = __link_path_walk (name, nd);
}
dput (save.dentry);
mntput (save.mnt);
return result;
}

The real name of the analytic function __link_path_walk:
/ *
* Name resolution.
* This is the basic name resolution function, turning a pathname into
* The final dentry. We expect 'base' to be positive and a directory.
*
* Returns 0 and nd will have valid dentry and mnt on success.
* Returns error and drops reference to input namei data on failure.
* /
static fastcall int __link_path_walk (const char * name, struct nameidata * nd)
{
struct path next;
struct inode * inode;
int err;
unsigned int lookup_flags = nd-> flags;
/ / Remove the initial extra "/", but also shows the system can allow you to enter more than one "/" instead of error
while (* name =='/')
name + +;
/ / Empty path
if (! * name)
goto return_reval;
/ / Path to the corresponding inode
inode = nd-> dentry-> d_inode;
if (nd-> depth)
lookup_flags = LOOKUP_FOLLOW | (nd-> flags & LOOKUP_CONTINUE);
/ * At this point we know we have a real path component. * /
for (;;) {
/ / Loop, each loop to extract the file path of a directory name, '/' separated
unsigned long hash;
struct qstr this;
unsigned int c;
nd-> flags | = LOOKUP_CONTINUE;
/ / Check the file permissions, including read and write execute permissions, user / group / other permissions, return 0 as the legitimate
err = exec_permission_lite (inode, nd);
if (err ==-EAGAIN)
/ / EAGAIN means that the inode is being operating, check the execute permissions
/ / For the ordinary file test results would be a mistake
err = vfs_permission (nd, MAY_EXEC);
/ / Error break the cycle
if (err)
break;
/ / Fill quickstring structure
this.name = name;
/ / Name of the first character values
c = * (const unsigned char *) name;
/ / Calculate the filename of the hash, do not include '/'
hash = init_name_hash ();
do {
name + +;
hash = partial_name_hash (c, hash);
c = * (const unsigned char *) name;
} While (c & & (c! ='/'));
/ / Directory (if any) name length
this.len = name - (const char *) this.name;
/ / Hash
this.hash = end_name_hash (hash);
/ * Remove trailing slashes? * /
/ / C 0 that is the last name of a specific file
if (! c)
goto last_component;
/ / Skip the middle of the '/'
while (* + + name =='/');
/ / To the name of the tail, indicating the file name last character is '/'
if (! * name)
goto last_with_slashes;
/ *
* "." And ".." are special - ".." especially so because it has
* To be able to know about the current root directory and
* Parent relationships.
* /
/ / If first character is'. "
if (this.name [0] == '.') switch (this.len) {
default:
/ / Is a '' at the beginning of the file or directory name
break;
case 2:
/ / The first two characters are not "." Is an ordinary file or path name
if (this.name [1]! = '.')
break;
/ / With ".." at the beginning, is the parent directory, update the parent directory nameidata nd data, inode is updated to re-cycle
follow_dotdot (nd);
inode = nd-> dentry-> d_inode;
/ * Fallthrough * /
case 1:
/ / With '' at the beginning of the current directory, ignoring, re-cycle
continue;
}
/ *
* See if the low-level filesystem might want
* To use its own hash ..
* /
/ / Underlying implementation has its own FS HASH algorithm
if (nd-> dentry-> d_op & & nd-> dentry-> d_op-> d_hash) {
err = nd-> dentry-> d_op-> d_hash (nd-> dentry, & this);
if (err <0)
break;
}
/ * This does the actual lookups .. * /
/ / According to the file / directory name specific search
err = do_lookup (nd, & this, & next);
if (err)
break;
err =-ENOENT;
/ / Inode update the inode-based file directory level
inode = next.dentry-> d_inode;
/ / Find the inode, turn error handling
if (! inode)
goto out_dput;
err =-ENOTDIR;
if (! inode-> i_op)
goto out_dput;
if (inode-> i_op-> follow_link) {
/ / With symbolic links, in which each link taking into account the exception handling recursive
err = do_follow_link (& next, nd);
if (err)
goto return_err;
err =-ENOENT;
/ / Update the inode to the actual inode
inode = nd-> dentry-> d_inode;
if (! inode)
break;
err =-ENOTDIR;
if (! inode-> i_op)
break;
} Else
/ / Nd the next level to get the path information
path_to_nameidata (& next, nd);
err =-ENOTDIR;
if (! inode-> i_op-> lookup)
break;
/ / Continue to loop to find the next directory file name
continue;
/ * Here ends the main loop * /
/ / End of the file name, processing, and similar to the front
last_with_slashes:
/ / Last character is '/' is a directory
lookup_flags | = LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
last_component:
/ * Clear LOOKUP_CONTINUE iff it was previously unset * /
nd-> flags & = lookup_flags | ~ LOOKUP_CONTINUE;
if (lookup_flags & LOOKUP_PARENT)
goto lookup_parent;
if (this.name [0] == '.') switch (this.len) {
default:
break;
case 2:
/ / Filename is not "..", continue
if (this.name [1]! = '.')
break;
/ / File name is "..", to parent directory
follow_dotdot (nd);
inode = nd-> dentry-> d_inode;
/ * Fallthrough * /
case 1:
/ / Filename is "." Jump back treatment
goto return_reval;
}
/ / Normal file handling
/ / Underlying implementation has its own FS HASH algorithm
if (nd-> dentry-> d_op & & nd-> dentry-> d_op-> d_hash) {
err = nd-> dentry-> d_op-> d_hash (nd-> dentry, & this);
if (err <0)
break;
}
/ / Find the last file name
err = do_lookup (nd, & this, & next);
if (err)
break;
inode = next.dentry-> d_inode;
if ((lookup_flags & LOOKUP_FOLLOW)
& & Inode & & inode-> i_op & & inode-> i_op-> follow_link) {
err = do_follow_link (& next, nd);
if (err)
goto return_err;
inode = nd-> dentry-> d_inode;
} Else
/ / Update nameidata in mnt, dentry value
path_to_nameidata (& next, nd);
err =-ENOENT;
if (! inode)
break;
if (lookup_flags & LOOKUP_DIRECTORY) {
err =-ENOTDIR;
if (! inode-> i_op | |! inode-> i_op-> lookup)
break;
}
goto return_base;
lookup_parent:
/ / Copy the current quickstring structure of this information to nd the last in
/ / Type LAST_NORM
nd-> last = this;
nd-> last_type = LAST_NORM;
if (this.name [0]! = '.')
goto return_base;
if (this.len == 1)
nd-> last_type = LAST_DOT;
else if (this.len == 2 & & this.name [1] == '.')
nd-> last_type = LAST_DOTDOT;
else
goto return_base;
return_reval:
/ / Return
/ *
* We bypassed the ordinary revalidation routines.
* We may need to check the cached dentry for staleness.
* /
if (nd-> dentry & & nd-> dentry-> d_sb & &
(Nd-> dentry-> d_sb-> s_type-> fs_flags & FS_REVAL_DOT)) {
err =-ESTALE;
/ * Note: we do not d_invalidate () * /
if (! nd-> dentry-> d_op-> d_revalidate (nd-> dentry, nd))
break;
}
return_base:
return 0;
out_dput:
dput_path (& next, nd);
break;
}
/ / Here is wrong
path_release (nd);
return_err:
return err;
}

/ *
* It's more convoluted than I'd like it to be, but ... it's still fairly
* Small and for now I'd prefer to have fast path as straight as possible.
* It _is_ time-critical.
* /
static int do_lookup (struct nameidata * nd, struct qstr * name,
struct path * path)
{
struct vfsmount * mnt = nd-> mnt;
/ / From the system's dentry cache hash table to find the parent dentry is nd-> dentry, dentry called name
struct dentry * dentry = __d_lookup (nd-> dentry, name);
/ / Not found dentry, the real hard look from the storage
if (! dentry)
goto need_lookup;
/ / Need to revalidate the first to validate operation when
if (dentry-> d_op & & dentry-> d_op-> d_revalidate)
goto need_revalidate;
done:
/ / Find, fill the path parameter: the mount point directory entry dentry and mnt
path-> mnt = mnt;
path-> dentry = dentry;
__follow_mount (path);
return 0;
need_lookup:
/ / Make a real find, but read_lookup will recall __d_lookup, can not find it call to find the underlying fs achieved
/ / Seems to repeat the
/ / Real_lookup operation is reflected in the bottom of each fs and related marks the difference between treatment
dentry = real_lookup (nd-> dentry, name, nd);
if (IS_ERR (dentry))
goto fail;
goto done;
need_revalidate:
/ / To validate operation
dentry = do_revalidate (dentry, nd);
if (! dentry)
goto need_lookup;
if (IS_ERR (dentry))
goto fail;
goto done;
fail:
return PTR_ERR (dentry);
}

/ *
* This is called when everything else fails, and we actually have
* To go to the low-level filesystem to find out what we should do ..
*
* We get the directory semaphore, and after getting that we also
* Make sure that nobody added the entry to the dcache in the meantime ..
* SMP-safe
* /
static struct dentry * real_lookup (struct dentry * parent, struct qstr * name, struct nameidata * nd)
{
struct dentry * result;
struct inode * dir = parent-> d_inode;
mutex_lock (& ​​dir-> i_mutex);
/ *
* First re-do the cached lookup just in case it was created
* While we waited for the directory semaphore ..
*
* FIXME! This could use version numbering or similar to
* Avoid unnecessary cache lookups.
*
* The "dcache_lock" is purely to protect the RCU list walker
* From concurrent renames at this point (we mustn't get false
* Negatives from the RCU list walk here, unlike the optimistic
* Fast walk).
*
* So doing d_lookup () (with seqlock), instead of lockfree __d_lookup
* /
/ / Find the dentry cache entries
result = d_lookup (parent, name);
if (! result) {
/ / Not found, the new dentry items
struct dentry * dentry = d_alloc (parent, name);
result = ERR_PTR (-ENOMEM);
if (dentry) {
/ / Call the inode lookup operation, which is relevant and specific file system
result = dir-> i_op-> lookup (dir, dentry, nd);
if (result)
/ / Fail, releasing dentry
dput (dentry);
else
/ / Success, to find the dentry returned as the result
result = dentry;
}
mutex_unlock (& ​​dir-> i_mutex);
return result;
}
/ *
* Uhhuh! Nasty case: the cache was re-populated while
* We waited on the semaphore. Need to revalidate.
* /
/ / Dentry items found in the cache, to validate operational
mutex_unlock (& ​​dir-> i_mutex);
if (result-> d_op & & result-> d_op-> d_revalidate) {
result = do_revalidate (result, nd);
if (! result)
result = ERR_PTR (-ENOENT);
}
return result;
}

Summary of what the function call sequence:
path_lookup_open path_lookup_create
| |
VV
__path_lookup_intent_open
|
V
do_path_lookup
|
V
link_path_walk
|
V
__link_path_walk
|
V
do_lookup
|
V
real_lookup

These functions are part of a virtual file system operations operate on all types of file systems are applicable, from the concrete realization of the various FS can see the difference and related marks role.

4.3 open_namei_create

static int open_namei_create (struct nameidata * nd, struct path * path,
int flag, int mode)
{
int error;
/ / Nd the current dentry
struct dentry * dir = nd-> dentry;
if (! IS_POSIXACL (dir-> d_inode))
mode & = ~ current-> fs-> umask;
error = vfs_create (dir-> d_inode, path-> dentry, mode, nd);
mutex_unlock (& ​​dir-> d_inode-> i_mutex);
dput (nd-> dentry);
nd-> dentry = path-> dentry;
if (error)
return error;
/ * Don't check for write permission, don't truncate * /
return may_open (nd, 0, flag & ~ O_TRUNC);
}

4.4 path_to_nameidata

/ / Assign the path to nameidata structure parameters
static inline void path_to_nameidata (struct path * path, struct nameidata * nd)
{
/ / Release the original directory entry
dput (nd-> dentry);
/ / If the mount point is different, out of the original release
if (nd-> mnt! = path-> mnt)
mntput (nd-> mnt);
/ / Assign the new path to nameidata structure parameters
nd-> mnt = path-> mnt;
nd-> dentry = path-> dentry;
}

5 Conclusion

Open the file, the aim is to generate a struct file pointer to the structure, the structure in the name of the relevant file name, dentry pointer, the file system mount point information, struct nameidata saved as an intermediate structure related to the results, information needed to file the final return.

This article comes from CSDN blog, reproduced, please indicate the source: http://blog.csdn.net/air_snake/archive/2008/07/22/2690554.aspx

相关文章
  • sys_open analysis, find the file from the file name information 2011-06-23

    http://blog.csdn.net/air_snake/archive/2008/07/22/2690554.aspx Find the file information from the file name (namei) This document Copyleft owned yfydz all use under the GPL, can be freely copied, reproduced, reprinted, please maintain the integrity o

  • Depth analysis of the linux system. Htaccess file for more syntax to use tutorial 2011-08-27

    Depth analysis of the linux system. Htaccess file for more syntax to use tutorial Implementation conditions grammar rewrite rules RewriteCond: RewriteCond TestString CondPattern Force field: server config, virtual host, directory,. Htaccess Particula

  • 07 version Excle file resolution (large file) 2011-08-04

    Because of existing Excel (07) parsing the apache poi API can only use, but if the file is too large, poi resolve a problem, and take up much memory But also about a very slow speed, our team resolved to write a version of the Excel 07 program, inter

  • Rails file upload Chinese file name garbled 2009-03-05

    The use of rails in the Windows file, if the file name for the Chinese, then the upload is successful, you will find that file name is garbled. For example: How are you. Gif, found the name into From: Nao Video . Rmvb. But the document does not affec

  • [Change] Java compressed file directory or file 2010-04-07

    package com.guo.zip; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; / / Import

  • Liquibase: changelog file import sql file 2010-05-25

    Liquibase SQL statements can be extracted, a separate management. Hard Code in changelog.xml file, not easy to maintain later. Demo 1, in changelog.xml file into SQL file <?xml version="1.0" encoding="UTF-8"?> <databaseChangeL

  • ckeditor the java file upload and file browser 2010-06-25

    fckeditor upgrade to ckeditor for some time, according to understanding ckeditor system more reasonable, so it is intended to replace the original editor fckeditor ckeditor. Originally found in the use of support java fckeditor image upload and brows

  • linux modify the file is the file owner group 2010-07-02

    In Linux, we first need to become familiar with the Group . Owners of other users of this three-meaning , Very important . For example, we need to change the owner of a file :( Modify the file prior to the current user must have administrator permiss

  • Struts / JSP to upload. Preview server side documents (pictures. File. Flash. Multimedia) file components 2010-07-07

    Configuration: The first step: the need to introduce the project jar package Is currently 1.0: filemanager1.0.jar The second step: the need to configure a parameter in the web.xml file The role of parameters: the root directory of resources that site

  • ckeditor the java file upload and file browser 2 2010-07-08

    ckeditor file browsing only need to be a jsp or servlet to receive your request parameters and put pictures in the form of a list can be displayed, When the user when the selected pictures can be submitted to a callback function, callback functions a

  • couldn't copy package file to temp file 2010-07-22

    Simulator does not start up, and reported: couldn't copy package file to temp file. Google this: find me in res / raw four do not put a small music files, take the RAM. Or the smaller music files, or to transfer large RAM (re simulator), or to put it

  • linux to the output end of the file to another file 2010-09-25

    ">" Redirects the file overwrite the original file ;">>" appended to the end. 1, redirect standard output, you can use the ">" symbol, for example: dir my_dir> filelisting.txt Standard dir command will redirect

  • [I / O stream] compress a folder, including all the files folder. Subfolders: extract file method: compressed file called the Chinese handling of garbled 2010-10-07

    / ** * Zip library using compression / decompression folder * Because the basic java zip library is not support Chinese file name. Therefore, the Chinese name of the compressed entry into the garbage, the use of tools to extract the rar will not extr

  • c child write to a file is empty file operation 2010-10-25

    c child write to a file is empty file operation After one hour of investigation, and finally get a conclusion is really silent ................................ .................... I file the action in the child process to write the file using the fp

  • Linux file type and file extension (transfer) 2010-11-04

    Linux file types and file extensions Study: North South North From: LinuxSir.Org Summary: Linux common file types are: regular file, directory, character device file, block device file, symbolic link files, if you want to understand the knowledge of

  • Determine the file type is Java binary file or text file 2010-12-13

    1. According to extension, this is a simple string matching, was renamed because of the situation, basically useless 2. According to the paper flow in the existence of 0x00-0x07 The eight characters, if that is a binary file, you need to read the ent

  • Local upload pictures preview, and the client determine the file size and file format 2010-12-21

    Upload pictures immediately to see a screenshot preview of the map, or directly in the client operating rather than after the first upload to the server the way back URI. After inspection of the relevant data found that some existing methods, but for

  • C + + is simple to read and write text files. Statistical file lines. Read file data into an array 2011-05-09

    fstream provides three classes used to implement c + + file operations. (File creation, reading and writing). ifstream - read from existing file ofstream - write to the file contents fstream - Open the file for read and write File open mode: ios:: in

  • oracle installation error: libXp.so.6: cannot open shared object file: No such file or directory 2011-07-30

    Original link: http://blog.163.com/sz2273_pr/blog/static/4126429620102228333885/ 5.4 Installing Oracle 10g on a prompt the following error: Exception in thread "main" java.lang.UnsatisfiedLinkError: / tmp/OraInstall2009-11-25_02-34-42PM/jre/1.4.

  • Distributed File System (Cluster File System) 2011-06-27

    Source: http://netkiller.github.com/architect/architecture/dfs.html Distributed File System (Cluster File System) I have it distributed file system is divided into three categories, the aggregate file systems, global file system, file system load bal