📄 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/config.h>#include <linux/module.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/string.h>#include <linux/stat.h>#include <linux/errno.h>#include <linux/locks.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/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 super_block *, struct statfs *);static int smb_show_options(struct seq_file *, struct vfsmount *);static struct super_operations smb_sops ={ put_inode: force_delete, delete_inode: smb_delete_inode, put_super: smb_put_super, statfs: smb_statfs, show_options: smb_show_options,};/* We are always generating a new inode here */struct inode *smb_iget(struct super_block *sb, struct smb_fattr *fattr){ struct inode *result; DEBUG1("smb_iget: %p\n", fattr); result = new_inode(sb); if (!result) return result; result->i_ino = fattr->f_ino; memset(&(result->u.smbfs_i), 0, sizeof(result->u.smbfs_i)); 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)) { result->i_op = &smb_dir_inode_operations; result->i_fop = &smb_dir_operations; } 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_rdev = inode->i_rdev; 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_blksize= inode->i_blksize; fattr->f_blocks = inode->i_blocks; fattr->attr = inode->u.smbfs_i.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){ /* * A size change should have a different mtime, or same mtime * but different size. */ time_t last_time = inode->i_mtime; 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_rdev = fattr->f_rdev; inode->i_ctime = fattr->f_ctime; inode->i_blksize= fattr->f_blksize; inode->i_blocks = fattr->f_blocks; inode->i_size = fattr->f_size; inode->i_mtime = fattr->f_mtime; inode->i_atime = fattr->f_atime; inode->u.smbfs_i.attr = fattr->attr; /* * Update the "last time refreshed" field for revalidation. */ inode->u.smbfs_i.oldmtime = jiffies; if (inode->i_mtime != 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, (long) last_sz, (long) inode->i_size); if (!S_ISDIR(inode->i_mode)) invalidate_inode_pages(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. */ 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_inode_pages(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, inode->u.smbfs_i.oldmtime + SMB_MAX_AGE(s))) { VERBOSE("up-to-date, ino=%ld, jiffies=%lu, oldtime=%lu\n", inode->i_ino, jiffies, inode->u.smbfs_i.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); 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; break; case 'g': mnt->gid = value; break; case 'f': mnt->file_mode = (value & S_IRWXUGO) | S_IFREG; break; case 'd': mnt->dir_mode = (value & S_IRWXUGO) | S_IFDIR; break; case 'i': strncpy(mnt->codepage.local_name, optarg, SMB_NLS_MAXNAMELEN); break; case 'c': strncpy(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;}/* * smb_show_options() is for displaying mount options in /proc/mounts.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -