// SPDX-License-Identifier: GPL-2.0 /* * linux/fs/nfs/unlink.c * * nfs sillydelete handling * */ #include <linux/slab.h> #include <linux/string.h> #include <linux/dcache.h> #include <linux/sunrpc/sched.h> #include <linux/sunrpc/clnt.h> #include <linux/nfs_fs.h> #include <linux/sched.h> #include <linux/wait.h> #include <linux/namei.h> #include <linux/fsnotify.h> #include "internal.h" #include "nfs4_fs.h" #include "iostat.h" #include "delegation.h" #include "nfstrace.h" /** * nfs_free_unlinkdata - release data from a sillydelete operation. * @data: pointer to unlink structure. */ static void nfs_free_unlinkdata(struct nfs_unlinkdata *data) { … } /** * nfs_async_unlink_done - Sillydelete post-processing * @task: rpc_task of the sillydelete * @calldata: pointer to nfs_unlinkdata * * Do the directory attribute update. */ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata) { … } /** * nfs_async_unlink_release - Release the sillydelete data. * @calldata: struct nfs_unlinkdata to release * * We need to call nfs_put_unlinkdata as a 'tk_release' task since the * rpc_task would be freed too. */ static void nfs_async_unlink_release(void *calldata) { … } static void nfs_unlink_prepare(struct rpc_task *task, void *calldata) { … } static const struct rpc_call_ops nfs_unlink_ops = …; static void nfs_do_call_unlink(struct inode *inode, struct nfs_unlinkdata *data) { … } static int nfs_call_unlink(struct dentry *dentry, struct inode *inode, struct nfs_unlinkdata *data) { … } /** * nfs_async_unlink - asynchronous unlinking of a file * @dentry: parent directory of dentry * @name: name of dentry to unlink */ static int nfs_async_unlink(struct dentry *dentry, const struct qstr *name) { … } /** * nfs_complete_unlink - Initialize completion of the sillydelete * @dentry: dentry to delete * @inode: inode * * Since we're most likely to be called by dentry_iput(), we * only use the dentry to find the sillydelete. We then copy the name * into the qstr. */ void nfs_complete_unlink(struct dentry *dentry, struct inode *inode) { … } /* Cancel a queued async unlink. Called when a sillyrename run fails. */ static void nfs_cancel_async_unlink(struct dentry *dentry) { … } /** * nfs_async_rename_done - Sillyrename post-processing * @task: rpc_task of the sillyrename * @calldata: nfs_renamedata for the sillyrename * * Do the directory attribute updates and the d_move */ static void nfs_async_rename_done(struct rpc_task *task, void *calldata) { … } /** * nfs_async_rename_release - Release the sillyrename data. * @calldata: the struct nfs_renamedata to be released */ static void nfs_async_rename_release(void *calldata) { … } static void nfs_rename_prepare(struct rpc_task *task, void *calldata) { … } static const struct rpc_call_ops nfs_rename_ops = …; /** * nfs_async_rename - perform an asynchronous rename operation * @old_dir: directory that currently holds the dentry to be renamed * @new_dir: target directory for the rename * @old_dentry: original dentry to be renamed * @new_dentry: dentry to which the old_dentry should be renamed * @complete: Function to run on successful completion * * It's expected that valid references to the dentries and inodes are held */ struct rpc_task * nfs_async_rename(struct inode *old_dir, struct inode *new_dir, struct dentry *old_dentry, struct dentry *new_dentry, void (*complete)(struct rpc_task *, struct nfs_renamedata *)) { … } /* * Perform tasks needed when a sillyrename is done such as cancelling the * queued async unlink if it failed. */ static void nfs_complete_sillyrename(struct rpc_task *task, struct nfs_renamedata *data) { … } #define SILLYNAME_PREFIX … #define SILLYNAME_PREFIX_LEN … #define SILLYNAME_FILEID_LEN … #define SILLYNAME_COUNTER_LEN … #define SILLYNAME_LEN … /** * nfs_sillyrename - Perform a silly-rename of a dentry * @dir: inode of directory that contains dentry * @dentry: dentry to be sillyrenamed * * NFSv2/3 is stateless and the server doesn't know when the client is * holding a file open. To prevent application problems when a file is * unlinked while it's still open, the client performs a "silly-rename". * That is, it renames the file to a hidden file in the same directory, * and only performs the unlink once the last reference to it is put. * * The final cleanup is done during dentry_iput. * * (Note: NFSv4 is stateful, and has opens, so in theory an NFSv4 server * could take responsibility for keeping open files referenced. The server * would also need to ensure that opened-but-deleted files were kept over * reboots. However, we may not assume a server does so. (RFC 5661 * does provide an OPEN4_RESULT_PRESERVE_UNLINKED flag that a server can * use to advertise that it does this; some day we may take advantage of * it.)) */ int nfs_sillyrename(struct inode *dir, struct dentry *dentry) { … }