📄 inode.c
字号:
/* * inode.c * * Copyright (C) 1995, 1996 by Paal-Kr. Engstad and Volker Lendecke * Copyright (C) 1997 by Volker Lendecke * * Please add a note about your changes to smbfs in the ChangeLog file. */#include <linux/module.h>#include <linux/time.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/string.h>#include <linux/stat.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/file.h>#include <linux/dcache.h>#include <linux/smp_lock.h>#include <linux/nls.h>#include <linux/seq_file.h>#include <linux/mount.h>#include <linux/net.h>#include <linux/vfs.h>#include <linux/highuid.h>#include <linux/sched.h>#include <linux/smb_fs.h>#include <linux/smbno.h>#include <linux/smb_mount.h>#include <asm/system.h>#include <asm/uaccess.h>#include "smb_debug.h"#include "getopt.h"#include "proto.h"/* Always pick a default string */#ifdef CONFIG_SMB_NLS_REMOTE#define SMB_NLS_REMOTE CONFIG_SMB_NLS_REMOTE#else#define SMB_NLS_REMOTE ""#endif#define SMB_TTL_DEFAULT 1000static void smb_delete_inode(struct inode *);static void smb_put_super(struct super_block *);static int smb_statfs(struct dentry *, struct kstatfs *);static int smb_show_options(struct seq_file *, struct vfsmount *);static struct kmem_cache *smb_inode_cachep;static struct inode *smb_alloc_inode(struct super_block *sb){ struct smb_inode_info *ei; ei = (struct smb_inode_info *)kmem_cache_alloc(smb_inode_cachep, GFP_KERNEL); if (!ei) return NULL; return &ei->vfs_inode;}static void smb_destroy_inode(struct inode *inode){ kmem_cache_free(smb_inode_cachep, SMB_I(inode));}static void init_once(struct kmem_cache *cachep, void *foo){ struct smb_inode_info *ei = (struct smb_inode_info *) foo; inode_init_once(&ei->vfs_inode);}static int init_inodecache(void){ smb_inode_cachep = kmem_cache_create("smb_inode_cache", sizeof(struct smb_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), init_once); if (smb_inode_cachep == NULL) return -ENOMEM; return 0;}static void destroy_inodecache(void){ kmem_cache_destroy(smb_inode_cachep);}static int smb_remount(struct super_block *sb, int *flags, char *data){ *flags |= MS_NODIRATIME; return 0;}static const struct super_operations smb_sops ={ .alloc_inode = smb_alloc_inode, .destroy_inode = smb_destroy_inode, .drop_inode = generic_delete_inode, .delete_inode = smb_delete_inode, .put_super = smb_put_super, .statfs = smb_statfs, .show_options = smb_show_options, .remount_fs = smb_remount,};/* We are always generating a new inode here */struct inode *smb_iget(struct super_block *sb, struct smb_fattr *fattr){ struct smb_sb_info *server = SMB_SB(sb); struct inode *result; DEBUG1("smb_iget: %p\n", fattr); result = new_inode(sb); if (!result) return result; result->i_ino = fattr->f_ino; SMB_I(result)->open = 0; SMB_I(result)->fileid = 0; SMB_I(result)->access = 0; SMB_I(result)->flags = 0; SMB_I(result)->closed = 0; SMB_I(result)->openers = 0; smb_set_inode_attr(result, fattr); if (S_ISREG(result->i_mode)) { result->i_op = &smb_file_inode_operations; result->i_fop = &smb_file_operations; result->i_data.a_ops = &smb_file_aops; } else if (S_ISDIR(result->i_mode)) { if (server->opt.capabilities & SMB_CAP_UNIX) result->i_op = &smb_dir_inode_operations_unix; else result->i_op = &smb_dir_inode_operations; result->i_fop = &smb_dir_operations; } else if (S_ISLNK(result->i_mode)) { result->i_op = &smb_link_inode_operations; } else { init_special_inode(result, result->i_mode, fattr->f_rdev); } insert_inode_hash(result); return result;}/* * Copy the inode data to a smb_fattr structure. */voidsmb_get_inode_attr(struct inode *inode, struct smb_fattr *fattr){ memset(fattr, 0, sizeof(struct smb_fattr)); fattr->f_mode = inode->i_mode; fattr->f_nlink = inode->i_nlink; fattr->f_ino = inode->i_ino; fattr->f_uid = inode->i_uid; fattr->f_gid = inode->i_gid; fattr->f_size = inode->i_size; fattr->f_mtime = inode->i_mtime; fattr->f_ctime = inode->i_ctime; fattr->f_atime = inode->i_atime; fattr->f_blocks = inode->i_blocks; fattr->attr = SMB_I(inode)->attr; /* * Keep the attributes in sync with the inode permissions. */ if (fattr->f_mode & S_IWUSR) fattr->attr &= ~aRONLY; else fattr->attr |= aRONLY;}/* * Update the inode, possibly causing it to invalidate its pages if mtime/size * is different from last time. */voidsmb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr){ struct smb_inode_info *ei = SMB_I(inode); /* * A size change should have a different mtime, or same mtime * but different size. */ time_t last_time = inode->i_mtime.tv_sec; loff_t last_sz = inode->i_size; inode->i_mode = fattr->f_mode; inode->i_nlink = fattr->f_nlink; inode->i_uid = fattr->f_uid; inode->i_gid = fattr->f_gid; inode->i_ctime = fattr->f_ctime; inode->i_blocks = fattr->f_blocks; inode->i_size = fattr->f_size; inode->i_mtime = fattr->f_mtime; inode->i_atime = fattr->f_atime; ei->attr = fattr->attr; /* * Update the "last time refreshed" field for revalidation. */ ei->oldmtime = jiffies; if (inode->i_mtime.tv_sec != last_time || inode->i_size != last_sz) { VERBOSE("%ld changed, old=%ld, new=%ld, oz=%ld, nz=%ld\n", inode->i_ino, (long) last_time, (long) inode->i_mtime.tv_sec, (long) last_sz, (long) inode->i_size); if (!S_ISDIR(inode->i_mode)) invalidate_remote_inode(inode); }}/* * This is called if the connection has gone bad ... * try to kill off all the current inodes. */voidsmb_invalidate_inodes(struct smb_sb_info *server){ VERBOSE("\n"); shrink_dcache_sb(SB_of(server)); invalidate_inodes(SB_of(server));}/* * This is called to update the inode attributes after * we've made changes to a file or directory. */static intsmb_refresh_inode(struct dentry *dentry){ struct inode *inode = dentry->d_inode; int error; struct smb_fattr fattr; error = smb_proc_getattr(dentry, &fattr); if (!error) { smb_renew_times(dentry); /* * Check whether the type part of the mode changed, * and don't update the attributes if it did. * * And don't dick with the root inode */ if (inode->i_ino == 2) return error; if (S_ISLNK(inode->i_mode)) return error; /* VFS will deal with it */ if ((inode->i_mode & S_IFMT) == (fattr.f_mode & S_IFMT)) { smb_set_inode_attr(inode, &fattr); } else { /* * Big trouble! The inode has become a new object, * so any operations attempted on it are invalid. * * To limit damage, mark the inode as bad so that * subsequent lookup validations will fail. */ PARANOIA("%s/%s changed mode, %07o to %07o\n", DENTRY_PATH(dentry), inode->i_mode, fattr.f_mode); fattr.f_mode = inode->i_mode; /* save mode */ make_bad_inode(inode); inode->i_mode = fattr.f_mode; /* restore mode */ /* * No need to worry about unhashing the dentry: the * lookup validation will see that the inode is bad. * But we do want to invalidate the caches ... */ if (!S_ISDIR(inode->i_mode)) invalidate_remote_inode(inode); else smb_invalid_dir_cache(inode); error = -EIO; } } return error;}/* * This is called when we want to check whether the inode * has changed on the server. If it has changed, we must * invalidate our local caches. */intsmb_revalidate_inode(struct dentry *dentry){ struct smb_sb_info *s = server_from_dentry(dentry); struct inode *inode = dentry->d_inode; int error = 0; DEBUG1("smb_revalidate_inode\n"); lock_kernel(); /* * Check whether we've recently refreshed the inode. */ if (time_before(jiffies, SMB_I(inode)->oldmtime + SMB_MAX_AGE(s))) { VERBOSE("up-to-date, ino=%ld, jiffies=%lu, oldtime=%lu\n", inode->i_ino, jiffies, SMB_I(inode)->oldmtime); goto out; } error = smb_refresh_inode(dentry);out: unlock_kernel(); return error;}/* * This routine is called when i_nlink == 0 and i_count goes to 0. * All blocking cleanup operations need to go here to avoid races. */static voidsmb_delete_inode(struct inode *ino){ DEBUG1("ino=%ld\n", ino->i_ino); truncate_inode_pages(&ino->i_data, 0); lock_kernel(); if (smb_close(ino)) PARANOIA("could not close inode %ld\n", ino->i_ino); unlock_kernel(); clear_inode(ino);}static struct option opts[] = { { "version", 0, 'v' }, { "win95", SMB_MOUNT_WIN95, 1 }, { "oldattr", SMB_MOUNT_OLDATTR, 1 }, { "dirattr", SMB_MOUNT_DIRATTR, 1 }, { "case", SMB_MOUNT_CASE, 1 }, { "uid", 0, 'u' }, { "gid", 0, 'g' }, { "file_mode", 0, 'f' }, { "dir_mode", 0, 'd' }, { "iocharset", 0, 'i' }, { "codepage", 0, 'c' }, { "ttl", 0, 't' }, { NULL, 0, 0}};static intparse_options(struct smb_mount_data_kernel *mnt, char *options){ int c; unsigned long flags; unsigned long value; char *optarg; char *optopt; flags = 0; while ( (c = smb_getopt("smbfs", &options, opts, &optopt, &optarg, &flags, &value)) > 0) { VERBOSE("'%s' -> '%s'\n", optopt, optarg ? optarg : "<none>"); switch (c) { case 1: /* got a "flag" option */ break; case 'v': if (value != SMB_MOUNT_VERSION) { printk ("smbfs: Bad mount version %ld, expected %d\n", value, SMB_MOUNT_VERSION); return 0; } mnt->version = value; break; case 'u': mnt->uid = value; flags |= SMB_MOUNT_UID; break; case 'g': mnt->gid = value; flags |= SMB_MOUNT_GID; break; case 'f': mnt->file_mode = (value & S_IRWXUGO) | S_IFREG; flags |= SMB_MOUNT_FMODE; break; case 'd': mnt->dir_mode = (value & S_IRWXUGO) | S_IFDIR; flags |= SMB_MOUNT_DMODE; break; case 'i': strlcpy(mnt->codepage.local_name, optarg, SMB_NLS_MAXNAMELEN); break; case 'c': strlcpy(mnt->codepage.remote_name, optarg, SMB_NLS_MAXNAMELEN); break; case 't': mnt->ttl = value; break; default: printk ("smbfs: Unrecognized mount option %s\n", optopt); return -1; } } mnt->flags = flags; return c;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -