/* * linux/fs/nfs/inode.c * * Copyright (C) 1992 Rick Sladkey * * nfs inode and superblock handling functions */ #include #include #include #include #include #include #include #include #include #include extern int close_fp(struct file *filp, unsigned int fd); static int nfs_notify_change(struct inode *, struct iattr *); static void nfs_put_inode(struct inode *); static void nfs_put_super(struct super_block *); static void nfs_statfs(struct super_block *, struct statfs *); static struct super_operations nfs_sops = { NULL, /* read inode */ nfs_notify_change, /* notify change */ NULL, /* write inode */ nfs_put_inode, /* put inode */ nfs_put_super, /* put superblock */ NULL, /* write superblock */ nfs_statfs, /* stat filesystem */ NULL }; static void nfs_put_inode(struct inode * inode) { clear_inode(inode); } void nfs_put_super(struct super_block *sb) { /* No locks should be open on this, so 0 should be safe as a fd. */ close_fp(sb->u.nfs_sb.s_server.file, 0); lock_super(sb); sb->s_dev = 0; unlock_super(sb); } /* * The way this works is that the mount process passes a structure * in the data argument which contains an open socket to the NFS * server and the root file handle obtained from the server's mount * daemon. We stash theses away in the private superblock fields. * Later we can add other mount parameters like caching values. */ struct super_block *nfs_read_super(struct super_block *sb, void *raw_data, int silent) { struct nfs_mount_data *data = (struct nfs_mount_data *) raw_data; struct nfs_server *server; unsigned int fd; struct file *filp; dev_t dev = sb->s_dev; if (!data) { printk("nfs_read_super: missing data argument\n"); sb->s_dev = 0; return NULL; } fd = data->fd; if (data->version != NFS_MOUNT_VERSION) { printk("nfs warning: mount version %s than kernel\n", data->version < NFS_MOUNT_VERSION ? "older" : "newer"); } if (fd >= NR_OPEN || !(filp = current->files->fd[fd])) { printk("nfs_read_super: invalid file descriptor\n"); sb->s_dev = 0; return NULL; } if (!S_ISSOCK(filp->f_inode->i_mode)) { printk("nfs_read_super: not a socket\n"); sb->s_dev = 0; return NULL; } filp->f_count++; lock_super(sb); sb->s_blocksize = 1024; /* XXX */ sb->s_blocksize_bits = 10; sb->s_magic = NFS_SUPER_MAGIC; sb->s_dev = dev; sb->s_op = &nfs_sops; server = &sb->u.nfs_sb.s_server; server->file = filp; server->lock = 0; server->wait = NULL; server->flags = data->flags; server->rsize = data->rsize; if (server->rsize <= 0) server->rsize = NFS_DEF_FILE_IO_BUFFER_SIZE; else if (server->rsize >= NFS_MAX_FILE_IO_BUFFER_SIZE) server->rsize = NFS_MAX_FILE_IO_BUFFER_SIZE; server->wsize = data->wsize; if (server->wsize <= 0) server->wsize = NFS_DEF_FILE_IO_BUFFER_SIZE; else if (server->wsize >= NFS_MAX_FILE_IO_BUFFER_SIZE) server->wsize = NFS_MAX_FILE_IO_BUFFER_SIZE; server->timeo = data->timeo*HZ/10; server->retrans = data->retrans; server->acregmin = data->acregmin*HZ; server->acregmax = data->acregmax*HZ; server->acdirmin = data->acdirmin*HZ; server->acdirmax = data->acdirmax*HZ; strcpy(server->hostname, data->hostname); sb->u.nfs_sb.s_root = data->root; unlock_super(sb); if (!(sb->s_mounted = nfs_fhget(sb, &data->root, NULL))) { sb->s_dev = 0; printk("nfs_read_super: get root inode failed\n"); return NULL; } return sb; } void nfs_statfs(struct super_block *sb, struct statfs *buf) { int error; struct nfs_fsinfo res; put_fs_long(NFS_SUPER_MAGIC, &buf->f_type); error = nfs_proc_statfs(&sb->u.nfs_sb.s_server, &sb->u.nfs_sb.s_root, &res); if (error) { printk("nfs_statfs: statfs error = %d\n", -error); res.bsize = res.blocks = res.bfree = res.bavail = 0; } put_fs_long(res.bsize, &buf->f_bsize); put_fs_long(res.blocks, &buf->f_blocks); put_fs_long(res.bfree, &buf->f_bfree); put_fs_long(res.bavail, &buf->f_bavail); put_fs_long(0, &buf->f_files); put_fs_long(0, &buf->f_ffree); /* We should really try to interrogate the remote server to find it's maximum name length here */ put_fs_long(NAME_MAX, &buf->f_namelen); } /* * This is our own version of iget that looks up inodes by file handle * instead of inode number. We use this technique instead of using * the vfs read_inode function because there is no way to pass the * file handle or current attributes into the read_inode function. * We just have to be careful not to subvert iget's special handling * of mount points. */ struct inode *nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { struct nfs_fattr newfattr; int error; struct inode *inode; if (!sb) { printk("nfs_fhget: super block is NULL\n"); return NULL; } if (!fattr) { error = nfs_proc_getattr(&sb->u.nfs_sb.s_server, fhandle, &newfattr); if (error) { printk("nfs_fhget: getattr error = %d\n", -error); return NULL; } fattr = &newfattr; } if (!(inode = iget(sb, fattr->fileid))) { printk("nfs_fhget: iget failed\n"); return NULL; } if (inode->i_dev == sb->s_dev) { if (inode->i_ino != fattr->fileid) { printk("nfs_fhget: unexpected inode from iget\n"); return inode; } *NFS_FH(inode) = *fhandle; nfs_refresh_inode(inode, fattr); } return inode; } int nfs_notify_change(struct inode *inode, struct iattr *attr) { struct nfs_sattr sattr; struct nfs_fattr fattr; int error; if (attr->ia_valid & ATTR_MODE) sattr.mode = attr->ia_mode; else sattr.mode = (unsigned) -1; if (attr->ia_valid & ATTR_UID) sattr.uid = attr->ia_uid; else sattr.uid = (unsigned) -1; if (attr->ia_valid & ATTR_GID) sattr.gid = attr->ia_gid; else sattr.gid = (unsigned) -1; if (attr->ia_valid & ATTR_SIZE) sattr.size = S_ISREG(inode->i_mode) ? attr->ia_size : -1; else sattr.size = (unsigned) -1; if (attr->ia_valid & ATTR_MTIME) { sattr.mtime.seconds = attr->ia_mtime; sattr.mtime.useconds = 0; } else sattr.mtime.seconds = sattr.mtime.useconds = (unsigned) -1; if (attr->ia_valid & ATTR_ATIME) { sattr.atime.seconds = attr->ia_atime; sattr.atime.useconds = 0; } else sattr.atime.seconds = sattr.atime.useconds = (unsigned) -1; error = nfs_proc_setattr(NFS_SERVER(inode), NFS_FH(inode), &sattr, &fattr); if (!error) nfs_refresh_inode(inode, &fattr); inode->i_dirt = 0; return error; }