LTP GCOV extension - code coverage report
Current view: directory - fs/nfs - unlink.c
Test: 2.6.14_rebootonly_gcov.info
Date: 2006-05-22 Instrumented lines: 99
Code covered: 0.0 % Executed lines: 0

       1                 : /*
       2                 :  *  linux/fs/nfs/unlink.c
       3                 :  *
       4                 :  * nfs sillydelete handling
       5                 :  *
       6                 :  * NOTE: we rely on holding the BKL for list manipulation protection.
       7                 :  */
       8                 : 
       9                 : #include <linux/slab.h>
      10                 : #include <linux/string.h>
      11                 : #include <linux/dcache.h>
      12                 : #include <linux/sunrpc/sched.h>
      13                 : #include <linux/sunrpc/clnt.h>
      14                 : #include <linux/nfs_fs.h>
      15                 : 
      16                 : 
      17                 : struct nfs_unlinkdata {
      18                 :         struct nfs_unlinkdata   *next;
      19                 :         struct dentry   *dir, *dentry;
      20                 :         struct qstr     name;
      21                 :         struct rpc_task task;
      22                 :         struct rpc_cred *cred;
      23                 :         unsigned int    count;
      24                 : };
      25                 : 
      26                 : static struct nfs_unlinkdata    *nfs_deletes;
      27                 : static RPC_WAITQ(nfs_delete_queue, "nfs_delete_queue");
      28                 : 
      29                 : /**
      30                 :  * nfs_detach_unlinkdata - Remove asynchronous unlink from global list
      31                 :  * @data: pointer to descriptor
      32                 :  */
      33                 : static inline void
      34                 : nfs_detach_unlinkdata(struct nfs_unlinkdata *data)
      35               0 : {
      36               0 :         struct nfs_unlinkdata   **q;
      37                 : 
      38               0 :         for (q = &nfs_deletes; *q != NULL; q = &((*q)->next)) {
      39               0 :                 if (*q == data) {
      40               0 :                         *q = data->next;
      41               0 :                         break;
      42                 :                 }
      43                 :         }
      44                 : }
      45                 : 
      46                 : /**
      47                 :  * nfs_put_unlinkdata - release data from a sillydelete operation.
      48                 :  * @data: pointer to unlink structure.
      49                 :  */
      50                 : static void
      51                 : nfs_put_unlinkdata(struct nfs_unlinkdata *data)
      52               0 : {
      53               0 :         if (--data->count == 0) {
      54               0 :                 nfs_detach_unlinkdata(data);
      55               0 :                 if (data->name.name != NULL)
      56               0 :                         kfree(data->name.name);
      57               0 :                 kfree(data);
      58                 :         }
      59                 : }
      60                 : 
      61                 : #define NAME_ALLOC_LEN(len)     ((len+16) & ~15)
      62                 : /**
      63                 :  * nfs_copy_dname - copy dentry name to data structure
      64                 :  * @dentry: pointer to dentry
      65                 :  * @data: nfs_unlinkdata
      66                 :  */
      67                 : static inline void
      68                 : nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data)
      69               0 : {
      70               0 :         char            *str;
      71               0 :         int             len = dentry->d_name.len;
      72                 : 
      73               0 :         str = kmalloc(NAME_ALLOC_LEN(len), GFP_KERNEL);
      74               0 :         if (!str)
      75                 :                 return;
      76               0 :         memcpy(str, dentry->d_name.name, len);
      77               0 :         if (!data->name.len) {
      78               0 :                 data->name.len = len;
      79               0 :                 data->name.name = str;
      80                 :         } else
      81               0 :                 kfree(str);
      82                 : }
      83                 : 
      84                 : /**
      85                 :  * nfs_async_unlink_init - Initialize the RPC info
      86                 :  * @task: rpc_task of the sillydelete
      87                 :  *
      88                 :  * We delay initializing RPC info until after the call to dentry_iput()
      89                 :  * in order to minimize races against rename().
      90                 :  */
      91                 : static void
      92                 : nfs_async_unlink_init(struct rpc_task *task)
      93               0 : {
      94               0 :         struct nfs_unlinkdata   *data = (struct nfs_unlinkdata *)task->tk_calldata;
      95               0 :         struct dentry           *dir = data->dir;
      96               0 :         struct rpc_message      msg = {
      97                 :                 .rpc_cred       = data->cred,
      98               0 :         };
      99               0 :         int                     status = -ENOENT;
     100                 : 
     101               0 :         if (!data->name.len)
     102               0 :                 goto out_err;
     103                 : 
     104               0 :         status = NFS_PROTO(dir->d_inode)->unlink_setup(&msg, dir, &data->name);
     105               0 :         if (status < 0)
     106               0 :                 goto out_err;
     107               0 :         nfs_begin_data_update(dir->d_inode);
     108               0 :         rpc_call_setup(task, &msg, 0);
     109               0 :         return;
     110                 :  out_err:
     111               0 :         rpc_exit(task, status);
     112                 : }
     113                 : 
     114                 : /**
     115                 :  * nfs_async_unlink_done - Sillydelete post-processing
     116                 :  * @task: rpc_task of the sillydelete
     117                 :  *
     118                 :  * Do the directory attribute update.
     119                 :  */
     120                 : static void
     121                 : nfs_async_unlink_done(struct rpc_task *task)
     122               0 : {
     123               0 :         struct nfs_unlinkdata   *data = (struct nfs_unlinkdata *)task->tk_calldata;
     124               0 :         struct dentry           *dir = data->dir;
     125               0 :         struct inode            *dir_i;
     126                 : 
     127               0 :         if (!dir)
     128               0 :                 return;
     129               0 :         dir_i = dir->d_inode;
     130               0 :         nfs_end_data_update(dir_i);
     131               0 :         if (NFS_PROTO(dir_i)->unlink_done(dir, task))
     132               0 :                 return;
     133               0 :         put_rpccred(data->cred);
     134               0 :         data->cred = NULL;
     135               0 :         dput(dir);
     136                 : }
     137                 : 
     138                 : /**
     139                 :  * nfs_async_unlink_release - Release the sillydelete data.
     140                 :  * @task: rpc_task of the sillydelete
     141                 :  *
     142                 :  * We need to call nfs_put_unlinkdata as a 'tk_release' task since the
     143                 :  * rpc_task would be freed too.
     144                 :  */
     145                 : static void
     146                 : nfs_async_unlink_release(struct rpc_task *task)
     147               0 : {
     148               0 :         struct nfs_unlinkdata   *data = (struct nfs_unlinkdata *)task->tk_calldata;
     149               0 :         nfs_put_unlinkdata(data);
     150                 : }
     151                 : 
     152                 : /**
     153                 :  * nfs_async_unlink - asynchronous unlinking of a file
     154                 :  * @dentry: dentry to unlink
     155                 :  */
     156                 : int
     157                 : nfs_async_unlink(struct dentry *dentry)
     158               0 : {
     159               0 :         struct dentry   *dir = dentry->d_parent;
     160               0 :         struct nfs_unlinkdata   *data;
     161               0 :         struct rpc_task *task;
     162               0 :         struct rpc_clnt *clnt = NFS_CLIENT(dir->d_inode);
     163               0 :         int             status = -ENOMEM;
     164                 : 
     165               0 :         data = kmalloc(sizeof(*data), GFP_KERNEL);
     166               0 :         if (!data)
     167               0 :                 goto out;
     168               0 :         memset(data, 0, sizeof(*data));
     169                 : 
     170               0 :         data->cred = rpcauth_lookupcred(clnt->cl_auth, 0);
     171               0 :         if (IS_ERR(data->cred)) {
     172               0 :                 status = PTR_ERR(data->cred);
     173               0 :                 goto out_free;
     174                 :         }
     175               0 :         data->dir = dget(dir);
     176               0 :         data->dentry = dentry;
     177                 : 
     178               0 :         data->next = nfs_deletes;
     179               0 :         nfs_deletes = data;
     180               0 :         data->count = 1;
     181                 : 
     182               0 :         task = &data->task;
     183               0 :         rpc_init_task(task, clnt, nfs_async_unlink_done , RPC_TASK_ASYNC);
     184               0 :         task->tk_calldata = data;
     185               0 :         task->tk_action = nfs_async_unlink_init;
     186               0 :         task->tk_release = nfs_async_unlink_release;
     187                 : 
     188               0 :         spin_lock(&dentry->d_lock);
     189               0 :         dentry->d_flags |= DCACHE_NFSFS_RENAMED;
     190               0 :         spin_unlock(&dentry->d_lock);
     191                 : 
     192               0 :         rpc_sleep_on(&nfs_delete_queue, task, NULL, NULL);
     193               0 :         status = 0;
     194                 :  out:
     195               0 :         return status;
     196                 : out_free:
     197               0 :         kfree(data);
     198               0 :         return status;
     199                 : }
     200                 : 
     201                 : /**
     202                 :  * nfs_complete_unlink - Initialize completion of the sillydelete
     203                 :  * @dentry: dentry to delete
     204                 :  *
     205                 :  * Since we're most likely to be called by dentry_iput(), we
     206                 :  * only use the dentry to find the sillydelete. We then copy the name
     207                 :  * into the qstr.
     208                 :  */
     209                 : void
     210                 : nfs_complete_unlink(struct dentry *dentry)
     211               0 : {
     212               0 :         struct nfs_unlinkdata   *data;
     213                 : 
     214               0 :         for(data = nfs_deletes; data != NULL; data = data->next) {
     215               0 :                 if (dentry == data->dentry)
     216               0 :                         break;
     217                 :         }
     218               0 :         if (!data)
     219               0 :                 return;
     220               0 :         data->count++;
     221               0 :         nfs_copy_dname(dentry, data);
     222               0 :         spin_lock(&dentry->d_lock);
     223               0 :         dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
     224               0 :         spin_unlock(&dentry->d_lock);
     225               0 :         rpc_wake_up_task(&data->task);
     226               0 :         nfs_put_unlinkdata(data);
     227                 : }

Generated by: LTP GCOV extension version 1.4